【问题标题】:MD5 and SHA-2 collisions in PythonPython 中的 MD5 和 SHA-2 冲突
【发布时间】:2011-08-12 20:21:50
【问题描述】:

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

我的问题是,无论我选择哪种散列算法,我都会遇到冲突。在一种情况下,我有两个文件恰好是同一张专辑中的 #1 和 #2,它们的文件大小不同,但无论我使用 MD5、SHA2-256、SHA2-512 等,它们都会产生相同的哈希键......

这是我第一次真正在文件上使用哈希键,这是一个意想不到的结果。从我对这些哈希算法的了解很少,我觉得这里发生了一些可疑的事情。这可能是与 MP3 或 Python 的实现有关的问题吗?

这是我正在使用的代码的 sn-p:

    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

【问题讨论】:

  • 你确定 MP3 文件本身是不同的吗?散列冲突不太可能发生,尤其是对于更大、更高级的算法,例如 SHA-1 和 SHA-2。有这么多冲突可能只是表明您实际上有许多重复文件。
  • 顺便说一句,你为什么调用 m.update()? m=hashlib.md5("foo"); m.update("foo") 等价于 m=hashlib.md5("foofoo")。

标签: python hash mp3 md5 sha


【解决方案1】:

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

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

【讨论】:

  • 请看我更新的帖子。文件肯定不相同。
  • @Jesse:很有趣。我建议你打开一个描述问题的 Python 错误 (bugs.python.org) - 这里重要的是 2 个文件,在 Windows 上你会得到不同的哈希值,而在 Linux 上是相同的哈希值
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    正如其他人所说,单个哈希冲突不太可能,并且几乎不可能,除非文件相同。我建议使用外部实用程序生成总和作为健全性检查。例如,在 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'
    

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 感谢将 open(path, 'r') 替换为 open(path, 'rb') 成功了。我现在得到两个不同的键
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 2012-11-06
      • 1970-01-01
      • 1970-01-01
      • 2012-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多