首页/安全/加密与证书速查/AES-GCM 认证加密(AEAD)
加密算法基础95 条

AES-GCM 认证加密(AEAD)

基于 CTR 加密与 GHASH 认证的 AEAD 模式(NIST SP 800-38D),同时提供机密性与完整性,是 TLS 1.2/1.3 与 IPsec 中主流的 AES 工作模式。

加密与证书速查安全更新于 2026-10-13

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 -5

nonce 与标签选择

项目推荐值偏离后的后果
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 字节标记存储布局,便于换算法后仍能解开旧密文
nonce12 字节每次加密唯一,随机生成或结构化计数;重复即导致密钥流重叠
密文与明文等长CTR 类流式加密不改变长度,不要按块对齐去补零
标签16 字节紧随密文存储,缺失或截断会让完整性保护失效
AAD 摘要可选把租户、序号等上下文一同存入,解密时原样传入校验
在没有 AES 硬件加速的终端(部分移动设备、老 ARM 芯片、嵌入式网关)上,ChaCha20-Poly1305 通常比 AES-GCM 更快,且不易受实现层面的表查找侧信道影响。TLS 1.3 部署时把两者都列出,由服务端按客户端能力选择。

易错点

  • nonce 重用:同一密钥下重复 nonce 会泄漏认证子密钥并允许伪造消息,是最常见也最致命的 GCM 误用;解密失败后重试时尤其容易复用同一个 nonce
  • 把 openssl enc 当作 AEAD 工具:openssl enc 不支持 GCM/CCM 这类认证模式,命令会直接报错,需要改用库接口或支持 AEAD 的专用工具
  • 标签与密文分开存放、或只校验标签不校验 AAD:AAD 未纳入校验时,攻击者可以把密文搬到另一条消息或另一个租户上下文中
  • 认证标签截断过短(如 64 位)以节省带宽:伪造难度大幅下降,安全强度不再匹配底层算法
  • 单密钥承载全量数据并长期不轮换:随机 nonce 的碰撞概率随调用次数上升,密钥轮换是控制该风险的基本手段

数据来源与参考

  • NIST SP 800-38D(GCM 规范)
  • RFC 5288(TLS 中的 AES-GCM 套件)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