两个不同的字符串能生成相同的MD5哈希码吗?

106

针对我们的每个二进制资产,我们会生成一个MD5哈希值。这被用来检查特定的二进制资产是否已经存在于我们的应用程序中。但是,不同的二进制资产是否可能生成相同的MD5哈希值?因此,不同的字符串是否可能生成相同的MD5哈希值?


这是用来检查某个二进制资产是否已经存在于我们的应用程序中。这个要求是关于唯一性的。MD5不用于这种情况,通常它被用作校验和来确定某些东西是否被更改过(它只是一个哈希)。同样的数据再次产生相同的MD5校验和的可能性非常小。 - Mladen B.
12个回答

103
对于一组数十亿的资产来说,《随机碰撞的机会微乎其微》- 这不应该让您担心。考虑到生日悖论,假设有2^64(或18,446,744,073,709,551,616)个资产,单个MD5冲突在此集合中出现的概率为50%。在这个规模下,您可能会在存储容量方面超过谷歌。
然而,由于MD5哈希函数已被破解(它容易受到碰撞攻击的攻击),任何决定攻击者都可以在几秒钟内生成2个相撞的资产。因此,如果您想使用MD5,请确保这样的攻击者不会危及您的应用程序的安全性!
此外,如果攻击者可以伪造与您数据库中的现有资产相撞的冲突,那么请考虑后果。虽然(截至2011年) MD5没有已知的这种攻击(预像攻击),但通过扩展当前关于碰撞攻击的研究,这是可能的。
如果这些问题成为问题,请考虑查看哈希函数SHA-2系列(SHA-256、SHA-384和SHA-512)。缺点是稍微慢一些,并且哈希输出较长。

5
就我所知,现在用“天数”来形容这个情况有些夸张了。 - Nick Johnson
1
真的,我更新了我的帖子。2004年的随机碰撞攻击非常快。而2007年的MD5前缀碰撞攻击可能需要数天时间,但通常对攻击者更有用。 - intgr
2
请参考Rubens的答案,其中提供了一个可行的示例,可以在几个小时内生成两个不同可执行文件之间的冲突。 :) - Nick Johnson
有没有两个有意义的文本在相同的上下文中具有相同的MD5哈希值的例子?就像“让我们在星期一下午5:00见面”和“我永远不会见你!”我知道这是非常罕见的情况,但有没有任何例子呢? - endo64

47

MD5是一种加密哈希函数 - 因此,两个不同的字符串可以生成相同的MD5代码。

特别地,需要注意的是,MD5代码具有固定长度,因此可能的MD5代码数量是有限的。然而,任意长度的字符串数量绝对是无限的,因此逻辑上一定会发生碰撞。


15
是的,两个不同的字符串可能会生成相同的MD5哈希码。
以下是一个简单的测试,使用非常相似的十六进制字符串二进制消息:
$ echo '4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa200a8284bf36e8e4b55b35f427593d849676da0d1555d8360fb5f07fea2' | xxd -r -p | tee >/dev/null >(md5) >(sha1sum)
c6b384c4968b28812b676b49d40c09f8af4ed4cc  -
008ee33a9d58b51cfeb425b0959121c9

$ echo '4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa202a8284bf36e8e4b55b35f427593d849676da0d1d55d8360fb5f07fea2' | xxd -r -p | tee >/dev/null >(md5) >(sha1sum)
c728d8d93091e9c7b87b43d9e33829379231d7ca  -
008ee33a9d58b51cfeb425b0959121c9

它们生成不同的SHA-1校验和,但相同的MD5哈希值。其次,这些字符串非常相似,因此很难找到它们之间的区别。
可以使用以下命令找到差异:
$ diff -u <(echo 4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa200a8284bf36e8e4b55b35f427593d849676da0d1555d8360fb5f07fea2 | fold -w2) <(echo 4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa202a8284bf36e8e4b55b35f427593d849676da0d1d55d8360fb5f07fea2 | fold -w2)
--- /dev/fd/63  2016-02-05 12:55:04.000000000 +0000
+++ /dev/fd/62  2016-02-05 12:55:04.000000000 +0000
@@ -33,7 +33,7 @@
 af
 bf
 a2
-00
+02
 a8
 28
 4b
@@ -53,7 +53,7 @@
 6d
 a0
 d1
-55
+d5
 5d
 83
 60

上面的碰撞示例来自Marc Stevens的文章:MD5的单块碰撞,2012年;他解释了他的方法,并提供了源代码(论文的备用链接)。

另一个测试:

$ echo '0e306561559aa787d00bc6f70bbdfe3404cf03659e704f8534c00ffb659c4c8740cc942feb2da115a3f4155cbb8607497386656d7d1f34a42059d78f5a8dd1ef' | xxd -r -p | tee >/dev/null >(md5) >(sha1sum)
756f3044edf52611a51a8fa7ec8f95e273f21f82  -
cee9a457e790cf20d4bdaa6d69f01e41

