MD4 Collision
利用王小云的论文实现 MD4 碰撞攻击
前言
MD4 是麻省理工学院教授 Ronald Rivest 于 1990 年设计的一种信息摘要算法,能够将任意长度的字符串压缩成 128bits 的 hash 值。但是由于存在碰撞攻击,已经不再使用。本题是对 MD4 碰撞攻击的实现。
论文内容
下面是对论文的大致翻译,最好对着原论文看(LaTeX 啥的麻烦,word 复制粘贴勉强看看吧)
(以下提到的表均为王小云论文中的表)
MD4 算法描述
- 对于给定的字符串,首先对字符串进行填充,使得填充后的长度为 512bits 的整数倍
- 对每一块长度为 512bits 的字符串,MD4 利用压缩函数将它压缩成 128bits 的 hash 值。这个压缩函数一共有 3 轮,每一轮使用不同的非线性布尔函数,定义如下:
F(X, Y, Z) = (X∧Y)∨(¬X∧Z)
G(X, Y, Z) = (X∧Y)∨(X∧Z)∨(Y∧Z)
H(X, Y, Z) = X⊕Y⊕Z
注意,这里的 X,Y,Z 均为 32bits,且函数 F,G,H 均进行的是位运算
¬为按位取反,∧为与,∨为或,⊕为异或
压缩函数的每一轮的均使用 16 次对应的非线性布尔函数,在每一步中,链变量 a,b,c,d 的值都会更新。
φ0(a, b, c, d, mk, s) = ((a + F(b, c, d) + mk) mod 2^32) <<< s
φ1(a, b, c, d, mk, s) = ((a + G(b, c, d) + mk + 0x5a827999) mod 2^32) >>> s
φ2(a, b, c, d, mk, s) = ((a + H(b, c, d) + mk + 0x6ed9eba1) mod 2^32) <<< s
链变量的初始值为
(a, b, c, d) = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476) - MD4 压缩函数
记填充后的字符串为 M',M 为 M'中的一块,压缩函数定义如下:
记 M 的链变量为(aa, bb, cc, dd)。若 M 是第一块要进行 hash 的分块,则(aa, bb, cc, dd)为初始值(即 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476)。否则,它们来源于压缩前一块 M 时更新的链变量值。
执行以下 48 个步骤(三轮):
For j = 0, 1, 2 and i = 0, 1, 2, 3
a = φj(a, b, c, d, wj,4i, sj,4i)
d = φj(d, a, b, c, wj,4i+1, sj,4i+1)
c = φj(c, d, a, b, wj,4i+2, sj,4i+2)
b = φj(b, c, d, a, wj,4i+3, sj,4i+3)
在这里,wj,4i+k 是 M,<<< sj,4i+k 为循环左移 sj,4i+k 位
M'分组的使用顺序以及移位的数量已在表 5 给出
更新链变量的方法
aa = (a + aa) mod 2^32
bb = (b + bb) mod 2^32
cc = (c + cc) mod 2^32
dd = (d + dd) mod 2^32
若 M 是 M'的最后一块,则 H(M') = aa+bb+cc+dd 就是 M'的 hash 值
否则对下一个 512bits 块重复上述过程,(aa,bb,cc,dd)就作为下一块 M 的初始链变量值。
攻击前的准备
- 符号说明
1.1 M = (m0, m1, ..., m15) 与 M = (m0, m1, ..., m15)代表 2 组 512bits 的明文
1.2 ai, bi, ci, di 代表对 M 压缩时的第 (4i - 3) ,(4i - 2),(4i - 1) 和 4i 步的输出, 1 ≤ i ≤ 16.
1.3 a'i, b'i, c'i, d'i 代表对 M'压缩时的第 (4i - 3) ,(4i - 2),(4i - 1) 和 4i 步的输出, 1 ≤ i ≤ 16.
1.4 ∆mi = m i – mi代表m i与m i之间的单字差异
1.5 ai,j, bi,j, ci,j, di,j 代表 ai, bi, ci, di 的第 j 位 bit,第 1 位为 j=1
1.6 xi[j], xi[-j] (x 可以是 a, b, c, d) 代表改变 x(x 为单字)的第 j 位比特后的值, j 为 0 变为 1,-j 为 1 变为 0。
xi[±j1, ±j2, ..., ±jl]代表改变x的第j1, j2, ..., jn 位bit后的值, j为0变为1,-j为1变为0。
1.7 为了更好的描述过程,将使用整数模来表示位差异,比如
∆c2 = c2 - c2 = -2^18 + 2^21
即为
c'2 = c2[-19, 22]
碰撞攻击过程
攻击成功的概率在 2^(-2)- 2^(-6)之间,复杂度小于 2^8 次 MD4 计算。攻击过程分为 3 步:
找出 M 和 M' 产生碰撞的碰撞微分
推导出一组确保碰撞微分保持不变的充分条件
对于任意随机消息 m,对 m 做一些修改,使几乎所有的充分条件保持不变(弱明文)
MD4 的碰撞微分
我们选择如下碰撞微分:
∆M = M' - M = (∆m0, ∆m1, ......, ∆m15)
∆m1 = 2^31, ∆m2 = 2^31 - 2^28, ∆m12 = -2^16
∆mi = 0, 0 ≤ i ≤ 15, i != 1, 2, 12.
很明显,碰撞微分由两个内部碰撞,分别为步骤 2-25 和步骤 36-41 组成。
由第三节我们可以知道,只要 M 满足表 6 中的所有条件,则 M 和 M'构成一对碰撞。明文修改
依据表 6,我们知道(M, M')构成一对碰撞的概率是 2^(-122),远低于生日攻击的 2^(-64)
我们可以通过 2 种明文修改技术将碰撞概率提升至 2^(-16) ~ 2^(-2),方法如下:
2.1 单步修正
我们可以很轻易地修改 M 使其满足第 1 轮的条件保持不变。
经过单步修正后,(M, M')构成一对碰撞的概率提升至 2^(-25)
2.2 多步修正
虽然 2^(-25)的概率对于要找到一对碰撞已经够大了,但是在第二轮中使用多步修正
还可以进一步提高,而且这种方法在对 MD5, SHA-0, 特别是 SHA-1.的分析中特别重要
多步修正的原理是对某些明文的修改由第一轮中的部分碰撞组成,它保留第一轮中的所有条件,但只改变第二轮中的 1bit。方法如下:
(这里按照表 1 给出的方法进行修改即可)
实现过程
按照论文内容,我们要是不想理会繁琐的推导,直接实现就行
首先选定一个 M(随机或者指定),然后对于第一轮的所有条件,修改链变量的值,并更新对应的 M。然后在第二轮里,我只使用了能更大幅度提升碰撞概率的多步修正修改了 a5 与 d5 的值,单步修正没有使用。第二轮修正完成后,M 就已经修改成一个容易找到碰撞的明文。依据碰撞微分的公式,修改第 1,2,12 分组的相关 bit,我们就有大概率能找到 M 的碰撞 M'。论文最后还提到,修改 c5 及以后的链变量能更大程度提升概率(即表 6 后 7 行,与其相关联的是表 2),但是没有详细说,所以我也就没加在代码里了。
概括起来就是:
对于任意一个 m,修改使其满足表 6 所有条件后为 m1,此时 m1 称为弱明文,弱明文的意思就是,m1 的 1,2,12 分组修改后(记为 m2),会与 m1 形成一对碰撞。即 m1 与 m2 形成碰撞
代码
1 |
|
概率性碰撞,快的话,我跑过 1.7s 一个碰撞的,慢的话,有 10min 一个碰撞的
结果
1 |
|
M 均经过 hex
总结
- 英文文献,看着比较痛苦
- 大牛的论文言简意赅,理解论文花了很多时间
- 都说 MD4 不安全,有碰撞,别使用,亲身动手实践一遍才知道是什么情况。在搜论文的过程中发现有基于此论文进行对 MD4 有意义的碰撞攻击,实现 2 个有意义的明文 MD4 却一样,感觉这个更好玩,可惜没太看懂实现
来呀快活呀