AES-GCM 是什么
GCM(Galois/Counter Mode)是 NIST SP 800-38D 定义的认证加密模式:用 CTR 模式产生密钥流加密明文,同时用 GHASH 在有限域 GF(2^128) 上计算认证标签。一次调用既输出密文又输出标签,接收方校验失败就必须整体丢弃消息。它是 TLS 1.2/1.3、IPsec ESP 与大量存储加密的默认选择。
基本信息
| 标准 | NIST SP 800-38D |
|---|---|
| 结构 | CTR 加密 + GHASH 认证 |
| IV/nonce | 推荐 96 位(12 字节) |
| 认证标签 | 常用 128 位,可截断但越短越弱 |
| 关联数据 AAD | 参与认证但不加密,适合放协议头与序号 |
| 单条消息上限 | 约 2^36 字节 |
| 并行性 | 加密与认证均可并行,适合流水线实现 |
典型使用场景
- TLS 1.2 的 AES-GCM 套件与 TLS 1.3 的 TLS_AES_128/256_GCM_SHA256/384
- IPsec ESP 数据面加密与完整性保护
- 数据库字段级加密:把租户标识、行主键放进 AAD 防止密文搬移
- 对象存储与备份文件加密:密文与标签一并存储
- 自研接口通信:消息头放 AAD,正文加密,一次校验完成
- 需要随机访问的存储:GCM 可并行解密,优于 CBC 逐块链式依赖
Python 使用示例
Python 使用示例
# 使用 cryptography 库,不要自行拼装 CTR + GHASH
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
key = AESGCM.generate_key(bit_length=256) # 每租户或每会话一把密钥
nonce = os.urandom(12) # 96 位随机 nonce,随密文一起存储
aead = AESGCM(key)
ct = aead.encrypt(nonce, b'payload', b'v1|tenant-42') # 第三参数为 AAD
pt = aead.decrypt(nonce, ct, b'v1|tenant-42') # 认证失败抛 InvalidTag
assert pt == b'payload'性能与限制验证
性能与限制验证
# 测量本机 GCM 吞吐(openssl enc 不支持 AEAD 模式,不能用来加解密 GCM)
openssl speed -elapsed -evp aes-256-gcm
# 列出现有库支持的 GCM 套件,确认 TLS 侧配置项名称
openssl ciphers -v 'ECDHE+AESGCM' | head -5nonce 与标签选择
| 项目 | 推荐值 | 偏离后的后果 |
|---|---|---|
| nonce 长度 | 96 位 | 非 96 位会先经 GHASH 派生,实现差异多、更易出错 |
| nonce 生成 | 随机或结构化计数器 | 随机值在单密钥下调用次数过多会碰撞 |
| 标签长度 | 128 位 | 截断到 64 位会显著降低伪造难度 |
| AAD | 协议头、租户、序号 | AAD 不进 AAD 校验会导致密文可被跨上下文搬移 |
| 密钥隔离 | 按设备/会话/租户分密钥 | 单密钥承载全量流量,nonce 空间压力集中 |
同一密钥下 nonce 绝不能重复:重用会泄漏 GHASH 的认证子密钥,攻击者可伪造任意消息(俗称 forbidden attack)。随机 96 位 nonce 在单密钥下的调用次数建议控制在约 2^32 次以内;流量大的系统应按设备或会话拆密钥,或改用结构化计数器保证唯一。
GCM 不提供密钥承诺(key commitment):同一密钥下不同明文可能产生相同的标签前缀,多接收方场景要防「一对多」歧义时可考虑 AES-GCM-SIV 或先做哈希承诺。另外标签校验失败时不要回显部分解密结果,也不要区分「标签错」与「格式错」的错误码。
结构化 nonce 示例
结构化 nonce 示例
import os, struct
# 96 位 nonce = 32 位随机前缀 + 64 位递增计数器,单密钥内绝不重复
prefix = os.urandom(4) # 进程/设备启动时生成一次,重启换新值
counter = 0 # 持久化到磁盘或数据库,重启后从上次值继续
def next_nonce():
global counter
counter += 1
return prefix + struct.pack('>Q', counter) # 大端 8 字节,保证跨平台一致
# 同机多进程时用「前缀不同 + 计数器相同」也可以,避免共享计数器带来的争用密文存储字段建议
| 字段 | 长度 | 作用与错误做法 |
|---|---|---|
| 格式版本 | 1-2 字节 | 标记存储布局,便于换算法后仍能解开旧密文 |
| nonce | 12 字节 | 每次加密唯一,随机生成或结构化计数;重复即导致密钥流重叠 |
| 密文 | 与明文等长 | CTR 类流式加密不改变长度,不要按块对齐去补零 |
| 标签 | 16 字节 | 紧随密文存储,缺失或截断会让完整性保护失效 |
| AAD 摘要 | 可选 | 把租户、序号等上下文一同存入,解密时原样传入校验 |
在没有 AES 硬件加速的终端(部分移动设备、老 ARM 芯片、嵌入式网关)上,ChaCha20-Poly1305 通常比 AES-GCM 更快,且不易受实现层面的表查找侧信道影响。TLS 1.3 部署时把两者都列出,由服务端按客户端能力选择。