在Python中生成唯一哈希的最安全方法是什么?

5
我需要生成可用于文件名的唯一标识符,并且在给定相同输入值的情况下可以再现。由于源输入有数百万种组合,因此我需要生成数百万个这些标识符。
为了简单起见,我将在示例中使用一个小集合,但实际集合可能相当大(数百甚至数千项)。它们比手动编码到文件名中的内容更大。
我注意到生成UUID的第5种方法允许您提供字符串输入。
> input_set = {'apple', 'banana', 'orange'}
> uuid.uuid5(uuid.NAMESPACE_URL, pickle.dumps(input_set)).hex
'f39926529ad45997984643816c1bc403'

文档称其在内部使用SHA1。冲突的风险太高了吗?有没有更好的方法可靠地哈希唯一标识符?


2
这是一个处理UUID冲突问题的资源:https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions - user8651755
1
维基百科的文章具体讨论了版本3、4和5发生碰撞的可能性。 - user8651755
1
@BrendanAbel:是什么类型的字符串?它们都是预先知道的吗?所有哈希函数都保证会有碰撞。虽然碰撞的几率极低,但如果您可以对输入数据进行假设,可能有办法保证您永远不会发生碰撞。 - Blender
@BrendanAbel:这些集合可以有多大,每个元素的可能选择有多少? - Blender
1
@BrendanAbel:如果您可以枚举所有有效的组合并将字符串集映射到其相应的索引,那么您只需要20位(或4个字母数字字符)。如果您只有一百万个有效输入,则仅使用加密哈希函数并手动验证是否存在冲突可能会更容易。由于需要数千年的处理器时间才能故意找到一个,我怀疑您不会意外地找到一个。 - Blender
显示剩余9条评论
3个回答

6

与其使用pysha3(请参见DoesData的答案),你也可以使用内置的hashlib

import hashlib

h = hashlib.sha3_512() # Python 3.6+
h.update(b"Hello World")
h.hexdigest()

输出:

'3d58a719c6866b0214f96b0a67b37e51a91e233ce0be126a08f35fdf4c043c6126f40139bfbc338d44eb2a03de9f7bb8eff0ac260b3629811e389a5fbee8a894'

MD5可以吗?例如:https://dev59.com/HGAg5IYBdhLWcg3w9e_l - Charlie Parker

6

您从字符串中获取SHA1碰撞的概率非常低。目前已知的SHA1碰撞少于63个。

首次发现SHA1碰撞

第一次计算出SHA-1哈希碰撞。只需要五个聪明的大脑...和6610年的处理器时间

在密码学世界中,SHA1不再被认为是安全的,但在这里确实超出了您的期望。

加密哈希函数旨在成为单向函数。这意味着函数的反函数“难以”计算。(即,仅知道输出无法帮助您确定输入)正如Blender在评论中指出的那样,这与碰撞发生的机会无关。

查看生日悖论,了解如何计算碰撞概率的基本信息。

这个问题讨论了SHA1碰撞的可能性。本文指出:

如果从假定在多项式时间内不可解决的问题P中,可证明地将查找碰撞归约为多项式时间,则密码哈希函数对抗碰撞攻击具有可证明的安全性。该函数被称为可证明安全或仅可证明。

这里列出了“安全”的哈希算法。

更新 您在评论中提到您的输入远远超过SHA1的160位限制。在这种情况下,我建议您使用SHA3,因为您的输入大小没有限制。请查看Python 文档以获取更多信息。

以下是一个基本示例:

import sha3
k = sha3.keccak_512()
k.update(b"data")
k.hexdigest()
'1065aceeded3a5e4412e2187e919bffeadf815f5bd73d37fe00d384fe29f55f08462fdabe1007b993ce5b8119630e7db93101d9425d6e352e22ffe3dcb56b825'

谢谢。虽然我想指出的是,我不是使用文件名作为源输入,而是使用非常大的字符串;比160位SHA1或128位UUID字符串要大得多。 - Brendan Abel
2
无论单向函数是否存在,任何哈希函数都保证存在碰撞。 - Blender
如果名称较长,则考虑使用不同的哈希算法。一些算法可以处理任意长度的字符串。 - DoesData
1
@BrendanAbel:SHA-1的输出为160位。每种哈希函数都有固定长度的输出,这就是它们有用的原因。它们可以接受任意量的数据并产生从中派生的固定长度哈希值。 - Blender
MD5可以吗?例如:https://dev59.com/HGAg5IYBdhLWcg3w9e_l - Charlie Parker
@CharlieParker 这取决于您的使用情况,但通常来说,MD5不安全。参考 - https://security.stackexchange.com/questions/19906/is-md5-considered-insecure - DoesData

0
如果较小的 base64.urlsafe_b64encode 输出更可取:
> import base64, hashlib

> base64.urlsafe_b64encode(hashlib.sha3_512('asdf'.encode()).digest())
b'jYjPWyD1Os164UebWzbcICF1OwSZAsdyR7snsTGzAL08qL7vKHVtzie4mQhnxFd6JTXn47dRQTmcoalMyEsOuQ=='

上述输出的长度为88,而相应的十六进制长度为128。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接