Не получается создать словарь : хеш-пароль из 5-ти слов алфавита 'abcdefghijklmnopqrstuvwxyz'

Задание на https://www.codewars.com/kata/59146f7b4670ba520900000a/train/python

Даны хеши SHA-1 и по ним определить пароли - будут максимум 5 символов слова используйте только строчные буквы (a-z), никаких других символов.

В моём решении слова с 2, 3, 4 символами(получаю хэш и делаю словарь всё проходит) Слова с 5 символами по времени(тайм-аут) - я не могу их занести в словарь по моему решению - занимает много времени - есть подсказка

Notes:

  • pre-generating the full hash table is not advised, due to the time-limit on the CW platform
  • there will be only a few tests for 5-letter words (hint: start from the beginning of the alphabet)

"Начнётся с начала алфавита" - как это понять?
Ниже указано как я получил 5-ти значные слова с сервера, а в них присутствую символы с разных мест алфавита

def password_cracker(hash):
#    answer = generate_hash_password()
#    return answer.get(hash)
    return 'code'

Testing: "b1e8b6a2dfba27239052037268fe293f3dfd4d28"
Expecting: "akvjh"
'code' should equal 'akvjh'
Log
Testing: "0576a1b0aacea877c5b6a3dd0c9541724cef777d"
Expecting: "bsynd"
'code' should equal 'bsynd'
Log
Testing: "ff6719c2bd6bfc89538a397aab44b39a34a567a1"
Expecting: "edssz"
'code' should equal 'edssz'

Вот моё решение

  • хеш - 'e6fb06210fafc02fd7479ddbed2d042cc3a5155e' ответ - 'code'
  • хеш - 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3' ответ - 'test'
import hashlib
from itertools import product

def create_sha1_hash(input_string):   
    sha1_hash = hashlib.sha1()  
    sha1_hash.update(input_string.encode('utf-8'))  
    return sha1_hash.hexdigest()

def generate_hash_password():
    ## Генерируем пароль и хэш для заданной длины слова и помещаем в словарь
    HASH = {}
    lengths = [2, 3, 4] # длина каждого слова в списке кроме 5
    for length in lengths:
        password = list(map(''.join, product('abcdefghijklmnopqrstuvwxyz', repeat=length)))
        list_hash = list(map(create_sha1_hash, password))
        HASH.update(dict(zip(list_hash, password)))
    return HASH
    
def password_cracker(hash):
    answer = generate_hash_password()
    return answer.get(hash)

print(password_cracker(hash))

Подскажите(оптимизацию) как сделать общий словарь хэш-пароль с словами из 5-ти символов


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Вас предостерегают от создания полных словарей. Вам обещают что пароли будут недалеко от начала списка всех паролей, если вы станете перебирать их алфавитном порядке. Так что можно упростить ваш код до такого:

import hashlib
from itertools import product


def find_password(h):
    for r in range(2, 6):
        for p in map(bytes, product(b'abcdefghijklmnopqrstuvwxyz', repeat=r)):
            if hashlib.sha1(p).digest() == h:
                return p
    

print(find_password(bytes.fromhex(input())))
$ time -p echo ff6719c2bd6bfc89538a397aab44b39a34a567a1 | python temp.py
b'edssz'
real 0.84
user 0.83
sys 0.00

$ time -p echo a2b7caddbc353bd7d7ace2067b8c4e34db2097a3 | python temp.py
b'zzzzz'
real 4.32
user 4.32
sys 0.00

Удивительное дело, рекурсивный поиск пароля немного быстрее комбинаторного перебора:

import hashlib


def find_password(digest, k):
    alphabet = [bytes([c]) for c in b'abcdefghijklmnopqrstuvwxyz']
    password = []

    def search(sha1, k):
        if sha1.digest() == digest:
            print(b''.join(password))
            return True
        if k > 0:
            for c in alphabet:
                s = sha1.copy()
                s.update(c)
                password.append(c)
                if search(s, k - 1):
                    return True
                password.pop()
        return False

    search(hashlib.sha1(), k)


find_password(bytes.fromhex(input()), 5)
$ time -p echo ff6719c2bd6bfc89538a397aab44b39a34a567a1 | python temp.py
b'edssz'
real 0.67
user 0.67
sys 0.00

$ time -p echo a2b7caddbc353bd7d7ace2067b8c4e34db2097a3 | python temp.py
b'zzzzz'
real 4.21
user 4.21
sys 0.00
→ Ссылка