【问题标题】:File Checksums in PythonPython 中的文件校验和
【发布时间】:2013-05-23 20:09:17
【问题描述】:

我正在创建一个与文件相关的应用程序。我一直在寻找计算文件校验和的方法。我想知道基于此标准计算文件 md5 或 SHA-1 或其他东西的校验和的最佳哈希方法是什么

  • 校验和应该是唯一的。我知道它的理论值,但我仍然希望碰撞的概率非常小。
  • 如果校验和是否相等,可以比较两个文件是否相等。
  • 速度(不是很重要,但仍然)

请尽可能详细说明。

【问题讨论】:

  • md5 往往对校验和非常有效......与 SHA-1 相同......尽管我认为 SHA-1 的碰撞概率略小,因为它使用更多位,但两者的冲突概率都非常小
  • 还有关于哪一个更快的比较?如果两个文件的校验和相同,我会确定它们是否相等吗?
  • 你可以对它们运行 timeit ... 不,它不是 100% 保证的 ... 只是不太可能发生冲突 ...
  • 好的。我了解碰撞的事情。那么我应该怎么做才能检查文件的唯一性呢。
  • 您可以同时使用校验和(一个 md5 和一个 sha1)匹配和文件不同的机会非常小(仍然不是 100% 不可能,但非常非常不可能)......通常(阅读:在我遇到的每一个例子中)一个 MD5 或一个 SHA1 匹配足以假设唯一性

标签: python django file checksum


【解决方案1】:

几天前我创建了一个小的重复文件删除器脚本,它读取文件的内容并为其创建一个哈希,然后与下一个文件进行比较,即使名称不同,校验和也将是一样的。。

import hashlib
import os

hash_table = {}
dups = []
path = "C:\\images"
for img in os.path.listdir(path):
    img_path = os.path.join(path, img)
    _file = open(img_path, "rb")
    content = _file.read()
    _file.close()
    md5 = hashlib.md5(content)
    _hash = md5.hexdigest()

    if _hash in hash_table.keys():
        dups.append(img)
    else:
        hash_table[_hash] = img    

【讨论】:

  • 但是确定相同校验和的文件不能不同吗?
  • 不...除了逐字节检查之外,没有办法保证相同...没有捷径...这不太可能发生冲突,但它仍然可以...
  • 如果文件内容相同,则逻辑上它们是重复的,这意味着它们将创建相同的校验和。
  • 你了解 MD5 是如何生成的吗...查看彩虹表以获取具有相同校验和但不同的事物的示例:P
  • @abhishekgarg 我没有询问如何计算的方法,但正如您所写的那样。让我告诉你这是一种非常糟糕的计算校验和的方法,特别是如果它是一个大文件,因为你正在将它整个读取到内存中。想知道比发布问题更好的方法,我可能会回答更好的方法。
【解决方案2】:

md5 往往适用于校验和......与 SHA-1 相同......虽然我认为 SHA-1 的碰撞概率略小,因为它使用更多位,所以两者的冲突概率都非常小

如果你真的很担心,你可以同时使用校验和(一个 md5 和一个 sha1)匹配和文件不同的机会非常小(仍然不是 100% 不可能,但非常非常不可能)...... (这似乎是一种糟糕的形式,也是迄今为止最慢的解决方案)

通常(阅读:在我遇到的每一个例子中)一个 MD5 或一个 SHA1 匹配足以假设唯一性

没有办法100%保证唯一性,缺少逐字节比较

【讨论】:

  • 如果您可以假设没有人愿意花费 14 美元的计算机时间来攻击您,则 MD5 足以假设唯一性。如果没有任何理由让任何人攻击你,这很好,但对于一些无聊的 14 岁孩子来说,为了好玩而可能值得付出的努力已经危险地接近了……
  • 很公平......(我投票赞成你的答案,恕我直言,它是正确的,我发布这个作为答案的唯一原因是因为 OP 从我的 cmets 要求它。)但真的是你的答案总结得最好
  • 我的评论不代表你的答案是错误的;这只是意味着 OP 必须在 任何 答案正确之前定义他的用例……如果攻击不是问题(或者它们是问题,但 MD5 提供了足够的保护),那么一切都很好。
【解决方案3】:

这取决于您的用例。

如果您只担心意外碰撞,MD5 和 SHA-1 都可以,而 MD5 通常更快。事实上,MD4 对于大多数用例来说也足够了,而且通常更快……但它并没有被广泛实施。 (特别是,它不在 hashlib.algorithms_guaranteed 中……尽管在大多数库存的 Mac、Windows 和 Linux 版本上它应该在 hashlib_algorithms_available 中。)

另一方面,如果您担心故意攻击(即有人故意制作与您的哈希匹配的虚假文件),您必须考虑所保护内容的价值。 MD4 几乎肯定是不够的,MD5 可能还不够,但 SHA-1 是临界的。目前,Keccak(不久将由 SHA-3 发布)被认为是最好的选择,但您需要保持领先,因为情况每年都在变化。

