为什么用AES加密后前端和后端的密文结果不一致?

上官怡轩 阅读 330

我在给表单数据做AES加密时遇到奇怪的问题。用前端库加密后的密文,后端用同样的密钥解密总报错。之前用jsencrypt试过RSA没问题,换成AES-256-CBC后就乱了。

前端代码是这样的:


const CryptoJS = require("crypto-js");
let ciphertext = CryptoJS.AES.encrypt('测试数据', 'secret-key-123', {
  mode: CryptoJS.mode.CBC,
  padding: CryptoJS.pad.Pkcs7
}).ciphertext.toString();

后端用Node.js的crypto模块:


const cipher = crypto.createCipheriv('aes-256-cbc', 'secret-key-123', iv);
let encrypted = cipher.update(data, 'utf8', 'hex') + cipher.final('hex');

明明都用了CBC模式,为什么密文完全不一样?是不是库的默认参数有差异?试过调整padding和编码方式都没用,求大神指条明路…

我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
欧阳建宇
这问题出在密钥和IV(初始化向量)的处理上。CryptoJS会自动生成一个随机的IV,而Node.js的crypto模块需要你手动指定IV。另外,CryptoJS的密钥需要是32字节(256位),你的'秘密-key-123'不够长,会被自动填充,导致前后端不一致。

直接用这个:

前端代码:
const CryptoJS = require("crypto-js");
const key = CryptoJS.enc.Utf8.parse('secret-key-123secret-key-123'); // 32 bytes key
const iv = CryptoJS.lib.WordArray.random(16); // 随机生成16字节的IV
let encrypted = CryptoJS.AES.encrypt('测试数据', key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
let ciphertext = encrypted.ciphertext.toString();
let ivHex = iv.toString(CryptoJS.enc.Hex); // 把IV也转成字符串传给后端


后端代码:
const crypto = require('crypto');
const key = Buffer.from('secret-key-123secret-key-123', 'utf8'); // 同样的32字节key
const iv = Buffer.from(ivFromFrontend, 'hex'); // 从前端拿到的IV字符串转Buffer
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
let decrypted = decipher.update(ciphertext, 'hex', 'utf8') + decipher.final('utf8');


注意要把IV也一起传递给后端,前后端用相同的IV和key才行。
点赞
2026-03-24 17:04
a'ゞ光远
问题出在两个地方:密钥和IV。前端CryptoJS会自动把字符串密钥转成32字节,而后端直接用了原始字符串;另外前端默认生成随机IV,你得手动指定。

改成这样:

前端代码:

const CryptoJS = require("crypto-js");
let key = CryptoJS.enc.Utf8.parse('secret-key-123'); // 转成32字节
let iv = CryptoJS.enc.Utf8.parse('1234567890123456'); // 固定IV
let ciphertext = CryptoJS.AES.encrypt('测试数据', key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).ciphertext.toString(CryptoJS.enc.Hex);


后端代码:

const crypto = require('crypto');
const key = Buffer.from('secret-key-123'); // 自动补齐到32字节
const iv = Buffer.from('1234567890123456');
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update('测试数据', 'utf8', 'hex') + cipher.final('hex');


记得两边都用固定IV,生产环境要把IV和密文一起传输,别忘了处理好编码问题。
点赞 8
2026-02-15 23:06