← 返回加密工具箱

AES 加密完全指南:五种模式、IV 与填充的坑

加密工具箱 · 使用教程

AES 是当今用得最多的对称加密算法,几乎每个后端系统都会用到。但“会用 API 调一下”和“用对”是两件事——选错模式、IV 重复、密钥处理不当,任何一个都能让加密形同虚设。这篇文章把关键点讲清楚。

一、AES 是什么

AES(Advanced Encryption Standard,高级加密标准)是 2001 年美国 NIST 选定的对称加密标准,用来替代已经不够安全的 DES。它有三个特点:

项目说明
类型对称加密(加密和解密用同一把密钥)
分组长度固定 128 位(16 字节)
密钥长度128 / 192 / 256 位(16 / 24 / 32 字节)

日常说的“AES-128”“AES-256”指的就是密钥长度。密钥越长越安全,但速度略慢。**AES-128 在可预见的未来都是安全的**,AES-256 主要是为了应对量子计算的远期威胁。

AES 一次只能处理 16 字节。超过 16 字节的明文要靠“模式”来分段处理——这就是后面要讲的 ECB/CBC/CTR。

二、五种模式,ECB 千万别用在生产

ECB(电子密码本)——不要用

把明文切成 16 字节一块,每块独立加密。问题是:**相同的明文块会产生相同的密文块**。这意味着数据的结构会泄露。

最著名的例子是“ECB 企鹅”:一张图片用 ECB 加密后,企鹅的轮廓依然清晰可见,只是颜色变了。因为图片里大量重复的色块被加密成了相同的密文块。

ECB 只有在你加密的数据小于 16 字节、且每次内容都不同时才算勉强可用。现实中几乎没有这种场景。看到生产代码里用 ECB,就该改。

CBC(密码分组链接)——最常用

每一块明文先和前一块的密文做异或,再加密。第一块则和一个叫 IV(初始化向量)的随机值异或。这样相同的明文块会得到不同的密文块。

代价是:**必须串行处理**(后一块依赖前一块),不能并行加速。

CTR(计数器模式)——可并行、可变长

把 AES 当成一个伪随机数生成器来用,用计数器产生密钥流,再和明文异或。优点是:

缺点是**计数器值绝对不能重复**——一旦重复,两次的密钥流相同,异或一下就能还原明文。

CFB / OFB

这两个把分组密码当成流密码用,也不需要填充。CFB 适合流式传输,OFB 对传输错误更不敏感。实际项目中用得比 CBC/CTR 少,见到知道是什么就行。

模式需要 IV需要填充可并行推荐度
ECB不需要需要可❌ 不要用
CBC需要需要加密串行✅ 常用
CTR需要不需要可✅ 推荐
CFB需要不需要加密串行⚠️ 少用
OFB需要不需要不可⚠️ 少用

三、IV 的三个铁律

IV(Initialization Vector,初始化向量)是让相同明文产生不同密文的关键。用错 IV,前面的努力全白费。

1. IV 不用保密,但必须随机

IV 可以和密文一起明文传输——攻击者拿到 IV 也没关系。但**它必须是密码学安全的随机数**,不能是时间戳、不能是固定值、不能是自增序号。

2. 同一把密钥下,IV 绝对不能重复

这是最致命的一条。同一个密钥 + 同一个 IV 加密两次,相同位置的数据就能被推导。CTR 模式下尤其严重。

3. IV 要随密文一起存储

常见做法是把 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 字节。

五、怎么用本站工具

  1. 打开加密工具箱的 AES 标签页
  2. 选择模式(一般选 CBC)
  3. 填入密钥:16 字符 = AES-128,24 字符 = AES-192,32 字符 = AES-256
  4. CBC 等模式需要填 IV,长度必须是 16 字符
  5. 输入明文点「加密」,得到 Base64 格式的密文
  6. 解密时确保模式、密钥、IV 与加密时完全一致
加解密全程在浏览器本地完成,密钥和明文都不会发送到服务器。你可以断网验证这一点。

六、常见问题

解密报错或者乱码怎么办?
八成是这四个原因之一:模式不一致(加密用 CBC、解密用 ECB);密钥长度不对(AES 要求 16/24/32 字节);IV 不一致;密文被截断或编码转换出错。逐项对一遍基本能定位。
密钥可以直接用中文字符串吗?
技术上可以,但必须保证加解密双方用同一个字符集(统一 UTF-8)把字符串转成字节。如果一方用 UTF-8 另一方用 GBK,字节长度和内容都会不同,必然解不开。生产环境建议密钥用十六进制或 Base64 表示,避免字符集歧义。
为什么我的密文每次都不一样?
因为 IV 是随机的,这是正确行为。同样的明文、同样的密钥、不同的 IV,密文本来就该不同。如果你需要密文稳定(比如用于查询索引),那应该用哈希而不是加密。
AES 能加密密码存数据库吗?
不建议。密码应该用单向哈希 + 加盐(bcrypt、argon2、scrypt),而不是可逆加密。因为加密意味着你有能力还原出用户的原始密码,一旦密钥泄露,所有密码全部暴露。
AES-128 和 AES-256 该选哪个?
一般场景 AES-128 完全够用,性能更好。需要满足合规要求(比如某些行业规范明确要求 256 位)、或者对长期保密性有极高要求时选 256。对绝大多数业务系统,模式的正确性比密钥长度重要得多。
本站的密文为什么是 Base64 而不是十六进制?
两者都只是编码方式,信息量相同。Base64 更紧凑(长度约为原文的 1.33 倍),十六进制是 2 倍。如果你的对接方要求 hex,解码 Base64 再转 hex 即可。