极简工具箱

免费在线工具 · 本地计算 · 无需上传

AES 加密怎么选模式:GCM、CBC、ECB 的区别

用了 AES 就安全了吗?如果模式选的是 ECB,加密后的图片还能看出轮廓;如果 IV 写死,同样的明文永远得到同样的密文。算法只是第一步,模式才是关键。

广告位(百度联盟)

一、先理解三件事

  1. AES 是对称加密:加密解密用同一个密钥,速度快,适合加密大量数据。
  2. 密钥长度 128/192/256 位,256 位最稳,性能差异在现代 CPU 上很小(有 AES-NI 指令)。
  3. 分组长度固定 128 位,超过一块的数据要靠「模式」串起来——模式选错,安全性会大打折扣。

二、ECB:绝对不要用

ECB 把每 16 字节独立加密,相同明文块产生相同密文块。后果很直观:

任何场景都不该用 ECB。它的存在主要是教学和历史兼容。

三、CBC:经典但要小心 IV

CBC 让每个明文块先和前一个密文块异或,因此需要:

密文 = AES-CBC(key, IV, PKCS7(明文))

CBC 只提供机密性,不提供完整性。攻击者可以在不知道密钥的情况下篡改密文,导致解密结果被可控修改(比特翻转攻击)。所以 CBC 通常还要配一个 HMAC 做校验,而这正是最容易做错的地方。

四、GCM:现在应该默认选它

GCM 是认证加密(AEAD),一次运算同时给出密文和 16 字节认证标签(tag):

// Node.js 示例(AES-256-GCM)
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const enc = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();   // 必须和密文一起保存

除了 GCM,ChaCha20-Poly1305 在移动端(无 AES 硬件加速时)表现更好,也是 AEAD。

五、实际实现里最容易错的地方

错误后果
IV/nonce 写死或用时间戳相同明文得到相同密文,可被比对分析
nonce 重复(GCM)密钥流复用,可恢复明文
用 Math.random() 生成 IV随机性不足,可预测
忘记保存 tag/IV解密必然失败
密钥硬编码在前端等于没有加密
明文填充方式两边不一致解密出来尾部有多余字节或报错

密钥管理才是真正的难点:密钥不能进代码仓库、不能放前端、要能轮换。生产环境用 KMS 或环境变量注入,别在 JS 里写 const key = "1234567890123456"。

六、为什么两边总是解不开

跨语言对接 AES 失败,99% 是这四个参数没对齐:

  1. 算法全名:AES/CBC/PKCS5Padding(Java)对应 Node 的 aes-128-cbc + 自动 padding。
  2. 密钥怎么来:是原始 16 字节,还是把字符串做 MD5/SHA256 得到 32 字节?
  3. IV 从哪来:是密文前 16 字节,还是单独字段?编码是 hex 还是 Base64?
  4. 输出编码:Base64 还是十六进制,带不带换行。

调不通时,用同一组固定的 key/IV/明文,两边各算一次,把中间结果(十六进制)逐字节比对,比猜快得多。

七、什么时候不该用 AES

想验证某个模式的实际输出,可以用 AES 加解密工具 在本地试;密钥和内容都不上传,适合对照联调。需要把密文放进 JSON 或 URL 时,用 Base64 编解码。

小结

ECB 禁用;CBC 要随机 IV + 填充 + 额外完整性校验;GCM 是现在的默认选择,但 nonce 绝不能重复。跨语言解不开时,先对齐算法名、密钥派生、IV 位置和输出编码这四项。

本文相关工具(本地计算,无需上传)

更多使用教程