$ echo '0e306561559aa787d00bc6f70bbdfe3404cf03659e744f8534c00ffb659c4c8740cc942feb2da115a3f415dcbb8607497386656d7d1f34a42059d78f5a8dd1ef' | xxd -r -p | tee >/dev/null >(md5) >(sha1sum)
6d5294e385f50c12745a4d901285ddbffd3842cb  -
cee9a457e790cf20d4bdaa6d69f01e41

SHA-1校验和不同,但MD5哈希值相同。

区别在于一个字节:

$ diff -u <(echo 0e306561559aa787d00bc6f70bbdfe3404cf03659e704f8534c00ffb659c4c8740cc942feb2da115a3f4155cbb8607497386656d7d1f34a42059d78f5a8dd1ef | fold -w2) <(echo 0e306561559aa787d00bc6f70bbdfe3404cf03659e744f8534c00ffb659c4c8740cc942feb2da115a3f415dcbb8607497386656d7d1f34a42059d78f5a8dd1ef | fold -w2)
--- /dev/fd/63  2016-02-05 12:56:43.000000000 +0000
+++ /dev/fd/62  2016-02-05 12:56:43.000000000 +0000
@@ -19,7 +19,7 @@
 03
 65
 9e
-70
+74
 4f
 85
 34
@@ -41,7 +41,7 @@
 a3
 f4
 15
-5c
+dc
 bb
 86
 07

上面的例子改编自Tao Xie和Dengguo Feng: 使用仅一个消息块构造MD5碰撞, 2010年。


相关:


13
是的,这是可能的。实际上,这是一个生日悖论问题。但是,随机选择两个字符串具有相同的MD5哈希值的概率非常低。
请参见此处此处的示例。

1
什么概率?碰撞的概率吗?不,那将是1,也就是非常高。;-) - Konrad Rudolph
嗯,没错。肯定存在两个具有相同MD5哈希值的字符串。 - sharptooth
5
我知道这个问题被称为鸽巢原理问题。 - Daniel A. White
1
生日问题只涉及碰撞的可能性。要证明必须有一个,你需要鸽巢原理。 - jk.
@Alex Spencer:类似于这里描述的内容 https://dev59.com/W3RA5IYBdhLWcg3wsgFP - sharptooth

13

当然可以:MD5哈希具有有限长度,但是可以对无限数量的字符字符串进行MD5哈希。


4

是的,这是可能的。它被称为哈希碰撞

话虽如此,像MD5这样的算法是为了最小化碰撞的概率而设计的。

MD5的维基百科条目解释了一些MD5的漏洞,你应该注意到。


4

为了更加详细说明。从数学角度来看,哈希函数并不是单射的。

这意味着起始集合和结果集合之间不存在一对一(但是单向)的关系。

维基百科上的双射

编辑:完全单射的哈希函数是存在的:它被称为完美哈希


1
当输出大小小于输入大小时,不存在完美的哈希函数。 - Paŭlo Ebermann

4

我认为根据我们的需求仔细选择哈希算法是必要的,因为哈希冲突并不像我想象的那样稀有。最近我在我的项目中发现了一个非常简单的哈希冲突案例。我正在使用 xxhash 的 Python 封装进行哈希。链接:https://github.com/ewencp/pyhashxx

s1 = 'mdsAnalysisResult105588'
s2 = 'mdsAlertCompleteResult360224'
pyhashxx.hashxx(s1) # Out: 2535747266
pyhashxx.hashxx(s2) # Out: 2535747266

这在系统中引起了非常棘手的缓存问题,最终我发现这是哈希碰撞。


3

是的,这是可能发生的(尽管风险非常小)。否则,你会有一个相当有效的压缩方法!

编辑:正如Konrad Rudolph所说:将潜在无限的输入转换为有限的输出集(32个十六进制字符)将导致无数次碰撞。


3
正如其他人所说,两个不同的输入之间可能会发生冲突。但是,在您的用例中,我不认为这会成为问题。我非常怀疑您会遇到冲突——我曾在以前的工作中使用MD5为数以十万计的图像文件(JPG、位图、PNG、原始格式)生成指纹,并且没有出现过冲突。
但是,如果您正在尝试对某种数据进行指纹识别,也许可以使用两个哈希算法——一个输入结果与两个不同算法的相同输出的概率几乎为零。

1
实际上,如果攻击者能够使用一种哈希算法产生碰撞,他也可以利用这个来获取第二个算法的碰撞。最近在crypto.stackexchange上我的问题上讨论了这个问题。 - Paŭlo Ebermann

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