我正在创建与文件相关的应用程序。我一直在寻找计算文件校验和的方法。我想知道根据这个标准计算文件md5或SHA-1或其他东西的校验和的最佳散列方法是什么
请尽可能精心准备。
答案 0 :(得分:5)
这取决于您的使用案例。
如果您只担心意外碰撞,MD5和SHA-1都可以,MD5通常更快。实际上,MD4对于大多数用例来说也足够了,通常甚至更快......但它并没有广泛实现。 (特别是,它不在hashlib.algorithms_guaranteed
...虽然它应该在大多数Mac,Windows和Linux版本的hashlib_algorithms_available
中。)
另一方面,如果你担心故意攻击 - 即有人故意制作一个与你的哈希相匹配的伪造文件 - 你必须考虑你所保护的价值。 MD4几乎绝对不够,MD5可能还不够,但SHA-1是临界的。目前,Keccak(很快将由SHA-3推出)被认为是最好的选择,但是你会希望保持最佳状态,因为每年都会发生变化。
Cryptographic hash function上的维基百科页面有一个通常经常更新的表格。要理解该表:
要生成与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 /任何哈希值每个文件的整个文件。
最后,因为有人在评论中询问如何散写文件而不将整个内容读入内存:
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
的不同值(2的幂从4KB到8MB)。您可能还想尝试使用原始文件句柄(os.open
和os.read
),这在某些平台上有时会更快。
答案 1 :(得分:2)
具有足够位的散列大小的碰撞可能性theoretically非常小:
假设具有均匀分布的随机散列值,即集合 n个不同的数据块和生成b位的散列函数, 将存在一个或多个碰撞的概率p是有界的 通过块对的数量乘以a的概率 给对将发生碰撞,即
到目前为止,尚未观察到具有160位的SHA-1冲突。假设一个exabyte(10 ^ 18)的数据,在8KB块中,碰撞的理论机会是10 ^ -20 - 非常小的机会。
一个有用的捷径是通过短路消除已知彼此不同的文件。
例如,概要:
对于足够大小的X块,在第一遍中,95%以上的文件将被正确区分为唯一文件。这比盲目地读取整个文件并计算每个文件的完整哈希要快得多。
答案 2 :(得分:1)
md5对于校验和来说效果很好......与SHA-1相同......两者的碰撞概率都非常小,但我认为SHA-1的碰撞概率略小,因为它使用了更多的位
如果你真的很担心它,你可以使用两个校验和(一个md5和一个sha1)匹配和文件差异的机会极小(仍然不是100%不可能但非常非常不可能)...... (这似乎是糟糕的形式,也是迄今为止最慢的解决方案)
通常(读取:在我遇到的每个实例中)MD5或SHA1匹配足以假设唯一性
没有办法100%保证每个字节比较的唯一性
答案 3 :(得分:0)
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