[英]Reusing hashlib.md5 calculates different values for identical strings
這是我的第一個測試代碼:
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應該每次都有相同的結果。 我錯過了什么嗎?
因為您正在使用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,獨立計算。
hashlib.md5.update()
將數據添加到哈希。 它不會取代現有的價值; 如果要哈希一個新值,則需要初始化一個新的hashlib.md5
對象。
您正在散列的值是:
"Coconuts" -> 0e8f7761bb8cd94c83e15ea7e720852a
"CoconutsApples" -> 217f2e2059306ab14286d8808f687abb
"CoconutsApplesOranges" -> 4ce7cfed2e8cb204baeba9c471d48f07
"Coconuts" -> 0e8f7761bb8cd94c83e15ea7e720852a
"CoconutsBananas" -> a82bf69bf25207f2846c015654ae68d1
"CoconutsBananasOranges" -> 47dba619e1f3eaa8e8a01ab93c79781e
您期望的通常是您應該期望從常見的加密庫。 在大多數加密庫中,在調用完成計算的方法(例如hexdigest
之后重置哈希對象 。 看來hashlib.md5
使用了替代行為。
hashlib.md5
結果 MD5要求輸入以1
位,0或0
位填充,輸入長度以位為單位。 然后計算最終的哈希值。 hashlib.md5
內部似乎使用單獨的變量執行最終計算,在沒有此最終填充的情況下對每個字符串進行散列后保持狀態。
因此,哈希的結果是先前字符串與給定字符串的串聯,然后是正確的填充,正如duskwulf在他的回答中指出的那樣 。
hashlib正確記錄了這一點:
hash.digest()
返回到目前為止傳遞給
update()
方法的字符串的摘要。 這是一個digest_size
字節字符串,可能包含非ASCII字符,包括空字節。
和
hash.hexdigest()
像
digest()
一樣,但摘要是以雙倍長度的字符串形式返回的,只包含十六進制數字。 這可用於在電子郵件或其他非二進制環境中安全地交換值。
hashlib.md5
解決方案 由於似乎沒有reset()
方法,您應該為要創建的每個單獨的哈希值創建一個新的md5
對象。 幸運的是,哈希對象本身相對較輕(即使哈希本身不是這樣),因此不會占用很多CPU或內存資源。
對於散列本身,重置終結器中的散列可能沒有那么多意義。 但它對簽名生成很重要:您可能希望初始化相同的簽名實例,然后使用它生成多個簽名。 哈希函數應該重置,以便它可以計算多個消息的簽名。
有時,應用程序需要多個輸入的聚合哈希,包括中間哈希結果。 然而,在這種情況下,使用Merkle的哈希樹 ,其中中間的哈希本身再次進行哈希處理。
如上所述,我認為這是hashlib作者的糟糕API設計。 對於密碼學家來說,它肯定不遵循最不驚訝的規則。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.