原文地址:http://www.blogwind.com/Wuvist/comment.aspx?article_id=3138

唉……不知道怎么评价Huge Anderson每个星期给的challenge……每次都觉得很有挑战性,然后花上几十个小时在上面……

well……For a cup of coffee……

Huge这个星期给的挑战是寻找MD5 hash的部分碰撞……

确切的说,要我们找出md5 hash与“d024eac470132c7116d8ce8aa8409b8e”类似的文件

所谓类似,是说md5 hash出来的结果跟上面的有越多的连续相同的字符越好……位置也要一样……比方说:
d024eac470132c7116d8ce8aa8409b8e
9f038cc6a7ec9baad98c9dfc1aa6e3b8 便是有一个相同的……
9f038ac6a7ec9baad98c9dfc1aa6e3b8
便是有两个相同的……

企图碰运气是不实际的……只能写程序生成数以万计的文件计算md5 hash然后与“d024eac470132c7116d8ce8aa8409b8e”比较。

我的C++都几乎忘光了……实际上,我也从来没有用心去学C++。

只好使用VB.Net,虽然,我认为VB.Net程序的运行速度会比C++低。

然后,我真的很想去撞墙……

一直以来,我居然都把.Net framework提供的md5类库用错了……

System.Security.Cryptography.MD5CryptoServiceProvider生成的md5 hash是32 bytes的!!!

我居然一直以为是16bytes……并且使用在了博客风等系统上……唉……进行数据转换的时候,实在是有太多问题了……

应该使用下面的函数将返回的md5 hash字节数组转换为String:
 

Function ToHexString(ByVal bytes() As Byte) As String
Dim str As New StringBuilder
Dim i As Integer
For i = 0 To bytes.Length - 1
str.Append(Hex(bytes(i)))
Next i

 

Return str.ToString
End Function

这个bytes() to String的转换函数是从MSDN给的范例修改得来的。原程序是直接使用String,我将其修改成为StringBuilder以提高速度。

但是,很奇怪,有的时候并不能获得32位的十六进制数,有时是30位,有时是28位,实在想不明白是哪里出错了……要错,恐怕也只能是.Net的问题了……

插入一下……我还是不懂得如何从HexString转换到bytes()……否则,我的程序应该可以快很多……该死的类型转换……

我一开始,写程序自动随机生成128 bytes的文件,然后计算md5 checksum,并跟“d024eac470132c7116d8ce8aa8409b8e”做比较。

生成了一亿个文件,找到了7位连续相同的碰撞。

然后,随机生成十亿个256 bytes的文件……足足算了12个小时……找出来9位连续相同的碰撞……

这个结果证明了两件事情:
第一:我的运气很好--至于为什么说很好,下面有解释。
第二:我的电脑现在很稳定了,可以连续全符合工作12小时而不出任何问题。

9位连续相同的碰撞是所有学生作出来的结果中最好的……Finally, I win the cup of coffee.

md5的hash只是32 bytes而已,也就是说16^32种变化。

所以,无论是生成32 bytes还是64 bytes乃至256 bytes的随机文件,产生碰撞的可能性应该一样。但是,生成256 bytes的文件明显要比32 bytes的慢8倍左右。

试验证明也是如此,没有功夫再去等10亿个文件的统计,我只是重新做了一千万个文件的计算,分别是16 bytes, 32 bytes, 64 bytes,结果如下:

碰撞位数 碰撞次数 平均值 首次碰撞位置
4 1540 6493.506494 1147
5 96 104166.6667 12077
6 9 1111111.111 41748
4 1554 6435.006435 3574
5 103 97087.37864 359164
6 5 2500000.000 3096880
4 1597 6263.701847 2470
5 87 114942.52873 75989
6 6 1666666.6666 633064

看不出什么显著变化……

基本上,每找出多一位的碰撞,需要多检查16倍的文件……这个结果也是很合乎理解的……是十六进制的……

因为,有很多4位数的碰撞……每6400个文件便能找到一个四位连续碰撞这个数据很可信……乘16等于102400,跟做出来的5位碰撞也很相似……6位碰撞也是如此……照此推论……找出9位连续碰撞需要6710886400个文件……

(10位连续碰撞则是1073 7418 2400)

但是,我只是试了10亿个文件……所以,我的运气很好!!!其实也不见得很好……大家不妨注意一下第一次碰撞出现的位置……第一次出现的位置一般都是要比平均数低很多的……

或者,我一开始就应该生成16 bytes的文件……12小时大概就可以处理160亿个文件……那么,如果我的运气还是“很好”的话,便可能找到10位的连续碰撞了……

嗯嗯嗯……

其实,我说了这么多……

只是想说明一件事情:不要靠运气,你必须相信统计。

如果我运气真的真的很好的话……我是有可能试一个文件便找到完全的碰撞……但是,我试了10亿次……还是没有找到……

而我试了10亿次的结果,基本上是符合统计预测的。

上帝是不仍骰子的……大家不要赌博……