【问题标题】:MD5 digest vs. hexdigest collision riskMD5 摘要与十六进制摘要碰撞风险
【发布时间】:2013-08-18 02:55:54
【问题描述】:

我通过散列包含所有这些信息的字符串,并比较散列对象的十六进制摘要来比较个人的个人信息,特别是他们的姓名、出生日期、性别和种族。这会产生一个 32 位的十六进制数,我将其用作数据库中的主键。例如,使用我的识别字符串将像这样工作:

>> import hashlib
>> id_string = "BrianPeterson08041993MW"
>> byte_string = id_string.encode('utf-8')
>> hash_id = hashlib.md5(bytesring).hexdigest()
>> print(hash_id)
'3b807ad8a8b3a3569f098a575091bc79'

此时,我正在尝试确定碰撞风险。我的理解是 MD5 没有明显的碰撞风险,至少对于我的相对较小的字符串(长度约为 20-40 个字符)而言。但是,我使用的不是 128 位摘要对象,而是 32 位十六进制摘要。

现在,我相信 hexdigest 是对摘要的压缩(也就是说,它存储在更少的字符中),那么在比较 hexdigest 时不会增加冲突的风险吗?还是我不在基地?

【问题讨论】:

  • 32 个字符·4 位/字符 = 128 位
  • 啊。那么 hexdigest 是表示哈希的正确方式,并且不会增加非唯一性的风险?
  • hexdigest 只返回二进制 digest 的十六进制表示。
  • 对。我想我的问题是:不同的表示是否有不同的机会是非唯一的,这取决于他们使用多少信息单元来进行表示与原始消息需要多少信息单元进行编码?如果是这样,最好的表示是什么?嗯,让我在你的下一个答案前言:像我 10 岁一样跟我说话。
  • 只是要知道:散列的大小与您的字符串几乎相同...为什么要计算它,而不是将其用作密钥?

标签: hash md5 digest


【解决方案1】:

现在,我相信 hexdigest 是对摘要的压缩(也就是说,它存储在更少的字符中),那么在比较 hexdigest 时不会增加冲突的风险吗?还是我不在基地?

[...]

我想我的问题是:根据用于表示的信息单元数与原始消息编码所需的信息单元数,不同的表示是否有不同的机会成为非唯一的?如果是这样,最好的表示是什么?嗯,让我在你的下一个答案前言:像我 10 岁一样跟我说话

老问题,但是是的,可以这么说,你有点偏离base

重要的是随机位数,而不是演示文稿的长度。

摘要只是一个数字,一个整数,可以使用不同数量的不同数字转换为字符串。例如,一个 128 位的数字以一些不同的基数显示:

"340106575100070649932820283680426757569" (base 10)
"ffde24cb47ecbff8d6e461a67c930dc1" (base 16, hexadecimal)
"7vroicmhvcnvsddp31kpu963e1" (base 32)

越短越好(在身份验证令牌等方面),但每个表示都有完全相同的信息和发生冲突的机会。较短的表示较短,原因与“55”比“110111”短的原因相同,但仍编码相同的内容。

This answer 也可能会澄清一些事情,以及玩弄如下代码:

new BigInteger("340106575100070649932820283680426757569").toString(2)

...或其他语言中的等价物(上面的 Java/Scala)。

在更实际的层面上,

[...] 我在数据库中用作主键

我不明白为什么不通过使用普通的自动递增 id 列(在 MySQL 中为BIGINT AUTO_INCREMENT,在 PostgreSQL 中为BIGSERIAL)来消除 任何 冲突的可能性。

【讨论】:

  • 这是一个很好的答案 - 谢谢!关于为什么不直接使用普通的自增ID的问题,如果使用hash,只要知道底层数据就可以在数据库中找到相关记录。但是,如果您使用自动增量键(我确实将其用于某些目的),您将需要该键来查找记录(即,除非您已经知道该键,否则您不能直接进入记录)。当您想要快速搜索很长的字段组合而不必枚举查询中的每个字段时,哈希还可以提供速度优势。
【解决方案2】:

缩写的 32 位十六进制摘要(8 个十六进制字符)不足以有效保证用户数据库无冲突。

生日碰撞概率的公式在这里:

What is the probability of md5 collision if I pass in 2^32 sets of string?

使用 32 位密钥意味着您的软件将在大约 10,000 个用户时开始出现故障。 The collision probability would be about 1%. 在那之后情况变得非常糟糕。在 100,000 个用户时,冲突概率为 69%。

64 位密钥和 100 亿用户是碰撞率约 2.7% 的另一个突破点。

对于 1000 亿用户(在可预见的未来地球人口的上限),我认为 96 位密钥有点冒险:collision chance is about one in 100 million. 确实,您需要一个 128 位密钥,它给出了你a collision rate of about 1X10^-17.

128 位密钥的长度为 128/4 = 32 个十六进制字符。如果您想使用较短的密钥,出于美观目的,您需要使用 23 个字母数字字符才能超过 128 位。或者,如果您使用可打印字符(ASCII 32-126),则可以使用 20 个字符。

因此,当您谈论用户时,您需要至少 128 位的无冲突随机密钥,或 20-32 字符长的字符串,或 128/8 = 16 字节的二进制表示。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-24
    • 2021-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多