Whirlpool哈希算法的消息扩展过程详解
首先,Whirlpool是一种基于Miyaguchi-Preneel结构构建的迭代哈希函数,其核心是使用一个专为哈希设计的、类似AES的分组密码算法W。消息扩展过程是其关键组成部分,它决定了在每一轮压缩中使用的轮密钥。
1. 题目描述
Whirlpool的消息扩展过程指的是:如何从输入的512位消息分组(同时也是上一轮的中间哈希值)中,派生出一系列用于10轮压缩的轮密钥。这个过程不是简单地从主密钥推导,而是将当前的数据块本身视为“密钥”,通过一个确定性的、与W密码加密流程相似的算法,生成10个512位的轮密钥 \(K_0, K_1, ..., K_{10}\)。我们需要详细理解这个派生过程的每一步。
2. 预备知识:W分组密码
在深入消息扩展前,需要理解Whirlpool使用的W密码的框架:
- 分组大小:512位,视为一个8x8的字节矩阵(8行,8列,共64字节)。
- 轮函数:每轮操作包括四个步骤:
- AddRoundKey (AK):将状态矩阵与轮密钥矩阵进行异或。
- SubBytes (SB):使用一个8位的非线性S盒对每个字节进行替换。
- ShiftColumns (SC):将矩阵的每一列循环下移,第j列下移j个位置(j从0开始)。
- MixRows (MR):用GF(\(2^8\))上的一个MDS矩阵左乘矩阵的每一行。
- 总轮数为10。
3. 消息扩展过程详解
消息扩展过程的核心思想是:将当前要处理的消息分组 \(M_i\) 作为初始“密钥状态”,然后运行一个修改版的W密码加密流程,其每一轮的输出(在AddRoundKey之前)作为一个轮密钥。这个流程称为“密钥调度”或“消息扩展”。
我们逐步拆解:
步骤1:初始化
将当前的512位消息分组 \(M_i\) 拷贝到一个8x8的字节矩阵 \(K_0\) 中。\(K_0\) 就是第0轮的轮密钥。
公式:\(K_0 = M_i\)
步骤2:迭代生成后续轮密钥
对于第 \(r\) 轮(从1到10),轮密钥 \(K_r\) 由上一轮的轮密钥 \(K_{r-1}\) 经过一个函数 \(g\) 计算得来。
公式:\(K_r = g(K_{r-1}) \oplus C_r\) (注意:这里的异或是整个矩阵的异或,且 \(C_r\) 是轮常数)
这个函数 \(g\) 模仿了W密码的轮函数,但为了打破对称性并引入非线性,做了一些调整。我们拆解 \(g\) 函数:
-
SubBytes (SB):对 \(K_{r-1}\) 矩阵中的每一个字节,应用与W密码相同的S盒进行替换。
数学表示:\(SB(K_{r-1})\)
目的:引入非线性。 -
ShiftColumns (SC):对替换后的矩阵,应用与W密码相同的列移位操作(每列j循环下移j个位置)。
数学表示:\(SC(SB(K_{r-1}))\)
目的:实现字节在列内的扩散。 -
MixRows (MR):对移位后的矩阵,应用与W密码相同的行混合操作(用MDS矩阵乘每一行)。
数学表示:\(MR(SC(SB(K_{r-1})))\)
目的:实现字节在行内的强扩散,确保输出的每一位都依赖于输入的多个位。
至此,\(g(K_{r-1}) = MR(SC(SB(K_{r-1})))\)。
步骤3:与轮常数异或 (AddRoundConstant)
为了使每一轮的扩展都不同,并防止弱密钥,需要将 \(g(K_{r-1})\) 的结果与一个轮常数 \(C_r\) 进行异或,从而得到最终的 \(K_r\)。
公式:\(K_r = g(K_{r-1}) \oplus C_r\)
轮常数 \(C_r\) 如何生成?
轮常数 \(C_r\) 也是一个8x8的字节矩阵。它的定义非常巧妙:
- 矩阵中除了第一行(行索引0)外,所有其他字节都是0(0x00)。
- 第一行(一个8字节的行)的数值是:
S[8(r-1) + j],其中j是列索引(0到7),S是Whirlpool的S盒,S[x]表示查表输出。 - 更直观地说:对于第r轮,取出S盒的第
8(r-1)到8(r-1)+7这8个输出值,顺序放在 \(C_r\) 矩阵的第一行。
例如:
- \(C_1\) 的第一行是:S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7]。
- \(C_2\) 的第一行是:S[8], S[9], S[10], S[11], S[12], S[13], S[14], S[15]。
- 以此类推。
这个设计与AES的轮常数思想类似,但实现方式不同,它直接利用S盒的非线性输出作为常数,简单而有效。
4. 完整流程总结
- 输入:当前处理的消息分组 \(M_i\)(512位)。
- 初始化:\(K_0 = M_i\)。
- 迭代:对于
r = 1 to 10:
a. 对 \(K_{r-1}\) 进行 SubBytes 变换。
b. 对结果进行 ShiftColumns 变换。
c. 对结果进行 MixRows 变换,得到 \(g(K_{r-1})\)。
d. 计算轮常数 \(C_r\)(仅第一行为S盒值,其余为0)。
e. 计算 \(K_r = g(K_{r-1}) \oplus C_r\)。 - 输出:\(K_0, K_1, ..., K_{10}\) 共11个512位的轮密钥。
5. 关键点与安全考量
- 对称性的打破:虽然 \(g\) 函数是W密码轮函数的变体(少了初始的AddRoundKey),但引入了轮常数 \(C_r\)。这是至关重要的,它确保了即使输入消息分组 \(M_i\) 是全0或具有某种规律,生成的10个轮密钥也完全不同,从而防止了对称性或固定点攻击。
- 非线性与扩散:S盒提供了必要的非线性,防止线性分析。ShiftColumns和MixRows的组合提供了优秀的扩散特性,确保轮密钥之间的强依赖性,即初始密钥(消息分组)的微小变化会迅速扩散到所有轮密钥中。
- 效率:消息扩展过程在硬件和软件上都可以高效实现,因为它使用了与主加密轮函数(压缩函数)完全相同的底层组件(S盒,移位,行混合)。
通过这个过程,Whirlpool成功地将“数据”(消息分组)转化为了用于压缩自身的“密钥”,形成一个紧密耦合、高度非线性的压缩结构,这是其安全性的基石之一。