这是我的第一个测试代码:
import hashlib
md5Hash = hashlib.md5()
md5Hash.update('Coconuts')
print md5Hash.hexdigest()
md5Hash.update('Apples')
print md5Hash.hexdigest()
md5Hash.update('Oranges')
print md5Hash.hexdigest()
这是我的第二大块代码:
import hashlib
md5Hash = hashlib.md5()
md5Hash.update('Coconuts')
print md5Hash.hexdigest()
md5Hash.update('Bananas')
print md5Hash.hexdigest()
md5Hash.update('Oranges')
print md5Hash.hexdigest()
但第一个代码的输出是:
0e8f7761bb8cd94c83e15ea7e720852a
217f2e2059306ab14286d8808f687abb
4ce7cfed2e8cb204baeba9c471d48f07
第二个代码是:
0e8f7761bb8cd94c83e15ea7e720852a
a82bf69bf25207f2846c015654ae68d1
47dba619e1f3eaa8e8a01ab93c79781e
我将第二个字符串从'Apples'替换为'Bananas',第三个字符串仍然保持不变。但是我仍然得到第三个字符串的不同结果。 Hashing应该每次都有相同的结果。 我错过了什么吗?
答案 0 :(得分:4)
因为您正在使用update
方法,所以md5Hash
对象将被重用于3个字符串。所以它基本上是连接在一起的3个字符串的哈希值。因此,更改第二个字符串也会改变第三个字符的结果。
您需要为每个字符串声明一个单独的md5对象。使用循环(符合python 3的代码需要字节前缀BTW,并且也适用于python 2):
import hashlib
for s in (b'Coconuts',b'Bananas',b'Oranges'):
md5Hash = hashlib.md5(s) # no need for update, pass data at construction
print(md5Hash.hexdigest())
结果:
0e8f7761bb8cd94c83e15ea7e720852a
1ee31b77d0697c36914b99d1428f7f32
62f2b77089fea4c595e895901b63c10b
请注意,这些值现在不同了,但至少它是每个字符串的MD5,独立计算。
答案 1 :(得分:3)
hashlib.md5.update()
将数据添加到哈希中。它不能取代现有的价值观;如果要散列新值,则需要初始化新的hashlib.md5
对象。
您要散列的值是:
"Coconuts" -> 0e8f7761bb8cd94c83e15ea7e720852a
"CoconutsApples" -> 217f2e2059306ab14286d8808f687abb
"CoconutsApplesOranges" -> 4ce7cfed2e8cb204baeba9c471d48f07
"Coconuts" -> 0e8f7761bb8cd94c83e15ea7e720852a
"CoconutsBananas" -> a82bf69bf25207f2846c015654ae68d1
"CoconutsBananasOranges" -> 47dba619e1f3eaa8e8a01ab93c79781e
答案 2 :(得分:0)
您期望的是通常的加密库应该是您期望的。在大多数加密库中,在调用完成计算的方法(例如hexdigest
)后重置哈希对象。似乎hashlib.md5
使用了替代行为。
hashlib.md5
MD5要求输入填充1
位,零个或多个0
位以及输入的长度(以位为单位)。然后计算最终的哈希值。 hashlib.md5
内部似乎使用单独的变量执行最终计算,在没有最终填充的情况下对每个字符串进行散列后保持状态。
因此,哈希的结果是前面的字符串与给定字符串的串联,后跟正确的填充,duskwulf pointed out in his answer。
hashlib正确记录了这一点:
hash.digest()
返回到目前为止传递给
update()
方法的字符串的摘要 。这是一个digest_size
字节的字符串,可能包含非ASCII字符,包括空字节。
和
hash.hexdigest()
与
digest()
类似,但摘要以双倍长度的字符串形式返回,仅包含十六进制数字。这可用于在电子邮件或其他非二进制环境中安全地交换值。
hashlib.md5
由于似乎没有reset()
方法,您应该为要创建的每个单独哈希值创建一个新的md5
对象。幸运的是,哈希对象本身相对较轻(即使哈希本身不是这样),所以这不会占用很多CPU或内存资源。
对于散列本身,重置终结器中的散列可能没有多大意义。但它对签名生成很重要:您可能希望初始化相同的签名实例,然后使用它生成多个签名。哈希函数应该重置,以便它可以计算多条消息的签名。
有时,应用程序需要在多个输入上使用聚合哈希,包括中间哈希结果。在这种情况下,使用Merkle tree个散列,其中中间散列本身再次进行散列。
如上所述,我认为这是hashlib作者的糟糕API设计。对于密码学家来说,它肯定不会遵循最不惊讶的规则。