RIPEMD-160 哈希算法的轮函数设计
字数 3438 2025-12-07 08:59:53
RIPEMD-160 哈希算法的轮函数设计
题目描述:
RIPEMD-160是一种经典的密码学哈希算法,输出长度为160位。其核心是一个基于Merkle-Damgård结构的压缩函数,而压缩函数又由两个并行的、结构相似但使用不同常量的“线路”组成,每条线路包含5轮处理,每轮16步。请详细解释RIPEMD-160压缩函数中轮函数的设计,包括其整体结构、每条线路的轮函数逻辑、使用的非线性函数、消息字顺序、常数以及循环左移位数,并说明这种双线路设计的意图。
解题过程循序渐进讲解:
-
第一步:定位RIPEMD-160轮函数的上下文
- RIPEMD-160算法首先对输入消息进行填充,使其长度满足模512位等于448,并附加一个64位的消息长度表示,形成总长度为512倍数的分组。
- 算法内部维护一个160位(5个32位字)的链值(初始值IV或上一分组的输出)。
- 对于每个512位的消息分组,将其作为输入,与当前的160位链值一起,送入压缩函数进行处理,产生一个新的160位链值。
- 轮函数是压缩函数的核心计算单元。理解轮函数的设计,必须先明确其在压缩函数中的位置。
-
第二步:理解压缩函数的双线路并行结构
- RIPEMD-160的压缩函数最显著的特点是双并行处理线路,通常称为左线路和右线路。
- 初始的160位链值被划分为5个32位寄存器:(A, B, C, D, E) 用于左线路,(A', B', C', D', E') 用于右线路,且初始化时 A=A', B=B', C=C', D=D', E=E'。
- 每条线路独立处理相同的512位消息分组,但处理顺序、使用的布尔函数和常数不同。
- 每条线路包含5轮运算,每轮包含16步运算,因此每条线路总共进行80步运算。
- 每一步运算都会更新其线路的5个寄存器中的一个。
- 在所有80步运算结束后,两条线路的输出会进行交叉相加,产生最终的压缩函数输出。
-
第三步:剖析单条线路的轮函数逻辑(以左线路的一步为例)
- 我们以左线路的第
j步(j 从0到79)操作为例。每一步的运算遵循以下模式:
A := (A + f_j(B, C, D) + X[ρ(j)] + K_j) <<< s_j + E
B := B <<< 10
(A, B, C, D, E) := (E, A, B, C, D) - 变量解释:
A, B, C, D, E:当前线路的5个32位寄存器状态。f_j(B, C, D):一个依赖于轮数j的非线性函数(在第四步详述)。X[ρ(j)]:从当前512位消息分组中提取的一个32位“消息字”。ρ(j)是一个置换函数,决定了在第j步使用原消息分组16个32位字中的哪一个。左线路和右线路的置换序列ρ_L(j)和ρ_R(j)完全不同,这是实现两条线路差异性的关键。K_j:一个32位的加法常量,每16步(即每轮)改变一次。左线路和右线路使用不同的常量集。<<< s_j:循环左移s_j位。移位数s_j也是预先定义的,每16步一个模式,左右线路的移位数模式也不同。+:模 2^32 加法。
- 寄存器更新流程:上面的赋值和轮换意味着每一步中,
A寄存器获得一个新值(基于非线性函数、消息字、常数和移位的结果,加上旧的E),然后B被循环左移10位,最后5个寄存器整体右循环轮换一位(E移到D的位置,D移到C,...,新的A移到B的位置,但注意旧的B在移位后移到了A的位置?不对,根据上面的赋值,应该是(E, 新A, 旧B, 旧C, 旧D)变成了新的(A, B, C, D, E))。更准确地说,赋值后,寄存器组变为(新A, 旧B, 旧C, 旧D, 旧E),然后执行B := B <<< 10得到(新A, 旧B<<<10, 旧C, 旧D, 旧E),最后整体右循环轮换得到(旧E, 新A, 旧B<<<10, 旧C, 旧D)。这个过程确保了每个寄存器在每个位置(角色B, C, D)上都参与过非线性函数的计算。
- 我们以左线路的第
-
第四步:详解轮函数中的非线性函数 f_j
- 非线性函数
f每16步(一轮)改变一次,共5个不同的函数,对应5轮运算。对于左线路和右线路,这些函数的定义是相同的,但在不同轮次使用。 - 定义如下(其中
∧表示按位与,∨表示按位或,¬表示按位非,⊕表示按位异或):- 第1轮 (j = 0..15):
f_j(B, C, D) = B ⊕ C ⊕ D(异或) - 第2轮 (j = 16..31):
f_j(B, C, D) = (B ∧ C) ∨ (¬B ∧ D)(类似于MD4/5的IF函数) - 第3轮 (j = 32..47):
f_j(B, C, D) = (B ∨ ¬C) ⊕ D(一个较复杂的函数) - 第4轮 (j = 48..63):
f_j(B, C, D) = (B ∧ D) ∨ (C ∧ ¬D)(类似于MD4/5的MAJ函数的变体) - 第5轮 (j = 64..79):
f_j(B, C, D) = B ⊕ (C ∨ ¬D)(另一个复杂函数)
- 第1轮 (j = 0..15):
- 这些函数提供了良好的非线性性和比特扩散特性。
- 非线性函数
-
第五步:了解消息字顺序、常数和循环左移位数
- 消息字顺序
ρ(j):这是左右线路差异的主要来源之一。左线路使用的顺序ρ_L(j)和右线路使用的顺序ρ_R(j)是两个精心设计的、几乎互补的排列,确保了在80步中,原消息的16个字以不同的、近乎均匀的次序被使用。具体排列表是固定的,例如左线路第一轮可能按顺序使用X[0]到X[15],而右线路第一轮则使用一个完全不同的顺序。 - 常数
K_j:同样是每轮不同,且左右线路不同。它们是基于正弦函数或类似方法导出的十六进制常量,用于消除输入中的规律性。例如,左线路的常数可能是(十六进制)0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E,分别用于第1到第5轮。右线路则使用另一组常数,如0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000。 - 循环左移位数
s_j:每16步(一轮)有一个固定的移位数模式(例如,第一轮可能是[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8]这样的序列),左右线路的模式也不同。这些位移增加了算法的扩散性。
- 消息字顺序
-
第六步:压缩函数的最终合并
- 在左右线路各自完成80步运算后,得到两组最终的寄存器值:(A, B, C, D, E) 和 (A', B', C', D', E')。
- 压缩函数的输出(即对该消息分组的处理结果)通过以下交叉相加计算:
A_out = B + C'
B_out = C + D'
C_out = D + E'
D_out = E + A'
E_out = A + B' - 注意:这里的
+是模2^32加法,B, C, D, E, A是左线路最终状态,C', D', E', A', B'是右线路最终状态。这个交叉相加是RIPEMD-160特有的设计。
-
第七步:总结双线路设计的意图
- RIPEMD-160的前身RIPEMD-128是单线路设计,后来发现其抗碰撞强度不足。
- 双线路并行设计的主要目的是极大地增强算法抵抗已知密码分析攻击(特别是差分碰撞攻击)的能力。
- 两条线路使用不同的消息字顺序、不同的常数和不同的移位模式,但起始状态相同且处理相同的消息。这意味着,要找到一个消息对,使其在两条独立的、高度非线性的处理路径上都产生特定的差分碰撞,其难度远远大于只针对一条路径。这相当于设置了两道需要同时突破的屏障。
- 最终输出时的交叉相加进一步混合了两条线路的中间状态,使得从最终输出倒推出单条线路的内部状态或构造碰撞变得更加困难。
- 这种设计理念有效地提升了哈希函数的安全性,使得RIPEMD-160至今仍被认为是安全的(尽管输出长度160位在当前计算能力下已不推荐用于新的敏感系统,但其设计结构依然具有学习和借鉴价值)。