Python中的MD5和SHA-2冲突

时间:2011-04-26 07:53:25

标签: python hash mp3 md5 sha

我正在编写一个简单的MP3编目器来跟踪我的各种设备上的MP3。我计划使用MD5或SHA2键来识别匹配的文件,即使它们已经被重命名/移动等等。我不是想匹配逻辑上相同的MP3(即:相同的歌曲,但编码方式不同)。我有大约8000个MP3。只有大约6700个生成了唯一的密钥。

我的问题是,无论我选择何种哈希算法,我都会遇到冲突。在一个案例中,我有两个文件碰巧是同一专辑中的曲目#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)中执行此代码并且它没有产生冲突。如stat调用所示,文件不一样。我还下载了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

4 个答案:

答案 0 :(得分:8)

我有点感觉你正在读一小于预期的数据,而且这两个文件的块相同。我不知道为什么,但尝试用'rb'打开二进制文件。 read()应该读取到文件末尾,但是Windows的行为方式不同。来自文档

  

在Windows上,“b”附加到模式   以二进制模式打开文件,所以   还有像'rb','wb'这样的模式,   和'r + b'。 Windows上的Python制作了一个   文本和二进制之间的区别   文件;中的行尾字符   文本文件会自动更改   稍微读取或写入数据时。   这种幕后修改   文件数据适用于ASCII文本   文件,但它会破坏二进制数据   像在JPEG或EXE文件中那样。是   非常小心使用二进制模式时   读写这样的文件。上   Unix,附加一个'b'也没有坏处   到模式,所以你可以使用它   平台 - 独立于所有二进制文件   文件。

答案 1 :(得分:2)

如果几个不同的哈希算法都返回相同的哈希结果,或者您的实现中存在错误,那么您遇到问题的文件几乎肯定是相同的。

作为一个完整性测试编写你自己的“哈希”,它只是完全返回文件的内容,看看这个是否产生相同的“哈希”。

答案 2 :(得分:1)

正如其他人所说的那样,单个哈希冲突是不可能的,并且几乎不可能,除非文件是相同的。我建议使用外部实用程序生成总和作为理智检查。例如,在Ubuntu(以及大多数/所有其他Linux发行版)中:

blair@blair-eeepc:~$ md5sum Bandwagon.mp3
b87cbc2c17cd46789cb3a3c51a350557  Bandwagon.mp3
blair@blair-eeepc:~$ sha256sum Bandwagon.mp3 
b909b027271b4c3a918ec19fc85602233a4c5f418e8456648c426403526e7bc0  Bandwagon.mp3

快速Google搜索显示Windows机器可以使用类似的实用程序。如果您看到与外部实用程序的冲突,则文件是相同的。如果没有碰撞,你做错了。我怀疑Python实现是错误的,因为我在Python中执行哈希时获得相同的结果:

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

答案 3 :(得分:0)

就像@Delan Azabani所说的那样,这里有一些可疑的东西;碰撞必然会发生,但不是经常发生。检查歌曲是否相同,并请更新你的帖子。

此外,如果您觉得自己没有足够的密钥,可以同时使用两个(甚至更多)哈希算法:例如,使用MD5,您可以2**128或{{ 1}}键。通过使用SHA-1,您可以使用3402823669209384634633746074317682114562**160个密钥。通过组合它们,您可以14615016373309029182036848327162830196559325429762**128 * 2**160

(但如果你问我,MD5足以满足你的需求。)