这取决于您的用例。
如果您只担心意外碰撞,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.open 和 os.read),这有时在某些平台上可能更快。