为什么Vue项目中混合加密发送的密文到后端解密失败?
最近在做一个需要混合加密的登录功能,用RSA加密对称密钥然后AES加密密码,但后端总说解密失败。
代码逻辑是这样的:先用后端给的公钥加密AES的密钥,再用这个密钥加密密码,然后一起发过去。但测试时后端说RSA解密密钥失败。
这是我的Vue组件代码片段:
import { JSEncrypt } from 'jsencrypt';
import { AES, enc } from 'crypto-js';
export default {
methods: {
async submit() {
const password = '123456';
const aesKey = Crypto.randomBytes(16).toString('hex'); // 这里生成的AES密钥
const encryptor = new JSEncrypt();
encryptor.setPublicKey('MII...');
// 这里先加密AES密钥
const encryptedKey = encryptor.encrypt(aesKey);
// 再加密密码
const encryptedPassword = AES.encrypt(password, aesKey).toString();
// 发送到后端
await axios.post('/login', { key: encryptedKey, password: encryptedPassword });
}
}
}
我检查过公钥格式没问题,也确认过Base64编码,但后端说RSA解密时出现illegal key错误。难道是密钥生成的方式不对吗?或者AES加密时的密钥格式有问题?
你用的是 Crypto.randomBytes(16).toString('hex'),这个生成出来的是 32 字节的 hex 字符串(每个字符是 4 位),但 AES 要求的密钥字节数必须是 16 字节(AES-128)、24 字节(AES-192)或 32 字节(AES-256)。
你这样生成出来的密钥长度是对的(如果是 32 字节就是 AES-256),但问题在于你传给 RSA 加密的这个字符串是 hex 字符串(只包含 0-9 和 a-f),而后端在用 RSA 解密时很可能期望的是原始字节流,不是 hex 字符串,这就导致解密失败。
你需要把 AES 密钥以 Buffer 形式生成,并且加密前要转成 Base64 或 Binary 字符串,而不是 Hex。
正确的做法应该是这样:
这样后端拿到的是 Base64 字符串,解密后就可以还原成原始的 AES 密钥 Buffer。
另外还有一个潜在问题:AES 加密时不能直接用字符串当密钥,crypto-js 内部会自动做处理,但为了保险起见建议改成这样:
这样保证你传给 AES 的密钥是 WordArray 格式,不是字符串。
先说重点:你用
Crypto.randomBytes(16).toString('hex')生成的AES密钥是个32字符的十六进制字符串,但RSA加密时需要的是原始字节数组(Buffer)。后端解密出来的结果格式跟你预期的不一样,自然就报错了。解决办法很简单,把AES密钥生成改成这样:
然后RSA加密时也要注意,
JSEncrypt默认会把输入当成字符串处理,所以你需要先把AES密钥转成Base64编码再加密:最后,AES加密密码时直接用这个Buffer格式的密钥就行,
AES-CryptoJS能自动处理。完整修改后的代码大概是这样的:
记得提醒后端,解密出来的AES密钥是Base64编码的,得转回Buffer才能用。这种前后端加密通信真的挺磨人的,多测试几次吧,缓存起来这些细节以后还能用。