← 返回博客首页

AES 加密模式选型:ECB、CBC、GCM 图解与实战

一个最常见的加密误区

「我用了 AES,所以安全」——这句话对问题的回答其实只进行了一半。AES 是分组加密算法,它只定义了单个固定长度数据块的加密变换;怎么把这段任意长度的明文切成块、怎么让块之间互相影响、怎么防止篡改,这些答案组成了工作模式(mode of operation)。选错模式,AES 的保护力会大打折扣。

本文用图解把最常用的三种模式讲清楚,并给出能直接落地的选型。

先认识分组

AES 一次处理 16 字节的块。明文太长就分成多个 16 字节块;最后一块不足 16 字节时做 PKCS7 填充

明文:  [12 字节区]                    →  需补齐 4 字节
实际:  [12 字节区][\x04\x04\x04\x04]  →  补到 16

填充满整块时也会额外补一整块(\x10×16),这样解密时永远能区分「真数据」和「已填充」。

ECB:块与块之间完全独立

明文块1 ──AES──▶ 密文块1
明文块2 ──AES──▶ 密文块2     (块之间不互相影响)
明文块3 ──AES──▶ 密文块3

相同的明文块 → 相同的密文块。这正是它的致命伤:加密后数据里的重复图案原样保留。默认不要用 ECB,它只适合加密单块固定长度且不可预测的数据。

CBC:把上一个块接到下一个块

      IV(随机)        密文块1         密文块2
        │               │               │
明文块1 ─┴─∈⊕────────► AES ──►┐  明文块2─┴─∈⊕─► AES ──►

CBC 让每个明文块先与前一个密文块异或再加密,形成一条链:

  • IV 使命:第一个块的前任由随机的初始化向量(IV)担任;
  • IV 规则:每次加密都要新鲜随机、绝不复用;把 IV 明文拼在密文首部;
  • 缺点:加密必须逐块串行(不能并行),若某块密文损坏,会波及后续一块的明文。

GCM:加密 + 认证一起搞定

GCM 用 CTR 计数器流模式加密(可并行、无需填充),同时在字段上算了认证标签:

nonce ──▶ 计数器(1) ─▶ 密钥流 ∈⊕ 明文块1 ─▶ 密文块1 ─┐
nonce ──▶ 计数器(2) ─▶ 密钥流 ∈⊕ 明文块2 ─▶ 密文块2 ─┼──▶ GMAC 认证标签
                                                      AAD ─┘
  • 输出 = nonce ‖ 密文 ‖ tag,tag 用于检测任何篡改
  • 96 位 nonce 随机且唯一,同 key 下绝不重用;
  • TLS 1.3 与主流库(OpenSSL、WebCrypto、Go、.NET)的默认首选。

三模式速查

特性 ECB CBC GCM
机密性
完整性/防篡改 ✘(额外 HMAC) ✔(自带认证标签)
填充 PKCS7 PKCS7 无(流式)
可并行加密
随机 IV/nonce 不需要 必须 必须
缺点 泄漏模式 串行、易错拼 HMAC 实现需经认证

常见坑清单

  1. ECB 用于多变长数据 → 形象、结构泄漏;改 GCM。
  2. CBC 复用/硬编码 IV → 共前缀泄漏;IV 每次随机并前置。
  3. 只用加密不做认证 → 密文可被翻转仍解出内容;GCM 自带认证。
  4. GCM nonce 重用 → 密钥流复用,灾难性;每 key 每 nonce 唯一。
  5. 密钥硬编码进代码 → 无论多强算法都会失效;密钥单独安全管理。

动手验证与自查

选一个加密工具库(浏览器可用 WebCrypto 的 AES-GCM),把同一段带重复图案的文本分别用 CBC 与 GCM 加密两次——你会看到 CBC 的 IV 不同导致两次密文不同,这正好体现了随机 IV 的作用。再把 GCM 密文的任一字节改掉,用 tag 验证会直接失败,这就是「认证加密」的价值。

记住主线即可:默认 AES-256-GCM,IV/nonce 随机唯一,密文连同 nonce 与 tag 一起保存


常见问题

ECB 模式为什么不安全?

ECB 对每个明文块独立加密,相同的明文块必然得到相同的密文块。于是图像、配置、数据库这类含重复模式的数据,加密后仍能在视觉或统计层面暴露结构(例如那张著名的『企鹅图』,加密后轮廓清晰可见)。它既不能隐藏数据模式,也谈不上块之间混淆,因此任何现代场景都不应默认使用,除非是加密长度固定、内容不可预测的单块数据(如加密单个密钥)。

CBC 模式的 IV 为什么要随机且唯一?

CBC 让每个明文块先与前一个密文块异或再加密,形成『链』。第一个块没有前任,只能靠 IV 担任——于是 IV 必须**每次加密都随机生成且不得复用**(通常 16 字节)。如果同一密钥下重用 IV,两份以共同前缀开头的明文会在密文开头泄漏它们的前缀相等性,配合得当可被用来还原明文前缀。正确做法是把公开的 IV 拼进密文首部一并存储或传输,而不是硬编码常量。

GCM 为什么被称为『认证加密』?

GCM 不只是加密:它在伽罗瓦域上用乘法计算一个 **GMAC 认证标签**,能检测密文和 AAD 是否被篡改。相比只保证机密的 CBC/ECB,GCM 同时提供机密性与完整性,且天然采用 CTR 计数器模式,无需填充、可并行、吞吐高,是 TLS 1.3 和主流库默认的 AES-GCM 首选。代价是同样的 IV/nonce 重用后果更严重,且某些实现(受硬件加速影响)存在时序侧信道风险,需要规范实现。

实际项目里到底该选哪种 AES 模式?

总结成一条主线:**默认选 AES-256-GCM**,它同时给机密性和完整性、无需管填充、性能好;库不支持时才考虑 AES-256-CBC + HMAC(需自己拼 encrypt-then-MAC,容易出错)。格式约定:CBC 务必随机 IV 并把它放在密文前面;GCM 务必随机 96 位 nonce,并把它与认证标签一起随密文保存。切勿使用 ECB 加密多变长数据;密钥管理(如何安全地存 key)与算法选型同等重要。

← 返回博客首页