加密模式详解:GCM、CBC、CTR 等模式对比

直接对数据进行块加密,会暴露数据的统计规律。所以我们需要加密模式——把块加密算法套在某个模式里,变成流式或分组的安全方案。我个人最早做对象存储加密时,对这些模式也是一头雾水,后来踩了几个坑才真正搞明白。今天咱们就把 CBC、CTR、GCM 这三个最常用的模式拆开看。

CBC 模式——密码分组链接

CBC 的原理很简单:每个明文块先和上一个密文块做 XOR,然后再用密钥加密。第一个块需要一个初始向量(IV)。

核心特点:
  • 加密必须顺序执行,无法并行
  • 解密可以并行(前提是有所有密文块)
  • 一个密文块损坏,会影响后续块解密(错误扩散)
我踩过的坑: 在项目中直接对文件分片用 CBC 加密,每个分片独立 IV。结果发现当网络丢包导致某个分片部分损坏时,后面几百 KB 的数据全部解密失败。后来我改用 CTR 模式解决了这个问题。所以如果你做的是网络传输中的对象加密,CBC 的错误扩散会让你很头疼。

CBC 的加密过程就是一条链——加密器必须等前一块处理完才能继续。这也是为什么它在 GPU 或多核环境里比较吃亏。不过解密可以并行,因为密文块本身就能拿到。

CTR 模式——计数器模式

CTR 把块密码变成了流密码。用一个每次加 1 的计数器配合密钥生成密钥流,然后直接和明文 XOR。解密也一样:生成相同的密钥流 XOR 密文。

为什么推荐 CTR:
  • 加密和解密都能完全并行
  • 支持随机访问——想解密第 N 块,直接生成第 N 块的密钥流就行
  • 没有错误扩散:一个密文块错了,只有那块数据受影响

我记得有个对象存储项目,用户要求能随机读取大文件的任意字节。CBC 做不到,因为你需要从头解密到目标位置。CTR 轻松搞定——你只需要知道文件开始处的计数器值,就可以直接跳到指定位置生成密钥流。这个特性在对象存储里太实用了。

但 CTR 有个致命要求:计数器值(IV+nonce)不能重复使用。一旦重复,两个密文块 XOR 一下就能消掉密钥流,明文直接暴露。

我曾经 见过一个团队,他们用时间戳做计数器,结果并发写入时时间戳冲突……幸好是测试环境。生产环境就
必须用原子递增的计数器或者 UUID 级 nonce。

GCM 模式——Galois/计数器模式

GCM 是 CTR 的升级版。它在 CTR 加密的基础上,增加了一个 GMAC 认证标签,用于校验数据完整性。简单说:GCM = CTR + 认证。

为什么 GCM 成为主流:
  • 加密和认证一步到位,不需要额外计算 HMAC
  • 支持 AAD(附加认证数据),比如加密文件时可以同时认证文件名、时间戳
  • 硬件加速友好(Intel AES-NI + PCLMULQDQ)

我个人习惯:只要系统支持 AES-NI,我优先选 GCM。比如对象存储的桶加密、客户端加密,GCM 几乎成了事实标准。AWS S3 的 SSE-C 就是用的 GCM。

GCM 的 nonce 长度推荐 96 位(12 字节),这也是性能最优的长度。如果 nonce 长度不是 96 位,内部会增加一次额外的 GHASH 计算,性能会下降 10%–30%。

注意: 不要用同一个 key + nonce 加密超过 2^32 个块(约 68 GB)。如果超过,GHASH 碰撞概率会上升到不可接受。对象存储里大文件动辄 TB 级,所以要么分片用不同 nonce,要么换用 XChaCha20-Poly1305 等模式。

三种模式对比

属性CBCCTRGCM
加密并行否是是
解密并行是是是
随机访问支持否是是
错误扩散2 块以上仅当前块仅当前块
认证完整性无无有 (GMAC)
常见场景磁盘加密、遗留系统流加密、随机读对象对象存储、网络传输
性能(AES-NI)中等高高
三种加密模式流程对比 CBC 加密 明文块1 密文块1 ← 链式依赖 明文块2 密文块2 CTR 加密 计数器1 密钥流1 密文块1 + 计数器2 密钥流2 GCM 加密 计数器 密文块 AAD GMAC 模式选择建议 • 需要随机读取对象 → 优先 CTR 或 GCM • 需要同时验证完整性且能接受 nonce 管理成本 → GCM • 遗留系统兼容 → CBC(但注意错误扩散和并行性差) • 超大文件(>68 GB)→ 分片并用不同 nonce,或考虑 XChaCha20-Poly1305
我的个人选型习惯: 对象存储场景里,我基本只用 GCM 或 CTR。如果有认证需求(大部分生产环境都有),无脑 GCM。如果对性能要求极致且用硬件加速受限,CTR + 单独 HMAC 也可以,但要多一次计算开销。CBC 我在新项目中基本不用了——它太容易被并行攻击和错误传播影响。