AES 是当今用得最多的对称加密算法,几乎每个后端系统都会用到。但“会用 API 调一下”和“用对”是两件事——选错模式、IV 重复、密钥处理不当,任何一个都能让加密形同虚设。这篇文章把关键点讲清楚。
AES(Advanced Encryption Standard,高级加密标准)是 2001 年美国 NIST 选定的对称加密标准,用来替代已经不够安全的 DES。它有三个特点:
| 项目 | 说明 |
|---|---|
| 类型 | 对称加密(加密和解密用同一把密钥) |
| 分组长度 | 固定 128 位(16 字节) |
| 密钥长度 | 128 / 192 / 256 位(16 / 24 / 32 字节) |
日常说的“AES-128”“AES-256”指的就是密钥长度。密钥越长越安全,但速度略慢。**AES-128 在可预见的未来都是安全的**,AES-256 主要是为了应对量子计算的远期威胁。
把明文切成 16 字节一块,每块独立加密。问题是:**相同的明文块会产生相同的密文块**。这意味着数据的结构会泄露。
最著名的例子是“ECB 企鹅”:一张图片用 ECB 加密后,企鹅的轮廓依然清晰可见,只是颜色变了。因为图片里大量重复的色块被加密成了相同的密文块。
每一块明文先和前一块的密文做异或,再加密。第一块则和一个叫 IV(初始化向量)的随机值异或。这样相同的明文块会得到不同的密文块。
代价是:**必须串行处理**(后一块依赖前一块),不能并行加速。
把 AES 当成一个伪随机数生成器来用,用计数器产生密钥流,再和明文异或。优点是:
缺点是**计数器值绝对不能重复**——一旦重复,两次的密钥流相同,异或一下就能还原明文。
这两个把分组密码当成流密码用,也不需要填充。CFB 适合流式传输,OFB 对传输错误更不敏感。实际项目中用得比 CBC/CTR 少,见到知道是什么就行。
| 模式 | 需要 IV | 需要填充 | 可并行 | 推荐度 |
|---|---|---|---|---|
| ECB | 不需要 | 需要 | 可 | ❌ 不要用 |
| CBC | 需要 | 需要 | 加密串行 | ✅ 常用 |
| CTR | 需要 | 不需要 | 可 | ✅ 推荐 |
| CFB | 需要 | 不需要 | 加密串行 | ⚠️ 少用 |
| OFB | 需要 | 不需要 | 不可 | ⚠️ 少用 |
IV(Initialization Vector,初始化向量)是让相同明文产生不同密文的关键。用错 IV,前面的努力全白费。
IV 可以和密文一起明文传输——攻击者拿到 IV 也没关系。但**它必须是密码学安全的随机数**,不能是时间戳、不能是固定值、不能是自增序号。
这是最致命的一条。同一个密钥 + 同一个 IV 加密两次,相同位置的数据就能被推导。CTR 模式下尤其严重。
常见做法是把 IV 拼在密文前面:
存储格式:IV(16字节) + 密文
解密时先取前 16 字节当 IV,剩下的当密文
IV 不是密钥,明文存储没问题。
AES 一次处理 16 字节,明文长度不是 16 的倍数就要补齐。标准做法是 PKCS#7:
缺 3 字节 → 补 03 03 03
缺 1 字节 → 补 01
正好 16 字节 → 补一整块 16 个 0x10
注意最后一行:**即使明文正好是 16 的倍数,也要补一整块**。这是为了让解密方能准确判断填充长度,否则无法区分“数据末尾本来就是 0x01”和“补了一个 0x01”。
这就是为什么 AES-CBC 加密后长度总是 16 的倍数,且至少比明文多 1 字节。