如何纠正“TypeError: Unicode-objects must be encoded before hashing”错误?

458

我遇到了这个错误:

Traceback (most recent call last):
  File "python_md5_cracker.py", line 27, in <module>
  m.update(line)
TypeError: Unicode-objects must be encoded before hashing

当我尝试在Python 3.2.2中执行以下代码时:

import hashlib, sys
m = hashlib.md5()
hash = ""
hash_file = input("What is the file name in which the hash resides?  ")
wordlist = input("What is your wordlist?  (Enter the file name)  ")
try:
  hashdocument = open(hash_file, "r")
except IOError:
  print("Invalid file.")
  raw_input()
  sys.exit()
else:
  hash = hashdocument.readline()
  hash = hash.replace("\n", "")

try:
  wordlistfile = open(wordlist, "r")
except IOError:
  print("Invalid file.")
  raw_input()
  sys.exit()
else:
  pass
for line in wordlistfile:
  # Flush the buffer (this caused a massive problem when placed 
  # at the beginning of the script, because the buffer kept getting
  # overwritten, thus comparing incorrect hashes)
  m = hashlib.md5()
  line = line.replace("\n", "")
  m.update(line)
  word_hash = m.hexdigest()
  if word_hash == hash:
    print("Collision! The word corresponding to the given hash is", line)
    input()
    sys.exit()

print("The hash given does not correspond to any supplied word in the wordlist.")
input()
sys.exit()

3
我发现使用'rb'方式打开文件对我的情况有帮助。 - dlamblin
10个回答

438

它可能正在查找来自 wordlistfile 的字符编码。

wordlistfile = open(wordlist,"r",encoding='utf-8')

或者,如果您是基于逐行进行工作:

line.encode('utf-8')

编辑

根据下面的评论和这个答案

我上面的回答假设所需的输出是从wordlist文件中得到的str。如果您习惯于使用bytes,那么最好使用open(wordlist, "rb")。但是请记住,如果要将其与hexdigest的输出进行比较,则hashfile不应该使用rbhashlib.md5(value).hashdigest()输出一个str,不能直接与一个bytes对象进行比较:'abc' != b'abc'。(这个主题还有很多内容,但我现在没有时间)。

还应该注意这一行:

line.replace("\n", "")

应该是这样的

line.strip()

如果你决定将数据转换为bytes类型,那么以下代码可以同时兼容bytesstr类型的数据:

line.replace(b"\n", b"")

4
使用open(wordlist,"r",encoding='utf-8')的原因是为了指定编码方式。如果不指定编码方式,它将使用平台相关的编码方式进行解码,而这可能会导致问题。通过指定编码方式,可以确保正确地读取和处理文本文件中的内容。 - Tanky Woo
1
这段话的前半部分完全错误,令人震惊的是它竟然被赞了这么高。明确指定encoding只是改变了从磁盘上解码字节以获取一个存储任意Unicode字符的文本类型str的方式,但即使没有指定也会解码为str,问题在于一开始就使用了strline.encode('utf-8') 撤销了那个错误的解码,但最好的方法是一开始就用'rb'模式打开文件(不需要编码),这样line就是一个bytes对象(需要进行一些微小的更改以匹配,例如.replace("\n", ''))。 - ShadowRanger
@ShadowRanger 如果 OP 想要 一个 str 类型呢?我在回答中添加了一点内容,但我的原始回复是简短、简洁和立即可用的。当我写上面的回复时,它也恰好是我正在进行的一个项目的正确答案,所以 ¯\_(ツ)_/¯ - cwallenpoole

183

你必须定义编码格式,如utf-8, 试试这种简单的方法,

此示例使用SHA256算法生成随机数字:

>>> import hashlib
>>> hashlib.sha256(str(random.getrandbits(256)).encode('utf-8')).hexdigest()
'cd183a211ed2434eac4f31b317c573c50e6c24e3a28b82ddcb0bf8bedf387a9f'

45
import hashlib
string_to_hash = '123'
hash_object = hashlib.sha256(str(string_to_hash).encode('utf-8'))
print('Hash', hash_object.hexdigest())

