Python中的文件校验和

Sar*_*tra 4 python django checksum file

我正在创建一个与文件相关的应用程序.我一直在寻找计算文件校验和的方法.我想知道根据这个标准计算文件md5或SHA-1或其他东西的校验和的最佳散列方法是什么

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

请尽可能精心准备.

aba*_*ert 6

这取决于您的使用案例.

如果您只担心意外碰撞,MD5和SHA-1都可以,MD5通常更快.实际上,MD4对于大多数用例来说也足够了,通常甚至更快......但它并没有广泛实现.(特别是,它不在hashlib.algorithms_guaranteed......虽然它应该在hashlib_algorithms_available大多数股票Mac,Windows和Linux版本中.)

另一方面,如果你担心故意攻击 - 即有人故意制作一个与你的哈希相匹配的虚假文件 - 你必须考虑你所保护的价值.MD4几乎绝对不够,MD5可能还不够,但SHA-1是临界的.目前,Keccak(很快将由SHA-3推出)被认为是最好的选择,但你会想要保持领先,因为事情每年都会发生变化.

关于加密哈希函数的维基百科页面有一个通常经常更新的表.要了解表格:

要产生与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
Run Code Online (Sandbox Code Playgroud)

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

使用hashlib.md5()代替hashlib.new('md5')和使用bytes较少熵的测试(string.ascii_letters以空格分隔的1-8的运行)没有显示任何显着差异.

而且,对于我的安装附带的哈希算法,如下面所测试的,没有什么比md4更好.

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

如果速度非常重要,那么可以使用一个很好的技巧来改进:使用一个糟糕但非常快速的哈希函数,例如zlib.adler32,只将它应用于每个文件的前256KB.(对于某些文件类型,最后256KB,或最接近中间的256KB而不会过去,等等可能比第一个更好.)然后,如果发现碰撞,生成MD4/SHA-1/Keccak /无论什么哈希值每个文件的整个文件.


最后,因为有人在评论中询问如何散列文件而不将整个内容读入内存:

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()
Run Code Online (Sandbox Code Playgroud)

如果挤出每一点性能很重要,那么你需要bufsize在你的平台上试验不同的值(2的功率从4KB到8MB).您还可能希望尝试使用原始文件句柄(os.openos.read),这在某些平台上有时会更快.