SHA-256哈希算法中的消息扩展过程详解
我们先来明确一下SHA-256算法处理消息的整体框架,以便你理解“消息扩展”在其中扮演的角色。
背景简述:
SHA-256是一种密码哈希函数,输入任意长度的消息,输出256位(32字节)的哈希值。它的核心结构是迭代压缩的Merkle-Damgård结构。在处理时,算法首先对消息进行填充,然后将其分割成多个连续的512位消息块。每个消息块会驱动一个压缩函数进行运算,这个压缩函数会更新一个256位的内部状态(八个32位字,称为A, B, C, D, E, F, G, H),其核心运算需要64轮。消息扩展,就是为这64轮运算中的每一轮准备一个32位的扩展消息字(记为W₀, W₁, …, W₆₃)。
简单来说,消息扩展的任务是:将一个512位的输入消息块,扩展生成64个32位的扩展消息字(W₀到W₆₃),总长度为2048位。 这个过程增加了算法的复杂性和扩散性。
接下来,我们分步讲解这个消息扩展是如何进行的。
第一步:输入准备与初步分割
假设我们当前要处理的是经过填充和分割后得到的一个512位的消息块。
- 我们将这个512位的块看作一个由16个连续的32位字组成的数组,记为
M[0], M[1], …, M[15]。 - 这16个字是消息扩展的初始输入。注意,在SHA-256标准文档中,这16个字也通常被直接称作消息块的字。
第二步:扩展过程详解
扩展的目标是生成64个字(W₀到W₆₃)。生成规则分为两个阶段:
第一阶段:前16个字(W₀ 到 W₁₅)
- 这16个字直接来自输入消息块。即:
- W₀ = M[0]
- W₁ = M[1]
- …
- W₁₅ = M[15]
- 你可以理解为,算法先把原始消息块的16个字“抄”到扩展消息数组的前16个位置。
第二阶段:后48个字(W₁₆ 到 W₆₃)
- 这是消息扩展的核心,体现了非线性扩散。从第16个字(W₁₆)开始,每个字都由它前面已经确定的几个字通过特定的函数计算得出。
- 具体的生成公式如下(对于 16 ≤ t ≤ 63):
- Wₜ = σ₁(Wₜ₋₂) + Wₜ₋₇ + σ₀(Wₜ₋₁₅) + Wₜ₋₁₆
这个公式看起来很复杂,我们来逐一拆解:
-
Wₜ₋₁₆: 这是“很久以前”的消息字。在计算W₁₆时,它就是W₀。
-
σ₀(Wₜ₋₁₅): 这是对“较近的过去”的字Wₜ₋₁₅进行的一个小型函数变换,目的是引入非线性。σ₀函数的定义是:
- σ₀(x) = ROTR⁷(x) ⊕ ROTR¹⁸(x) ⊕ SHR³(x)
ROTRⁿ(x)表示将32位字x循环右移n位。SHRⁿ(x)表示将x逻辑右移(高位补零)n位。⊕表示按位异或运算。- 这个操作将x的比特位打乱、混合。
-
Wₜ₋₇: 这是“近期”的消息字。在计算W₁₆时,它就是W₉。
-
σ₁(Wₜ₋₂): 这是对“很近的过去”的字Wₜ₋₂进行的另一个小型函数变换。σ₁函数的定义是:
- σ₁(x) = ROTR¹⁷(x) ⊕ ROTR¹⁹(x) ⊕ SHR¹⁰(x)
- 操作同σ₀类似,但移动的位数不同,以产生不同的扩散效果。
-
+运算符: 注意,这里的“+”是模2³²加法。也就是说,将四个32位数相加,如果结果超过了2³²-1,就丢弃进位(即结果对2³²取模)。这确保了结果仍然是一个32位的字。
这个过程的可视化:
想象一个不断滑动和计算的过程。要计算Wₜ,你需要回顾前面已生成的W数组,取出特定位置的四个“配料”(Wₜ₋₁₆, Wₜ₋₁₅, Wₜ₋₇, Wₜ₋₂),对其中两个进行σ₀和σ₁变换,然后将这四个“配料”用模2³²加法混合在一起,就得到了新的Wₜ。
举例说明计算W₁₆:
W₁₆ = σ₁(W₁₄) + W₉ + σ₀(W₁) + W₀
其中:
- W₀, W₁, W₉, W₁₄ 都是已知的前16个字(来自原始消息块)。
- 分别计算σ₁(W₁₄)和σ₀(W₁)。
- 将这四个数(σ₁(W₁₄), W₉, σ₀(W₁), W₀)进行模2³²加法,结果就是W₁₆。
第三步:作用与安全目的
为什么SHA-256的设计者要设计如此复杂的扩展过程,而不是简单地把512位消息重复使用?主要有三个目的:
- 消除规律性: 原始消息可能存在模式(比如全零)。简单的重复会导致输入到压缩函数每一轮的数据高度相关,易于分析。扩展过程通过非线性函数(σ₀, σ₁)和远距离回溯(Wₜ₋₁₆, Wₜ₋₁₅等),将原始的16个字彻底打乱,生成了看似随机的64个字,破坏了任何潜在的规律。
- 实现比特扩散: σ₀和σ₁中的循环移位和异或操作,使得原始消息块中任何一个比特的改变,都会通过后续的迭代计算,迅速扩散到几乎所有的扩展消息字Wₜ中。这符合哈希函数的“雪崩效应”要求。
- 防止固定点攻击: 复杂的、与轮数相关的扩展关系,使得攻击者很难构造出一个特定的消息块,使其在经过多轮压缩后产生特定的中间状态,从而增强了抗碰撞和抗原像攻击的能力。
总结
SHA-256的消息扩展过程是一个精巧的确定性计算:
- 输入: 一个512位的消息块,分成16个32位字。
- 输出: 64个32位的扩展消息字(W₀ … W₆₃)。
- 规则:
- 前16个字:直接复制输入。
- 后48个字:由递推公式 Wₜ = σ₁(Wₜ₋₂) + Wₜ₋₇ + σ₀(Wₜ₋₁₅) + Wₜ₋₁₆ 生成。
- 核心函数:
- σ₀(x) = (x循环右移7) ⊕ (x循环右移18) ⊕ (x逻辑右移3)
- σ₁(x) = (x循环右移17) ⊕ (x循环右移19) ⊕ (x逻辑右移10)
- 目的: 将短输入充分混合扩散,生成无规律的轮输入,是SHA-256算法强度和抗密码分析的关键组成部分之一。
最终,这64个Wₜ会依次在压缩函数的64轮中,与轮常数Kₜ一起,参与对内部状态(A, B, …, H)的更新运算。