MD5哈希算法的压缩函数设计
字数 2486 2025-12-06 14:01:14
MD5哈希算法的压缩函数设计
MD5(Message-Digest Algorithm 5)是一种广泛使用的密码哈希函数,可将任意长度的消息映射为128位(16字节)的哈希值。其核心是压缩函数,它将一个512位的消息分组和128位的中间状态(四个32位寄存器A、B、C、D的当前值)作为输入,并输出更新后的128位状态。下面我将循序渐进地讲解其设计细节。
1. 压缩函数的整体流程
压缩函数对每个512位消息分组执行64轮运算。每轮处理一个32位消息子块,并使用不同的常量、循环左移位数和逻辑函数。整体步骤如下:
- 输入:128位当前状态(四个32位寄存器A、B、C、D的当前值,每个32位)、512位消息分组。
- 处理:将消息分组划分为16个32位子块(M[0]到M[15]),并通过消息扩展生成64个32位子块(用于64轮运算)。然后,在64轮中,依次更新寄存器A、B、C、D的值。
- 输出:压缩函数结束时,将更新后的A、B、C、D与初始状态(输入前的值)模2^32相加,作为新的128位状态。
2. 消息扩展:从16个子块到64个子块
消息分组最初划分为16个32位子块M[0…15]。在64轮中,每轮使用一个扩展后的消息子块W[t](t从0到63),其定义如下:
- 对于前16轮(t=0到15):W[t] = M[t]。
- 对于后续48轮(t=16到63):W[t] = M[(1 + 5t) mod 16](这是简化的表达,实际中通过循环左移和异或运算生成,但标准MD5使用特定索引规则,见下一步)。
实际上,MD5使用固定的索引数组来选取M中的子块。对于第i轮(i从1到64),使用的消息子块索引k[i]是预先定义的,例如:- 第1-16轮:依次使用M[0…15]。
- 第17-32轮:依次使用M[(1 + 5(i-17)) mod 16]等(具体公式为k[i] = (1 + 5(i-1)) mod 16 for i=17..32,但标准实现使用一个固定表,见RFC 1321)。
为简化,你可以记住:MD5的64轮中,每轮使用一个M中的子块,但顺序是打乱的,以增加雪崩效应。
3. 四轮逻辑函数与常量
64轮分为四组,每组16轮,每组使用不同的非线性逻辑函数F、G、H、I(每个函数输入三个32位寄存器B、C、D,输出32位):
- 第1轮(1-16):F(B, C, D) = (B ∧ C) ∨ (¬B ∧ D) (条件函数:如果B则C,否则D)
- 第2轮(17-32):G(B, C, D) = (B ∧ D) ∨ (C ∧ ¬D)
- 第3轮(33-48):H(B, C, D) = B ⊕ C ⊕ D (按位异或)
- 第4轮(49-64):I(B, C, D) = C ⊕ (B ∨ ¬D) (多数函数变种)
此外,每轮使用一个32位常量T[i](i从1到64),定义为T[i] = floor(2^32 * |sin(i)|)的整数部分,其中sin是正弦函数,i以弧度为单位。这提供了伪随机常数,避免规律性。
4. 单轮运算的步骤详解
以第i轮为例(i从1到64),假设当前寄存器值为A、B、C、D(每轮前更新顺序会循环右移),单轮更新一个寄存器(总是A),其他寄存器移位。具体步骤:
- 选择逻辑函数:根据轮数确定使用F、G、H或I,计算结果记为f。
- 加法1:计算 (A + f) mod 2^32。
- 加法2:加上消息子块W[k](k为当前轮对应的M索引)模2^32。
- 加法3:加上常量T[i]模2^32。
- 循环左移:将结果循环左移s位(s是预定义的,每轮不同,范围在1到16之间)。
- 加法4:加上B模2^32,结果存入A。
- 寄存器循环右移:更新顺序为 (原始D, 新A, 原始B, 原始C),但注意实际实现中,每轮后寄存器会重新标记,使A、B、C、D循环右移一位(即原B成为新A,原C成为新B,原D成为新C,原A成为新D)。
更准确地说,标准MD5的伪代码如下(以第i轮为例):
a = B + ((A + f(B, C, D) + M[k] + T[i]) <<< s)
然后更新:A = D, B = a, C = B, D = C(但注意这是循环赋值,实际代码通常用临时变量)。
其中<<<表示循环左移,s是预定义的移位数。
5. 四组轮次的参数差异
四组轮次在逻辑函数、消息子块索引k、循环左移位数s上不同:
- 第1-16轮:使用F函数,k = i-1(即M[0]到M[15]),s为[7,12,17,22]的循环。
- 第17-32轮:使用G函数,k = (5i-4) mod 16(实际为固定表),s为[5,9,14,20]的循环。
- 第33-48轮:使用H函数,k = (3i+2) mod 16(固定表),s为[4,11,16,23]的循环。
- 第49-64轮:使用I函数,k = (7i-7) mod 16(固定表),s为[6,10,15,21]的循环。
这些参数确保了充分的扩散和混淆。
6. 最终输出
64轮后,得到更新的A、B、C、D。然后执行以下操作:
- A_new = (A_old + A) mod 2^32
- B_new = (B_old + B) mod 2^32
- C_new = (C_old + C) mod 2^32
- D_new = (D_old + D) mod 2^32
其中A_old、B_old、C_old、D_old是压缩函数开始前的初始状态(来自前一分组或初始向量IV)。结果A_new、B_new、C_new、D_new作为下一个分组的输入状态,或最后一个分组处理后拼接为128位哈希值。
总结:MD5压缩函数通过消息扩展、四轮非线性函数、模2^32加法和循环左移,将消息分组和当前状态混合,产生雪崩效应。尽管MD5因碰撞攻击已不适用于安全场景,但其设计体现了经典哈希压缩函数的思路。