patternpythonMinor
Zipfile password recovery program
Viewed 0 times
recoveryprogramzipfilepassword
Problem
I would like to get a few tips on how to improve this program, which is supposed to help recovering lost passwords from .zip files.
So now the program seems to work fine but is a bit slow in my opinion. I'm wondering if there's a faster way than
import zipfile
import string
import itertools
import random
import time
"""
Zipfile password cracker using a dictionary attack and, if not successful,
switches to bruteforce
"""
def crack(zipfilename,dictionary):
t0=time.time()
password = None
zip_file = zipfile.ZipFile(zipfilename)
alphabet = string.ascii_letters + string.digits + string.punctuation
#Tries at first a dictionary attack
with open(dictionary, 'r') as f:
for line in f.readlines():
password_string = line.strip('\n')
try:
password = bytes(password_string, 'utf-8')
zip_file.extractall(pwd=password)
t1=time.time()
total = t1 - t0
print('Password found : %s' %password_string)
print('Time spent : %f seconds' %total)
return
except:
pass
#If the password hasn't been found yet, the function switches to bruteforce
nbcharmax = 10 #Maximum length to test
for i in range(1,nbcharmax):
print('Testing length = %i' % i)
for j in itertools.product(alphabet, repeat=i):
try:
password_string=''.join(j)
password = bytes(password_string, 'utf-8')
zip_file.extractall(pwd=password)
t1=time.time()
total = t1 - t0
print('Password found : %s' %password_string)
print('Time spent : %f seconds' %total)
return
except:
pass
if __name__ == "__main__":
crack('test.zip','dictionary.txt')So now the program seems to work fine but is a bit slow in my opinion. I'm wondering if there's a faster way than
zip_file.extractall() to open archive files?Solution
- Follow the styleguide (PEP8)
- don't import modules which you're not using (
random)
- more, imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants.
- I always like to put my imports in alphabetical order, so that it gets easier to find them.
- you should have two newlines before defining your methods
- you should also have a space after every
,
- you should put a space before and after operators (
x = 'something'); this is not required when defining arguments.
- instead of commenting code in the middle of the method, try to split the logic of your program in separate functions.
- you should be using the new
.format()style
- Working on the code:
- you should really let the user choose where the files actually are
- don't use bare
excepts.
- you can directly use
.encode()if you want to convert a string to bytes. That's actually the pythonic way of doing it as per this SO discussion
- when reading a file, you can omit the
rmode, as that's the default one
- Efficiency
The problem does not come from the
zip module but rather from the cartesian product you're doing. As @jonsharpe mentioned in his comments, your program has to go through a lot of passwords.The final code would look like this:
"""
Zipfile password cracker using a dictionary attack and, if not successful,
switches to bruteforce
"""
import itertools
import string
import time
import zipfile
ARCHIVE_PATH = 'test.zip'
DICTIONARY_PATH = 'dictionary.txt'
def dictionary_attack():
"""Tries at first a dictionary attack"""
t0 = time.time()
with open(DICTIONARY_PATH) as f:
for password in f:
password = password.rstrip().encode()
try:
zipfile.ZipFile(ARCHIVE_PATH).extractall(pwd=password)
t1 = time.time()
print('Password found: {}\nTime spent: {} seconds'.format(password.decode(), t1 - t0))
return True
except RuntimeError:
pass
return False
def bruteforce_attack(nbcharmax):
"""If the password hasn't been found yet, the function switches to bruteforce"""
alphabet = string.ascii_letters + string.digits + string.punctuation
t0 = time.time()
for i in range(1, nbcharmax):
for j in itertools.product(alphabet, repeat=i):
password = ''.join(j).encode()
try:
zipfile.ZipFile(ARCHIVE_PATH).extractall(pwd=password)
t1 = time.time()
print('Password found: {}\nTime spent: {} seconds'.format(password.decode(), t1 - t0))
return True
except RuntimeError:
pass
return False
if __name__ == "__main__":
if not dictionary_attack():
bruteforce_attack(4)Code Snippets
"""
Zipfile password cracker using a dictionary attack and, if not successful,
switches to bruteforce
"""
import itertools
import string
import time
import zipfile
ARCHIVE_PATH = 'test.zip'
DICTIONARY_PATH = 'dictionary.txt'
def dictionary_attack():
"""Tries at first a dictionary attack"""
t0 = time.time()
with open(DICTIONARY_PATH) as f:
for password in f:
password = password.rstrip().encode()
try:
zipfile.ZipFile(ARCHIVE_PATH).extractall(pwd=password)
t1 = time.time()
print('Password found: {}\nTime spent: {} seconds'.format(password.decode(), t1 - t0))
return True
except RuntimeError:
pass
return False
def bruteforce_attack(nbcharmax):
"""If the password hasn't been found yet, the function switches to bruteforce"""
alphabet = string.ascii_letters + string.digits + string.punctuation
t0 = time.time()
for i in range(1, nbcharmax):
for j in itertools.product(alphabet, repeat=i):
password = ''.join(j).encode()
try:
zipfile.ZipFile(ARCHIVE_PATH).extractall(pwd=password)
t1 = time.time()
print('Password found: {}\nTime spent: {} seconds'.format(password.decode(), t1 - t0))
return True
except RuntimeError:
pass
return False
if __name__ == "__main__":
if not dictionary_attack():
bruteforce_attack(4)Context
StackExchange Code Review Q#160827, answer score: 7
Revisions (0)
No revisions yet.