那次AES解不开的问题:密钥长度、IV和模式我后来都记住了

一次前端加解密失效的排查记录,从密钥字节数、IV复用到模式与填充的选择,顺带把常见的易错点记下来,避免以后再踩

优兔GOGO
2025年10月29日
经验分享
经验分享AES加密解密IV填充模式Base64

那次真的是被自己坑到。对方给了密文和一个看起来很“正常”的密钥,我在前端一解密,直接报错。第一反应是怀疑编码问题,结果折腾了半天,其实是三个基本点没对齐:密钥长度、IV 和加密模式。

一开始,我把明文做了 Base64 再加密,对方那边按字符串解密;回来对比时,我忘了确认两边的输入输出格式一致,导致“看起来一样”的字符串,其实不是同一组字节。后来用 Base64 工具把双方的输入输出都还原成可见形式,才发现我们一个用 hex,一个用 base64。

第二个问题更常见:密钥长度。AES-128/192/256 分别要求 16/24/32 字节。我拿到的密钥是人能看懂的口令,长度也不是 16 的整数倍。以前我没太在意,总觉得“库会帮我补齐”。这次换成严格校验的实现后,直接拒绝。于是我干脆固定用 16/24/32 字节的随机密钥,避免口令派生这段歧义(真要口令派生,就统一 PBKDF 参数)。

第三个是 IV。我当时图省事,把 IV 写死了,结果和对方的实现对不上(他们每次随机 IV 并放在密文前缀里)。更要命的是,即使我凑巧解开了,复用 IV 也有安全问题。现在我做法很简单:每次加密随机 IV,和密文一起存/传;解密时先把前缀切出来,流程就顺了。

最后一个细节是模式与填充。我们一开始用的是 CBC+Pkcs7,后来我这边想换 CTR,忘了告诉对方;还有一次把“无填充”配到了非流式模式,结果明文长度不对齐直接失败。现在我把默认写在文档里:模式 CTR 或 CBC,填充 Pkcs7(CTR 不需要填充)。

这件事后,我留了一个小清单给自己:

  1. 输入/输出统一(string/hex/base64、字符集 UTF-8);
  2. 密钥长度 16/24/32 字节,不要凑;
  3. IV 每次随机,跟密文一起传;
  4. 模式与填充在文档里白纸黑字;
  5. 对外前用一组固定样例互相跑通。

我再也没在这些地方栽过,省了很多时间。