为什么不能重用 nonce
AES-GCM 把计数器模式加密与 GHASH 认证组合在一起,代价是同一个密钥下每对 (密钥, nonce) 只能用一次。一旦 nonce 重用,两条消息使用完全相同的密钥流,密文异或就得到明文异或,机密性直接受损;更严重的是 GHASH 的子密钥可以被恢复,攻击者随即能伪造任意消息使其通过认证。这是 GCM 在实际工程里最主要的风险点。
基本信息
| 后果一 | 两条密文异或即得明文异或,机密性受损 |
|---|---|
| 后果二 | GHASH 认证密钥可被恢复,完整性失效 |
| 随机 nonce 上限 | 96 位随机 nonce 的单密钥调用建议不超过 2^32 次 |
| 确定性构造 | 固定字段加计数器,计数器必须持久化 |
| 兜底手段 | 无法保证计数器唯一时,缩短密钥生命周期 |
| 审计重点 | 重启、并发与异常重试之后的 nonce 生成路径 |
非安全示例与修正思路
非安全示例与修正思路
# 反例:进程重启后 nonce 计数器归零但密钥未变,历史消息的 nonce 被复用
# 修正 1:密钥与计数器绑定,计数器持久化,重启后接着往上加
# 修正 2:每次重启换一把新密钥,比维护持久计数器更简单
# 修正 3:多设备或多会话按实体派生唯一子密钥,天然隔离计数器空间
# 校验手段:记录密钥版本与计数区间,出现回退立即告警nonce 构造方式对比
| 方式 | 唯一性保障 | 代价 |
|---|---|---|
| 96 位随机 nonce | 概率唯一,受 2^32 次调用上限约束 | 实现简单,大规模下需严控调用次数 |
| 固定字段加计数器 | 确定性唯一 | 计数器必须持久化且并发安全 |
| 每会话派生密钥 | 计数器空间被隔离 | 需要额外的密钥派生与存储 |
即使只泄漏两条使用相同 nonce 的消息,也足以破坏认证;含重启、并发与异常重试的系统要专门审计 nonce 生成路径。
上限 2^32 的来源:随机 nonce 的碰撞概率在调用次数接近 2^32 时已不可忽视,这是工程约束而非理论硬边界。到这个量级要么换密钥,要么改为确定性构造。
同一套代码里其它 AEAD 误用也要一并检查:认证失败时是否先跳过了明文输出、标签长度是否被截短,以及密钥与 nonce 是否被一起写进日志。