在自身内部嵌套一个函数(我很绝望)

Nesting a function inside itself (i'm desperate)

精神疲惫

仅针对上下文的解释,实际上不需要哈希方面的帮助:

我正在尝试制作一个 python 脚本,该脚本可以暴力破解哈希字符串或密码(仅供学习,我确定这里有成千上万的 tenter 代码)。 目标是制作一个函数,可以尝试不同字母的所有可能组合,从一个字符 (a, b... y, z) 开始,然后开始尝试另一个字符 (aa, ab...zy, zz然后 aaa, aab... zzy, zzz) 不确定直到找到匹配项。

首先,它会要求您提供一个字符串(例如 aaaa),然后对字符串进行哈希处理,然后尝试使用函数对该哈希进行暴力破解,最后函数 return 再次对字符串进行哈希处理。找到匹配项。

PASSWORD_INPUT = input("Password string input: ")
PASSWORD_HASH = encrypt_password(PASSWORD_INPUT)  # This returns the clean hash
found_password = old_decrypt()  # This is the function below
print(found_password)

我成功完成了这段丑陋的代码:

built_password = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']

def old_decrypt():
    global built_password

    # First letter
    for a in range(len(characters)):  # Characters is a list with the abecedary
        built_password[0] = characters[a]
        if test_password(pretty(built_password)):  # This returns True if it matches
            return pretty(built_password)

        # Second letter
        for b in range(len(characters)):
            built_password[1] = characters[b]
            if test_password(pretty(built_password)):
                return pretty(built_password)

            # Third letter
            for c in range(len(characters)):
                built_password[2] = characters[c]
                if test_password(pretty(built_password)):
                    return pretty(built_password)

                # Fourth letter
                for d in range(len(characters)):
                    built_password[3] = characters[d]
                    if test_password(pretty(built_password)):
                        return pretty(built_password)

这个问题是它只适用于 4 个字母的字符串。

如您所见,每个字母几乎都是完全相同的循环,所以我想“嘿,我可以把它做成一个单一的功能”......在整整 3 天痴迷于尝试我想到的一切之后,我随之而来:

# THIS WORKS
def decrypt(letters_amount_int):
    global built_password

    for function_num in range(letters_amount_int):
        for letter in range(len(characters)):

            built_password[function_num] = characters[letter]
            if letters_amount_int >= 1:
                decrypt(letters_amount_int - 1)

            if test_password(pretty(built_password)):
                return pretty(built_password)

# START
n = 1
while True:
    returned = decrypt(n)

# If it returns a string it gets printed, else trying to print None raises TypeError
    try:
        print("Found hash for: " + returned)
        break
    except TypeError:
        n += 1

函数得到一个“1”,尝试使用 1 个字母,如果它没有 return 任何东西,它得到一个“2”,然后尝试使用 2。 它有效,但出于某种原因,它会产生大量不必要的循环,这些循环会花费越来越多的时间,我一直在砸脑袋,得出的结论是我不理解 python 的某些东西内部运作。

有人可以解释一下吗?谢谢

如果需要,这些是其他功能:

def encrypt_password(password_str):
    return hashlib.sha256(password_str.encode()).hexdigest()

def test_password(password_to_test_str):
    global PASSWORD_HASH
    if PASSWORD_HASH == encrypt_password(password_to_test_str):
        return True

characters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
              'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
              'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
              'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
              'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
              'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
              'Y', 'Z']

也许你可以尝试这样的事情。灵感来自 Multiple permutations, including duplicates

Itertools 有一个笛卡尔积生成器,与排列有关。

import itertools

def decrypt(characters, num_chars):
    for test_list in itertools.product(characters, repeat=num_chars):
        test_str = ''.join(test_list)
        if test_password(test_str):
            return test_str
        
    return None


for i in range(min_chars, max_chars+1):
    result = decrypt(characters, i)
    if result:
        print(f'Match found: {result}')

如果您 运行 此代码 characters, min_chars, max_chars = (characters, 1, 3) 并在每一步打印 test_str ,您将得到:

0
1
2
00
01
02
10
11
12
20
21
22

或者如果找到匹配项将提前停止。如果您想了解更多信息,我建议您查看笛卡尔积函数的递归纯 python 实现。但是,我怀疑笛卡尔积生成器会比递归解决方案更快。

请注意,itertools.product() 是一个生成器,因此它会按需生成每个值,并且以这种方式编写它可以让您比长字符串更快地找到较短字符串的匹配项。但是这种暴力算法所花费的时间确实应该随着真实密码的长度呈指数增长。

希望这对您有所帮助。

这种情况下的递归给出了一个非常优雅的解决方案:

def add_char(s, limit):
    if len(s) == limit:
        yield s
    else:
        for c in characters:
            yield from add_char(s + c, limit)


def generate_all_passwords_up_to_length(maxlen):
    for i in range(1, maxlen + 1):
        yield from add_char("", i)


for password in generate_all_passwords_up_to_length(5):
    test_password(password)