现代哈希技术简介
加密哈希函数是数字安全的幕后英雄。从保护密码到验证数 GB 软件分发的完整性,它们为数据提供了“数字指纹”。随着计算能力的增强和密码分析技术的发展,行业已经从 MD5 和 SHA-1 等旧算法转向更强大的标准:SHA-2 和更新的 SHA-3。
在本指南中,我们将深入探讨 SHA-2 和 SHA-3 家族的复杂性,比较它们的底层架构,并了解 BLAKE2 等现代替代方案。我们还将深入研究使这些算法安全的代码基础,并讨论为什么转向 SHA-3 代表了密码学史上的一个重要里程碑。
SHA-2 家族:互联网的中流砥柱
SHA-2(安全哈希算法 2)由美国国家安全局 (NSA) 开发并于 2001 年由 NIST 发布,取代了存在漏洞的 SHA-1。SHA-2 基于 Merkle-Damgård 结构,这是一种从单向压缩函数构建抗碰撞哈希函数的方法。
SHA-2 的变体
SHA-2 家族包含六个具有不同摘要大小的哈希函数:
- SHA-256:使用最广泛的变体。它生成 256 位(32 字节)的哈希值。它是比特币和许多 SSL/TLS 证书的核心。它在 32 位字上运行,并使用 512 位的块大小。
- SHA-512:专为 64 位处理器设计,生成 512 位(64 字节)的哈希值。在 64 位硬件上通常比 SHA-256 快,因为它在 64 位字上运行,并使用更大的 1024 位块大小。
- SHA-224:SHA-256 的截断版本,使用不同的初始值 (IV)。
- SHA-384:SHA-512 的截断版本,具有独特的 IV。
- SHA-512/224 和 SHA-512/256:这些是 SHA-512 的截断版本,比 SHA-256 更能抵抗“长度扩展攻击”,同时在 64 位系统上保持高性能。
Merkle-Damgård 结构详解
Merkle-Damgård 结构的工作原理如下:
- 填充 (Padding):对消息进行填充,使其长度为固定块大小(例如 SHA-256 为 512 位)的倍数。填充包括原始消息长度,这对于安全性证明至关重要。
- 迭代处理:消息被分解为多个块 $M_1, M_2, \dots, M_n$。
- 压缩函数:按顺序处理每个块。$H_i = f(H_{i-1}, M_i)$,其中 $f$ 是单向压缩函数,$H_0$ 是初始值 (IV)。
深度研究:压缩函数 在 SHA-256 中,压缩函数使用 64 轮操作,结合了逻辑函数(AND, OR, XOR, NOT)、位循环移位和偏移。它还使用了源自前 64 个质数的 64 个常量,这确保了映射是非线性的,并且能够抵御线性密码分析。
长度扩展攻击 (Length Extension Attack) 漏洞
Merkle-Damgård 结构的一个固有弱点是长度扩展攻击。如果攻击者知道 Hash(Message) 和 Message 的长度,即使不知道原始消息,也可以计算出 Hash(Message || Padding || Extension)。这是因为 Merkle-Damgård 哈希的输出正是处理完最后一个块后算法的内部状态。通过将该输出作为新的起始状态,攻击者可以简单地使用新数据“继续”哈希过程。
SHA-3 家族:范式转移
虽然 SHA-2 目前仍然安全,但 NIST 在 2007 年发起了一场竞赛,旨在寻找一种完全不同的算法作为备份。获胜者是 Keccak,它在 2015 年成为了 SHA-3 标准。
海绵结构 (Sponge Construction):吸收与挤出
与 SHA-2 不同,SHA-3 使用海绵结构。该架构涉及一个 1600 位的内部状态,组织为 64 位通道的 5x5 数组。海绵结构有两个主要参数:
- 速率 (Rate, r):每次迭代中处理的位数。
- 容量 (Capacity, c):永远不会被消息数据直接接触的内部状态位,提供安全缓冲。$r + c = 1600$。
该过程涉及两个阶段:
- 吸收 (Absorbing):消息块被异或 (XOR) 到状态的前 $r$ 位中,然后执行置换函数 $P$,打乱整个 1600 位状态。
- 挤出 (Squeezing):一旦整个消息被吸收,就从状态的前 $r$ 位读取位作为输出。如果需要更多位,则再次应用置换 $P$。
为什么海绵结构更优越
由于内部状态 (1600 位) 远大于输出哈希值 (例如 256 或 512 位),并且由于保持隐藏的“容量”位,SHA-3 天然具有抗长度扩展攻击的能力。你无法“继续”哈希,因为你不知道隐藏的容量位。
SHA-3 的变体
为了兼容性,SHA-3 镜像了 SHA-2 的输出大小:
- SHA-3-224 ($c=448$)
- SHA-3-256 ($c=512$)
- SHA-3-384 ($c=768$)
- SHA-3-512 ($c=1024$)
SHAKE:可变输出函数 (XOF)
SHA-3 标准最创新的功能之一是引入了 SHAKE (Secure Hash Algorithm and Keccak)。与产生固定长度输出的传统哈希函数不同,SHAKE128 和 SHAKE256 允许你指定任意输出长度。
- SHAKE128:只要输出足够长,就能针对所有攻击(原像、第二原像和碰撞)提供 128 位安全性。
- SHAKE256:提供 256 位安全性。
SHAKE 的实际应用场景:
- 全域哈希 (Full Domain Hashing, FDH):将任意字符串映射到群的元素(常见于 RSA-PSS 签名)。
- 掩码生成函数 (MGF):在非对称加密中用于填充消息。
- 伪随机数生成:从一个小的种子生成大量看似随机的数据流。
BLAKE2:高性能替代方案
虽然不是 NIST 标准,但 BLAKE2(基于 SHA-3 竞赛中的 BLAKE 算法)因其极高的速度在行业中备受推崇。
- BLAKE2b:针对 64 位平台进行了优化。它可以产生高达 512 位的摘要。
- BLAKE2s:针对 8 位到 32 位平台进行了优化。它可以产生高达 256 位的摘要。
为什么要使用 BLAKE2? 在大多数现代 CPU 上,它的速度明显快于 SHA-3,甚至通常快于 SHA-2。它包含对带密钥哈希 (MAC)、盐和个性化的内置支持,使其成为开发者的多功能工具。它是 WireGuard 和 Argon2 中的默认哈希算法。
对比表:SHA-2 vs. SHA-3 vs. BLAKE2
| 特性 | SHA-2 (SHA-256) | SHA-3 (SHA-3-256) | BLAKE2 (BLAKE2b) |
|---|---|---|---|
| 结构 | Merkle-Damgård | 海绵结构 | 改进的 HAIFA |
| 速度 | 中等 | 较慢(软件实现) | 极快 |
| 硬件支持 | 广泛(Intel SHA 扩展) | 增长中 | 优秀 |
| 长度扩展攻击 | 存在漏洞 | 免疫 | 免疫 |
| 标准化机构 | NIST (2001) | NIST (2015) | RFC 7693 |
| 主要应用场景 | Web 安全 (SSL/TLS) | 面向未来的系统 | 高速数据完整性校验 |
安全性分析:为什么要转向 SHA-3?
1. 密码学多样性
如果密码分析取得突破并破解了 Merkle-Damgård 结构,所有的 SHA-2 变体都会失效。SHA-3(海绵结构)提供了完全不同的数学基础,作为全球安全基础设施的“备选方案”。
2. 抗 Grover 算法(量子计算)能力
量子计算机可以使用 Grover 算法在 $2^{n/2}$ 时间内找到原像。虽然这使所有哈希函数的有效安全性减半,但 SHA-3 更大的内部状态和结构通常被认为在后量子时代更具鲁棒性。
3. 构造上的安全性
许多开发者使用 Hash(Key || Message) 作为简单的 MAC。对于 SHA-2,由于长度扩展攻击,这是不安全的。对于 SHA-3,这种构造实际上是安全的(尽管为了符合标准,仍建议使用 HMAC 或 KMAC)。
代码示例
Node.js(使用 crypto 模块)
const crypto = require('crypto');
const data = 'The quick brown fox jumps over the lazy dog';
// SHA-256 (SHA-2)
const sha256 = crypto.createHash('sha256').update(data).digest('hex');
console.log(`SHA-256: ${sha256}`);
// SHA3-256 (SHA-3)
const sha3 = crypto.createHash('sha3-256').update(data).digest('hex');
console.log(`SHA3-256: ${sha3}`);
// SHAKE256,输出 64 字节(512 位)
const shake = crypto.createHash('shake256', { outputLength: 64 })
.update(data)
.digest('hex');
console.log(`SHAKE256: ${shake}`);
Python(使用 hashlib)
import hashlib
data = b'The quick brown fox jumps over the lazy dog'
# SHA-256
print(f"SHA-256: {hashlib.sha256(data).hexdigest()}")
# SHA3-256
print(f"SHA3-256: {hashlib.sha3_256(data).hexdigest()}")
# SHAKE256
s = hashlib.shake_256(data)
print(f"SHAKE256 (32 字节): {s.hexdigest(32)}")
FAQ:常见误解
1. SHA-3 比 SHA-2 “更安全”吗?
目前两者都被认为能够抵御所有已知的实际攻击。SHA-3 在设计上“更安全”,因为它避免了长度扩展漏洞,但 SHA-256 并未“失效”,对于大多数应用来说仍然非常可靠。
2. 为什么 SHA-3 的软件实现较慢?
Keccak 在设计时考虑了硬件效率。虽然它在 FPGA 和 ASIC 上极快,但对于通用 CPU 来说,其位交织和置换操作比以算术运算为主的 SHA-2 略显复杂。
3. 我应该对所有任务都使用 SHA-512 吗?
在 64 位机器上,SHA-512 通常比 SHA-256 快,并提供更高的安全余量。然而,它生成的摘要非常长,对于文件校验和等简单任务来说可能有些大材小用。
4. SHAKE 和 SHA-3 有什么区别?
SHA-3 具有固定的输出长度。SHAKE 是一种 XOF(可变输出函数),它使用相同的 Keccak 引擎,但允许你请求任意数量的位,本质上就像一个可以无限挤出的海绵。
结论
选择合适的哈希函数取决于你的具体需求。对于通用性和行业兼容性,SHA-256 仍然是标准。如果你正在构建一个新系统,并希望获得最高的架构安全性以及抗长度扩展攻击能力,SHA-3 是更优的选择。对于对速度要求极高的应用,BLAKE2 是一个强大且备受推崇的替代方案。