hashlib.sha256方法始终期望unicode。在Python-2中,str既是str又是unicode,因此仅传递string_to_hash字符串就可以正常工作。然而,在Python-3中,string(这里是string_to_hash)和unicode是两种不同的类型。因此,当我们仅传递类型为text的string_to_hash时,它会抛出错误,指出需要一个unicode值。 - kundan

22

错误信息已经告诉您需要做什么。MD5处理的是字节,因此您需要将Unicode字符串编码为bytes,例如使用line.encode('utf-8')


19

存储密码(PY3):

import hashlib, os
password_salt = os.urandom(32).hex()
password = '12345'

hash = hashlib.sha512()
hash.update(('%s%s' % (password_salt, password)).encode('utf-8'))
password_hash = hash.hexdigest()

2
这行代码使密码无法使用。 password_salt = os.urandom(32).hex() 它应该是一个固定的已知值,但对于服务器来说可以是秘密的。 请根据您的代码进行更正或适应。 - Yash
2
我同意@Yash的观点。你可以使用单一的盐值来加密每个哈希(不是最好的方法),或者为每个哈希生成一个随机盐值,然后将其与哈希值一起存储以便稍后进行比较。 - Carson

16

编码这行代码对我起到了修复的作用。

m.update(line.encode('utf-8'))

14

请先查看答案。

现在,错误信息很明确:你只能使用字节而不是 Python 字符串(在 Python<3 中称为 unicode),所以你必须用你喜欢的编码方式对字符串进行编码:utf-32utf-16utf-8 甚至是受限的 8 位编码(有些人可能称之为代码页)。

Python 3 在读取文件时会自动将字节解码为 Unicode。我建议你这样做:

m.update(line.encode(wordlistfile.encoding))

这样推送到MD5算法的编码数据将与底层文件完全相同。


为什么要解码再重新编码,当你可以直接以二进制模式处理文件,并一路处理“字节”呢? - ShadowRanger
@ShadowRanger 对于这种简单的情况(只需读取行并剥离每行末尾的b'\n'),您的建议是正确和足够的。 - tzot

12

您可以以二进制模式打开文件:

import hashlib

with open(hash_file) as file:
    control_hash = file.readline().rstrip("\n")

wordlistfile = open(wordlist, "rb")
# ...
for line in wordlistfile:
    if hashlib.md5(line.rstrip(b'\n\r')).hexdigest() == control_hash:
       # collision

4
我很惊讶要滚动这么长时间才能找到第一个明智的答案。除非有理由认为“wordlist”文件是使用错误编码(因此必须从错误编码解码,然后使用正确编码进行哈希处理),否则这绝对是最佳解决方案,避免了无意义的解码和重新编码,而只需处理“bytes”(OP代码中的错误源)。 - ShadowRanger
Python3.*,我能想到的唯一可行的选项是以二进制模式打开文件,然后进行哈希操作。而Python2则可以直接打开并对文本进行哈希处理。 - Nishad C M

6
如果它是单行字符串,请使用 b 或 B 包装它。例如:
variable = b"This is a variable"

或者
variable2 = B"This is also a variable"

-4

这个程序是上述MD5破解器的无bug和增强版本,它读取包含哈希密码列表的文件,并将其与英语词典单词列表中的哈希单词进行比较。希望它有所帮助。

我从以下链接下载了英语词典 https://github.com/dwyl/english-words

# md5cracker.py
# English Dictionary https://github.com/dwyl/english-words 

import hashlib, sys

hash_file = 'exercise\hashed.txt'
wordlist = 'data_sets\english_dictionary\words.txt'

try:
    hashdocument = open(hash_file,'r')
except IOError:
    print('Invalid file.')
    sys.exit()
else:
    count = 0
    for hash in hashdocument:
        hash = hash.rstrip('\n')
        print(hash)
        i = 0
        with open(wordlist,'r') as wordlistfile:
            for word in wordlistfile:
                m = hashlib.md5()
                word = word.rstrip('\n')            
                m.update(word.encode('utf-8'))
                word_hash = m.hexdigest()
                if word_hash==hash:
                    print('The word, hash combination is ' + word + ',' + hash)
                    count += 1
                    break
                i += 1
        print('Itiration is ' + str(i))
    if count == 0:
        print('The hash given does not correspond to any supplied word in the wordlist.')
    else:
        print('Total passwords identified is: ' + str(count))
sys.exit()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接