7

我正在编写一个简单的 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()

任何关于为什么会发生这种情况的答案或见解将不胜感激。提前致谢。

--更新--

我尝试在 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

4 回答 4

9

我有种感觉,您正在读取一个小于预期的数据块,而这两个文件的数据块恰好是相同的。我不知道为什么,但尝试用“rb”打开二进制文件。read() 应该读取到文件末尾,但 windows 的行为不同。从文档

在 Windows 上,附加到模式的 'b' 以二进制模式打开文件,因此还有 'rb'、'wb' 和 'r+b' 等模式。Windows 上的 Python 区分了文本文件和二进制文件;读取或写入数据时,文本文件中的行尾字符会自动稍作更改。这种对文件数据的幕后修改适用于 ASCII 文本文件,但它会破坏 JPEG 或 EXE 文件中的二进制数据。在读写此类文件时要非常小心使用二进制模式。在 Unix 上,将“b”附加到模式并没有什么坏处,因此您可以独立于平台使用它来处理所有二进制文件。

于 2011-04-26T11:15:30.577 回答
2

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

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

于 2011-04-26T08:01:41.833 回答
2

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

blair@blair-eeepc:~$ md5sum Bandwagon.mp3
b87cbc2c17cd46789cb3a3c51a350557  Bandwagon.mp3
blair@blair-eeepc:~$ 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'
于 2011-04-26T08:23:16.870 回答
0

就像@Delan Azabani 所说,这里有些可疑;碰撞肯定会发生,但不会那么频繁。检查歌曲是否相同,请更新您的帖子。

另外,如果您觉得您没有足够的密钥,您可以同时使用两种(甚至更多)散列算法:例如使用 MD5,您有2**128, 或340282366920938463463374607431768211456密钥。通过使用 SHA-1,您拥有2**1601461501637330902918203684832716283019655932542976键。通过组合它们,您有2**128 * 2**160497323236409786642155382248146820840100456150797347717440463976893159497012533375533056

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

于 2011-04-26T08:08:09.520 回答