Cracker password SHA256 - v2 con concorrenza
Ho aggiornato il mio codice precedente con i suggerimenti. Ho anche implementato la concorrenza per accelerare i risultati.
Sarei interessato a commenti su un uso più efficiente di concorrenza / elaborazione parallela / hyper-threading
Grazie
import concurrent.futures
import hashlib
import time
def make_next_guess(guess):
carry = 0
next_guess = guess
for i, char in enumerate(next_guess):
if ord(char) >= ord("z"):
carry = 1
next_guess[i] = "!"
elif ord(char) < ord("z"):
next_guess[i] = chr(ord(char) + 1)
carry = 0
if carry == 0: break
if carry:
next_guess.append("!")
return next_guess
def hash_password(pwrd):
# Generates hash of original password
try:
pwrd = pwrd.encode("UTF-8")
password = hashlib.sha256()
password.update(pwrd)
return password.hexdigest()
except:
pass
def find_password(secure_password, guess, integer):
list_cracked = []
# Brute force to find original password
for _ in range(90 ** integer): # password maximum length 14 and there are 58 characters that can be used
return_password = "".join(guess)
if hash_password(return_password) in secure_password:
# print(f"Another password has been cracked: '{return_password}'")
list_cracked.append(return_password)
guess = make_next_guess(guess)
return f"Finished cracking all passwords of length {integer}", list_cracked, integer
def rainbow_table_check(secure_password):
global hash
list_cracked = []
for password in open("Rainbow.txt", "r", encoding="utf8"):
try:
password = password.strip()
hash = hash_password(password)
except:
pass
if hash in secure_password:
# print(f"Another password has been cracked: {password}")
list_cracked.append(password)
return "Rainbow attack complete - passwords: ", list_cracked, "Rainbow"
def dic_attack(secure_password):
list_cracked = []
for password in open("Dic.txt", "r", encoding="utf8"):
password = password.strip()
lst = [password.lower(), password.upper(), password.title()]
for password in lst:
hash = hash_password(password)
if hash in secure_password:
# print(f"Another password has been cracked: {password}")
list_cracked.append(password)
return "Dictionary attack complete - passwords: ", list_cracked, "Dictionary"
if __name__ == "__main__":
all_passwords = []
start = time.time()
secure_password = set()
print("Attempting to crack passwords....")
password_list = ["ABd", "Abc", "lpo", "J*&", "Njl", "!!!!", "Aqz", "Apple", "Cake", "Biden", "password1"]
for password in password_list:
secure_password.add(hash_password(password))
with concurrent.futures.ProcessPoolExecutor() as executor:
results = [executor.submit(dic_attack, secure_password),
executor.submit(rainbow_table_check, secure_password),
executor.submit(find_password, secure_password, ['!'], 1),
executor.submit(find_password, secure_password, ['!', '!'], 2),
executor.submit(find_password, secure_password, ['!', '!', '!'], 3),
executor.submit(find_password, secure_password, ['!', '!', '!', '!'], 4),
executor.submit(find_password, secure_password, ['!', '!', '!', '!', '!'], 5)]
for f in concurrent.futures.as_completed(results):
message, cracked, method = f.result()
time_run = f"{round((time.time() - start) // 60)} min {round((time.time() - start) % 60)} sec"
print(f"{message} : {cracked} - {time_run}")
all_passwords += cracked
print(f"Complete list of cracked passwords: {set(tuple(all_passwords))}")
print(f"This operation took: {round((time.time() - start) // 60)} min {round((time.time() - start) % 60)} sec")
Risposte
Due osservazioni:
I metodi hashlibprevedono di ricevere byte. In make_next_guess(), usa a bytearrayinvece di una stringa. Che evita le chiamate a ''.join(), ord(), ''.encode('UTF-8'), ecc Meglio ancora, rendono la funzione di un generatore che produce le congetture.
L'uso della elseclausola sul for i, byte in enumerate(guess):ciclo semplifica un po 'la logica. Quando il ciclo è finito, la elseclausola viene eseguita. Tuttavia, a breaksalta la elseclausola. Qui, se il ciclo non trova byte da aumentare, la clausola else aggiunge un altro byte alla lunghezza dell'ipotesi.
Qualcosa di simile a:
def generate_guesses(start):
ORD_Z = ord('z')
ORD_BANG = ord("!")
guess = start[:]
while True:
yield guess
for i, byte in enumerate(guess):
if byte < ORD_Z:
guess[i] += 1
break
else:
guess[i] = ORD_BANG
else:
guess.append(ORD_BANG)
Chiamato come:
for guess in generate_guesses(bytearray(b'xzzzz')):
... do something with the guess ...
Eventualmente, aggiungi un argomento stopo countche indica quando il generatore deve fermarsi o quante ipotesi deve generare. Basta cambiare la while True:linea per controllare le condizioni di arresto.
La seconda osservazione è che l'ultimo lavoro presentato al Pool è 90 volte più lavoro del lavoro precedente. In effetti, è più lavoro rispetto ai precedenti 4 lavori messi insieme (forse tutti gli altri lavori). Di conseguenza, si finisce con gli altri lavori che terminano prima e un lavoro in esecuzione su un core del processore per molto tempo. Prova a suddividere i lavori in blocchi di dimensioni più uguali per mantenere occupati tutti i core del processore. Ad esempio, i lavori potrebbero funzionare su blocchi di dimensioni uguali dello spazio di ricerca delle password:
'!' to 'zzz'
'!!!!' to 'zzz!'
'!!!"' to 'zzz"'
'!!!#' to 'zzz#' these are all chunks of 729k (90*90*90) guesses
...
'!!!z' to 'zzzz'