Cryptographic hash function 上的 Wikipedia 页面有一个通常会经常更新的表格。了解表格:

生成与 MD4 的碰撞只需要 3 轮,而 MD5 需要大约 200 万轮,而 SHA-1 需要 15 万亿轮。这足以产生碰撞需要几百万美元(以今天的价格计算)。这对你来说可能够好也可能不够好,但对 NIST 来说还不够好。


另外,请记住,“通常更快”并不像“在我的数据和平台上测试得更快”那么重要。考虑到这一点,在我的 Mac 上的 64 位 Python 3.3.0 中,我创建了一个 1MB 的随机 bytes 对象,然后这样做:

In [173]: md4 = hashlib.new('md4')
In [174]: md5 = hashlib.new('md5')
In [175]: sha1 = hashlib.new('sha1')
In [180]: %timeit md4.update(data)
1000 loops, best of 3: 1.54 ms per loop
In [181]: %timeit md5.update(data)
100 loops, best of 3: 2.52 ms per loop
In [182]: %timeit sha1.update(data)
100 loops, best of 3: 2.94 ms per loop

如您所见,md4 明显快于其他人。

使用hashlib.md5() 而不是hashlib.new('md5') 的测试,以及使用具有较少熵的bytes(运行1-8 个string.ascii_letters 以空格分隔)没有显示出任何显着差异。

而且,对于我的安装附带的哈希算法,如下所示,没有什么能比 md4 更好。

for x in hashlib.algorithms_available:
    h = hashlib.new(x)
    print(x, timeit.timeit(lambda: h.update(data), number=100))

如果速度真的很重要,你可以使用一个很好的技巧来改进它:使用一个糟糕但非常快的哈希函数,比如zlib.adler32,并且只将它应用于每个文件的前 256KB。 (对于某些文件类型,最后 256KB 或最靠近中间的 256KB 不超过等可能比第一个更好。)然后,如果发现冲突,生成 MD4/SHA-1/Keccak/whatever hashes on每个文件的整个文件。


最后,因为有人在评论中询问如何在不将整个文件读入内存的情况下对文件进行哈希处理:

def hash_file(path, algorithm='md5', bufsize=8192):
    h = hashlib.new(algorithm)
    with open(path, 'rb') as f:
        block = f.read(bufsize)
        if not block:
            break
        h.update(block)
    return h.digest()

如果充分发挥性能的每一点很重要,您需要在您的平台上尝试不同的 bufsize 值(从 4KB 到 8MB 的 2 的幂)。您可能还想尝试使用原始文件句柄(os.openos.read),这有时在某些平台上可能更快。

【讨论】:

  • 没有速度不是那么重要,而只是一个考虑因素。我决定使用 SHA-1,因为我认为它是速度和安全性的完美结合。您认为这是一个不错的选择吗?
  • 我同意你的回答,因为我发现它是解释性的。谢谢
  • @SaranshMohapatra:嗯,我没有信息来确定它是否适合您的用例……但它通常是一个不错的选择,这就是它如此普遍的原因,所以如果这对您来说是一个不错的选择,我当然不会感到惊讶。
  • 我希望你能在另一个问题上帮助我......请看看你是否能提供帮助。 stackoverflow.com/questions/16816815/authentication-in-android
  • “如何在不将整个内容读入内存的情况下散列文件”编辑似乎缺少一个 while 循环,该循环会继续读取直到文件被完全消耗。
【解决方案4】:

足够位的哈希大小的冲突可能性是theoretically,非常小:

假设随机散列值具有均匀分布,一个集合 n 个不同的数据块和一个生成 b 位的散列函数, 发生一次或多次碰撞的概率 p 是有界的 由块对的数量乘以 给定的对将发生碰撞,即

而且,到目前为止,还没有观察到 160 位的 SHA-1 冲突。假设 1 艾字节 (10^18) 的数据,在 8KB 块中,理论上发生冲突的几率是 10^-20 - 非常非常小的几率。

一个有用的快捷方式是通过短路消除已知彼此不同的文件。

例如,在大纲中:

  1. 读取所有感兴趣文件的前 X 块;
  2. 将前 X 个块具有相同哈希值的数据排序为可能相同的文件数据;
  3. 对于具有唯一前 X 个块的每个文件,您可以假设整个文件相对于所有其他测试文件是唯一的 - 您不需要读取该文件的其余部分;
  4. 对于剩余的文件,读取更多块,直到您证明签名相同或不同。

使用足够大小的 X 块,95% 以上的文件将在第一遍中被正确区分为唯一文件。这比盲目地读取整个文件并计算每个文件的完整哈希要快得多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-09
    相关资源
    最近更新 更多