原文地址: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亿次的结果,基本上是符合统计预测的。
上帝是不仍骰子的……大家不要×××……