前言

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位长度

步骤:

  1. 追加 bit 1
  2. 追加 k0,使总长度 ≡ 448 (mod 512)
  3. 追加 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 的安全性基于:

  1. 复杂的压缩函数:混合位运算、模加、非线性函数
  2. 足够的轮数:64 轮确保充分扩散
  3. 数学基础:基于素数推导的常数,消除后门可能
  4. 充分的输出长度:256 位抵抗生日攻击

参考资料