SHA-256哈希算法中的消息扩展过程详解
1. 题目描述
我们今天来详细讲解SHA-256哈希算法中的“消息扩展”过程。SHA-256是SHA-2家族中的重要成员,输出256位的哈希值。它的核心是将输入的原始消息,经过填充和分块后,输入到一个迭代压缩函数中进行处理。在压缩函数处理每个512位的消息块时,并不是直接使用这512位(即16个32位字),而是需要先将这16个字扩展生成64个32位字(W0 到 W63)。这个从16个字生成64个字的过程,就称为“消息扩展”。这个过程的设计对算法的安全性和抗碰撞性至关重要。我们的目标就是彻底理解这64个扩展字是如何一步一步计算出来的。
2. 前置知识:消息分块与基本约定
首先,我们需要明确消息扩展发生在哪个阶段:
- 输入消息经过填充,使其长度是512位的整数倍。
- 填充后的消息被切成N个512位的块,M^(1), M^(2), ..., M^(N)。
- 对每一个512位的消息块,独立执行一次消息扩展,生成该块对应的64个字W_t。
每个512位的块可以看作16个连续的32位“字”。我们记这16个初始字为:M0, M1, ..., M15。注意,在SHA-256的官方描述中,这16个初始字是整个512位块按大端序解释得到的32位整数。在扩展计算中,我们通常用W[0]到W[15]来代表这16个初始输入字,即:
W[0] = M0, W[1] = M1, ..., W[15] = M15。
3. 消息扩展过程的逐步推导
消息扩展的目标是计算出W[16]到W[63]这48个字。其计算不是线性的简单重复,而是利用了移位、异或、加法和特定的逻辑函数,引入了非线性和扩散。
步骤1:初始赋值(t = 0 到 15)
这是最简单的一步,直接使用输入消息块的前16个字。
W[t] = M[t] , 对于 t = 0, 1, ..., 15。
此时,W[0]到W[15]已经就绪。
步骤2:迭代扩展(t = 16 到 63)
对于接下来的每一个t(从16到63),W[t]的计算依赖于之前已经计算出来的某些W值。具体的计算公式如下:
W[t] = σ1(W[t-2]) + W[t-7] + σ0(W[t-15]) + W[t-16]
这个公式是核心,让我们逐一拆解:
-
组成部分1:σ1(W[t-2])
σ1(x)是一个函数,它对输入字x进行循环右移和移位操作,然后进行异或。- 具体定义:
σ1(x) = ROTR^17(x) XOR ROTR^19(x) XOR SHR^10(x) ROTR^n(x):将32位字x循环右移n位。循环右移是指移出的位从左边补回来。SHR^n(x):将32位字x逻辑右移n位。逻辑右移是指移出的位丢弃,左边补0。- 作用:
σ1函数对输入进行非线性变换和位扩散,确保相隔较近的字(t-2)的每一位都能影响结果W[t]的多个位。
-
组成部分2:W[t-7]
- 这是直接使用较早计算出的第t-7个字。它提供了一个线性的、距离适中的“记忆”或延迟。
-
组成部分3:σ0(W[t-15])
σ0(x)是另一个与σ1类似的函数,但参数不同。- 具体定义:
σ0(x) = ROTR^7(x) XOR ROTR^18(x) XOR SHR^3(x) - 作用:与
σ1类似,对更早的字(t-15)进行非线性扩散。
-
组成部分4:W[t-16]
- 这是本消息块最初始的16个字之一(当t=16..31时)或是由扩展早期生成的字(当t>31时)。它提供了消息块的“原始”输入。
-
“+” 操作:
- 这里的“+”是模 2^32 加法。即,将两个32位字当作无符号整数相加,如果结果超过2^32-1,则丢弃最高位的进位(相当于对2^32取模)。
- 模加法的引入增加了非线性,因为它不是比特级别的操作,进位会将低位的影响传播到高位。
4. 过程总结与实例演算
让我们用文字描述整个流程,并计算前几个扩展字来加深理解:
- 输入:一个512位的消息块,得到W[0]到W[15]。
- 循环计算:对于t从16到63:
a. 计算small_sigma_1 = σ1(W[t-2])
b. 计算small_sigma_0 = σ0(W[t-15])
c. 计算temp = small_sigma_1 + W[t-7](模2^32加法)
d. 计算temp = temp + small_sigma_0(模2^32加法)
e. 计算W[t] = temp + W[t-16](模2^32加法) - 输出:64个32位字 W[0], W[1], ..., W[63]。
微型演算示例(为了可读性,使用极短的4位字模拟思想,实际为32位):
假设我们已经计算出:
W[14] = 0101, W[15] = 1010 (这是初始块的最后两字)
现在要计算W[16]。W[16]依赖于W[0], W[1], ..., W[15]。
根据公式:W[16] = σ1(W[14]) + W[9] + σ0(W[0]) + W[0]
我们需要知道W[0], W[9]的值。这个例子只是为了展示依赖关系。在实际SHA-256中,每一个W[t]的计算都精确地遵循这个公式链。
5. 设计目标与安全性分析
为什么消息扩展要设计得如此复杂?
- 消除内部规律:如果只是简单地将512位消息重复使用,会引入大量的线性结构,使攻击者能轻易找到碰撞或原像。
σ0和σ1中的循环移位和异或破坏了比特之间的线性关系。 - 位扩散:原始消息块中的任何一个比特的改变,通过
σ0和σ1函数以及模加法,会迅速影响到后续几乎所有的扩展字W[t]。这符合“雪崩效应”。 - 防止固定点与对称性攻击:复杂的扩展使得攻击者难以构造具有特殊数学性质(如周期性、对称性)的消息块,从而抵抗针对压缩函数的某些密码学攻击。
- 为每一轮提供独特的输入:压缩函数有64轮,每一轮需要一个不同的W[t]。这个扩展过程确保了这64个输入字虽然源自同一个512位块,但彼此之间都具有复杂、非线性的关系,增加了分析的难度。
总结:SHA-256的消息扩展过程是一个将16个输入字(512位)非线性地扩展为64个字(2048位)的确定性算法。其核心是对于t=16到63,递归地使用公式 W[t] = σ1(W[t-2]) + W[t-7] + σ0(W[t-15]) + W[t-16] 进行计算,其中σ0和σ1是包含循环移位和逻辑移位的函数。这个过程为SHA-256压缩函数的每一轮提供了充分扩散、无线性规律的输入,是算法具备强碰撞抵抗能力的关键设计之一。