簡體   English   中英

重用hashlib.md5可以計算相同字符串的不同值

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM