2011-04-26 102 views
7

我在寫一個簡單的MP3編目器來跟蹤哪些MP3在我的各種設備上。我打算使用MD5或SHA2鍵來識別匹配的文件,即使它們已被重命名/移動等。我並不試圖匹配在邏輯上等同的MP3(即:同一首歌,但編碼不同)。我有大約8000個MP3。其中只有約6700個生成了唯一的密鑰。Python中的MD5和SHA-2碰撞

我的問題是,無論我選擇何種哈希算法,我都會碰到碰撞。在一個案例中,我有兩個文件碰巧是同一個專輯中的曲目#1和#2,它們是不同的文件大小,但是無論使用MD5,SHA2-256,SHA2-512等,還是產生相同的散列鍵。

這是我第一次真正在文件上使用散列鍵,這是一個意外的結果。從我對這些散列算法的瞭解我感覺有點可疑。這可能是與MP3或Python的實現相關的問題嗎?

下面是我使用的代碼片段:

data = open(path, 'r').read() 

    m = hashlib.md5(data) 

    m.update(data) 

    md5String = m.hexdigest() 

任何答案或見解,爲什麼發生這種情況,將不勝感激。提前致謝。

--UPDATE--

我試圖執行在Linux代碼(與Python 2.6),並沒有產生衝突。正如統計調用所顯示的那樣,這些文件並不相同。我也下載了WinMD5,並沒有產生碰撞(8d327ef3937437e0e5abbf6485c24bb3和9b2c66781cbe8c1be7d6a1447994430c)。這是Windows上的Python hashlib的錯誤嗎?我在Python 2.7.1和2.6.6下嘗試了相同的結果。

import hashlib 
import os 

def createMD5(path): 

    fh = open(path, 'r') 
    data = fh.read() 
    m = hashlib.md5(data) 
    md5String = m.hexdigest() 
    fh.close() 
    return md5String 

print os.stat(path1) 
print os.stat(path2) 
print createMD5(path1) 
print createMD5(path2) 

>>> nt.stat_result(st_mode=33206, st_ino=0L, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=6617216L, st_atime=1303808346L, st_mtime=1167098073L, st_ctime=1290222341L) 
>>> nt.stat_result(st_mode=33206, st_ino=0L, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=4921346L, st_atime=1303808348L, st_mtime=1167098076L, st_ctime=1290222341L) 
>>> a7a10146b241cddff031eb03bd572d96 
>>> a7a10146b241cddff031eb03bd572d96 
+5

你確定MP3文件本身實際上是不同的嗎?散列衝突是不太可能的,特別是對於更大,更高級的算法,如SHA-1和SHA-2。有這麼多的碰撞可能只是表明你實際上有很多重複的文件。 – 2011-04-26 07:59:43

+1

順便說一句,爲什麼你叫m.update()?米= hashlib.md5( 「foo」 的); m.update(「foo」)等同於m = hashlib.md5(「foofoo」)。 – 2011-04-26 08:06:02

回答

8

我那種有你正在閱讀一大塊數據比預期的更小的感覺,這個塊對兩個文件來說都是一樣的。我不知道爲什麼,但嘗試用'rb'打開二進制文件。 read()應該讀取文件的結尾,但窗口的行爲不同。從文檔

在Windows中,「B」附加到模式 以二進制方式打開文件,所以 也有模式,如「RB」,「WB」, 和「R + B」。 Windows上的Python使 文件與二進制文件 之間的區別;當讀取或寫入數據時, 文本文件中的行尾字符會自動更改爲 。 對 文件數據的這種後臺修改對於ASCII文本 文件來說很好,但它會像JPEG或EXE文件中那樣破壞二進制數據 。當 讀寫這類文件時,要非常小心地使用二進制模式。在 Unix上,將'b' 添加到該模式並不會造成任何影響,因此您可以在所有二進制 文件中使用它的平臺無關的 。

+0

,謝謝替換open(path ,'r')與開放(路徑,'rb')做了訣竅。我現在得到兩個不同的密鑰 – Jesse 2011-04-26 11:29:43

2

您遇到問題的文件幾乎肯定是相同的,如果幾個不同的散列算法都返回他們相同的散列結果,或出現在你實現中的錯誤。

作爲一個完整性測試,編寫你自己的「散列」,它只是將文件內容全部返回,看看它是否會生成相同的「哈希」。

+0

請看我更新的帖子。這些文件絕對不是完全相同的。 – Jesse 2011-04-26 10:56:24

+0

@Jesse:有趣。我建議你打開一個Python bug(http://bugs.python.org/)來描述這個問題 - 這裏最重要的是2個文件,在windows上你可以得到不同的哈希值,而在linux上的哈希值爲 – 2011-04-26 11:09:46

0

像@Delan Azabani說,這裏有點可疑;碰撞必然會發生,但並不常見。檢查歌曲是否相同,請更新您的帖子。此外,如果您覺得沒有足夠的密鑰,則可以同時使用兩種(或更多)散列算法:例如,使用MD5時,您有2**128340282366920938463463374607431768211456鍵。通過使用SHA-1,您有2**1601461501637330902918203684832716283019655932542976密鑰。通過組合它們,你有2**128 * 2**160497323236409786642155382248146820840100456150797347717440463976893159497012533375533056

(但如果你問我,MD5是綽綽有餘了您的需求更多。)

1

正如其他人所指出的,單一的哈希衝突的可能性不大,且多在附近上是不可能的,除非該文件是相同的。我會建議用外部工具產生這些數額作爲理智檢查。例如,在Ubuntu(和大多數/所有其他Linux發行版):

[email protected]:~$ md5sum Bandwagon.mp3 
b87cbc2c17cd46789cb3a3c51a350557 Bandwagon.mp3 
[email protected]:~$ sha256sum Bandwagon.mp3 
b909b027271b4c3a918ec19fc85602233a4c5f418e8456648c426403526e7bc0 Bandwagon.mp3 

一個快速谷歌搜索顯示有可用於Windows的機器類似的實用程序。如果您看到與外部實用程序的衝突,那麼這些文件是相同的。如果沒有碰撞,你做錯了什麼。我懷疑Python的實現是錯誤的,因爲我得到在Python中的散列時相同的結果:

>>> import hashlib 
>>> hashlib.md5(open('Bandwagon.mp3', 'r').read()).hexdigest() 
'b87cbc2c17cd46789cb3a3c51a350557' 
>>> hashlib.sha256(open('Bandwagon.mp3', 'r').read()).hexdigest() 
'b909b027271b4c3a918ec19fc85602233a4c5f418e8456648c426403526e7bc0'