- 校验和应该是唯一的。我知道这是理论上的,但我仍然希望碰撞的概率非常非常小。
- 如果它们的校验和相等,则可以比较两个文件是否相等。
- 速度(不是非常重要,但仍然需要考虑)
这取决于您的使用情况。
如果您只担心意外碰撞,那么MD5和SHA-1都可以,并且MD5通常更快。实际上,对于大多数用例而言,MD4也足够了,而且通常更快...但它没有被广泛实现。 (特别是它不在hashlib.algorithms_guaranteed
中...尽管它应该在大多数股票Mac、Windows和Linux版本的hashlib_algorithms_available
中。)
另一方面,如果您担心故意攻击-即有人有意地制作一个与您的哈希匹配的虚假文件-则必须考虑您所保护的价值。 MD4几乎肯定不足,MD5可能不足,但SHA-1接近边界。目前,Keccak(即将成为SHA-3)被认为是最好的选择,但您需要及时了解此事,因为每年都会发生变化。
密码哈希函数的维基百科页面有一张表格,通常会更新得相当频繁。要理解表格:
只需3轮即可生成针对MD4的碰撞,而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
值(从4KB到8MB的2次幂)。您还可以尝试使用原始文件句柄(os.open
和os.read
),这可能在某些平台上更快。MD5通常用于校验和... SHA-1也是如此...两者都有非常小的碰撞概率,尽管我认为SHA-1的碰撞概率略微更小,因为它使用更多的比特
如果你真的很担心这个问题,你可以同时使用两个校验和(一个md5和一个sha1),两者都匹配但文件不同的概率是微乎其微的(仍然不是100%不可能,但非常非常非常不可能)...(这似乎是一种不好的方式,而且是最慢的解决方案)
通常情况下(读作:在我遇到的每一个实例中),MD5或SHA1的任意一个匹配就足以假定唯一性
除了逐字节比较之外,没有办法百分之百地保证唯一性
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