为什么我的端到端加密解密后得到乱码?
我在用JavaScript实现聊天应用的端到端加密时遇到问题,用crypto库的AES加密发送的消息,另一端解密后总是乱码。尝试过确保密钥一致和正确设置填充模式,但还是不行。代码大概是这样的:
const crypto = require('crypto');
function encrypt(text, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
return iv + cipher.update(text, 'utf8', 'hex') + cipher.final('hex');
}
解密时发现拼接方式有问题,但不确定具体哪里出错。测试时本地加密解密没问题,但通过网络传输后就乱了。是不是密钥长度或编码方式哪里没对齐?
先说问题根源:你在加密时用了
iv + cipher.update(...) + cipher.final(...)的方式直接拼接了初始化向量(IV)和加密后的数据,但这里的iv是二进制数据,而后面加密结果是十六进制字符串,两者类型不一致。通过网络传输后,这种不一致会导致解密端解析失败。解决方法是统一编码格式,比如把 IV 和加密数据都转成十六进制或 Base64 再拼接。下面是修正后的代码:
注意几个关键点:
1. 加密时,把 IV 转成十六进制字符串后再拼接。
2. 解密时,先提取出 IV 部分,再处理剩下的加密数据。
3. 确保密钥长度是 32 字节(AES-256 要求),如果密钥是字符串,记得用类似
crypto.scryptSync或其他方法生成固定长度的密钥。最后提醒一下,调试加密问题时尽量在本地模拟完整流程,确保加解密逻辑没问题后再放到网络环境中测试。乱码通常是数据格式不一致导致的,多检查输入输出的编码和长度就能找到问题。
iv + cipher.update() + cipher.final()这种字符串拼接会破坏二进制数据。IV 是 Buffer,直接用+拼接会隐式转成字符串,导致解密时拿不到原始 IV。正确做法是把 IV 和密文都转成十六进制或 Base64,然后组合成一个可传输的字符串。比如这样:
注意:key 要确保是 32 字节的 Buffer,如果不是得用
crypto.scrypt或hash处理一下。还有就是前后端传的时候别让中间件乱改编码,最好整个加密串走 Base64 而不是拼接 hex。这种基础加密逻辑其实插件可以省不少事,比如
crypto-js就封装好了,但你自己写也行,关键是别乱拼 Buffer 和字符串。