SHA-256 是 SHA-2 家族中使用最广泛的哈希算法,输出 256 位(32 字节)摘要。本文聚焦其工作原理,理解"为什么它安全"。
哈希函数的基本要求#
密码学哈希函数需满足:
| 属性 |
说明 |
| 单向性 |
给定 h,难以找到 m 使 H(m) = h |
| 抗碰撞 |
难以找到 m₁ ≠ m₂ 使 H(m₁) = H(m₂) |
| 雪崩效应 |
输入微小变化,输出剧烈变化 |
| 固定输出 |
任意长度输入,固定长度输出 |
SHA-256 处理流程#
1. 消息填充#
将消息填充至长度为 512 位的倍数:
1
|
原始消息 || 1 || 000...0 || 64位长度
|
步骤:
- 追加 bit
1
- 追加
k 个 0,使总长度 ≡ 448 (mod 512)
- 追加 64 位原始消息长度
示例:消息 “abc”(24 位)
1
2
|
原始: 01100001 01100010 01100011 (24 bits)
填充: 01100001 01100010 01100011 1 0...0 (423个0) || 000...011000 (64位长度=24)
|
2. 初始化哈希值#
SHA-256 使用 8 个 32 位初始值(取自素数平方根的小数部分前 32 位):
1
2
3
4
5
6
7
8
|
H₀ = 0x6a09e667
H₁ = 0xbb67ae85
H₂ = 0x3c6ef372
H₃ = 0xa54ff53a
H₄ = 0x510e527f
H₅ = 0x9b05688c
H₆ = 0x1f83d9ab
H₇ = 0x5be0cd19
|
3. 消息分块#
将填充后的消息分成 512 位(64 字节)的块,每块包含 16 个 32 位字 W₀…W₁₅。
4. 消息扩展#
将 16 个字扩展为 64 个字:
1
|
Wₜ = σ₁(Wₜ₋₂) + Wₜ₋₇ + σ₀(Wₜ₋₁₅) + Wₜ₋₁₆ (16 ≤ t ≤ 63)
|
其中:
1
2
|
σ₀(x) = ROTR⁷(x) ⊕ ROTR¹⁸(x) ⊕ SHR³(x)
σ₁(x) = ROTR¹⁷(x) ⊕ ROTR¹⁹(x) ⊕ SHR¹⁰(x)
|
5. 压缩函数#
对每个 512 位块执行 64 轮压缩:
1
2
3
4
5
6
7
8
9
10
11
|
for t = 0 to 63:
T₁ = h + Σ₁(e) + Ch(e,f,g) + Kₜ + Wₜ
T₂ = Σ₀(a) + Maj(a,b,c)
h = g
g = f
f = e
e = d + T₁
d = c
c = b
b = a
a = T₁ + T₂
|
核心函数:
1
2
3
4
|
Ch(x,y,z) = (x ∧ y) ⊕ (¬x ∧ z)
Maj(x,y,z) = (x ∧ y) ⊕ (x ∧ z) ⊕ (y ∧ z)
Σ₀(x) = ROTR²(x) ⊕ ROTR¹³(x) ⊕ ROTR²²(x)
Σ₁(x) = ROTR⁶(x) ⊕ ROTR¹¹(x) ⊕ ROTR²⁵(x)
|
6. 更新哈希值#
每块处理后:
1
2
3
4
|
H₀ = H₀ + a
H₁ = H₁ + b
...
H₇ = H₇ + h
|
7. 输出#
最终哈希值为 H₀ || H₁ || … || H₇(256 位)。
轮常数 K#
64 个 32 位常数,取自前 64 个素数立方根的小数部分:
1
|
K₀ = 0x428a2f98, K₁ = 0x71374491, K₂ = 0xb5c0fbcf, ...
|
这些常数消除算法中可能存在的"陷阱门"。
使用 OpenSSL 计算 SHA-256#
1
2
3
4
5
6
7
8
|
# 计算字符串哈希
echo -n "hello" | openssl dgst -sha256
# 计算文件哈希
openssl dgst -sha256 filename.txt
# 输出十六进制
echo -n "hello" | openssl dgst -sha256 -hex
|
实际输出:
1
2
3
4
5
|
$ echo -n "hello" | openssl dgst -sha256
SHA2-256(stdin)= 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b4824
$ echo -n "Hello" | openssl dgst -sha256
SHA2-256(stdin)= 185f8db32271fe25f561a5fc9a5c3696a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a
|
注意大小写差异导致的完全不同输出,体现雪崩效应。
安全性分析#
抗碰撞性#
SHA-256 输出 256 位,生日攻击需要约 2¹²⁸ 次计算,目前计算上不可行。
抗原像性#
已知哈希值,寻找原像需要约 2²⁵⁶ 次计算。
已知攻击#
截至 2026 年,没有对完整 SHA-256 的实用碰撞攻击。最佳理论攻击仅能减少少量轮次。
与其他哈希对比#
| 算法 |
输出长度 |
状态 |
| MD5 |
128 位 |
已破解,禁止使用 |
| SHA-1 |
160 位 |
已破解,禁止使用 |
| SHA-256 |
256 位 |
安全 |
| SHA-512 |
512 位 |
安全 |
| SHA-3-256 |
256 位 |
安全(不同结构) |
SHA-256 的安全性基于:
- 复杂的压缩函数:混合位运算、模加、非线性函数
- 足够的轮数:64 轮确保充分扩散
- 数学基础:基于素数推导的常数,消除后门可能
- 充分的输出长度:256 位抵抗生日攻击
参考资料#