Web Crypto API AES加密后解密失败,密文看起来不对劲?
我用Web Crypto API写了个AES加密函数,但解密时总返回错误。明明密钥和参数都一致,加密后的密文看起来全是乱码,是不是哪里没处理对?
代码是这样写的:
async function encrypt(text) {
const encoder = new TextEncoder();
const key = await crypto.subtle.generateKey(
{ name: "AES-CBC", length: 256 },
true,
["encrypt", "decrypt"]
);
const iv = crypto.getRandomValues(new Uint8Array(16));
const encrypted = await crypto.subtle.encrypt(
{ name: "AES-CBC", iv },
key,
encoder.encode(text)
);
return btoa(String.fromCharCode.apply(null, new Uint8Array(encrypted)));
}
测试时发现解密函数能拿到密钥,但解密结果全是乱码。尝试过把加密后的ArrayBuffer转成Base64,会不会是编码方式的问题?或者初始化向量没传对?
btoa(String.fromCharCode.apply(null, new Uint8Array(encrypted)))上。String.fromCharCode对二进制数据处理会出问题,特别是当字节值超过 127 时会被错误解码,导致密文损坏。你加密出来的是 ArrayBuffer,得老老实实用正确的方式转 Base64。另外你还漏了个大坑:密钥和 IV 没保存!每次加密都生成新密钥和随机 IV,解密时怎么对得上?你得把用到的 IV 和 key(或导出的 key material)一起存下来或者传过去。
下面是改好的加密函数:
解密的时候记得把 IV 转回 Uint8Array,密钥用
importKey还原。不然还是解不出来。说白了就是两个点:别乱搞字符编码,Binary数据要原样转;加解密三要素——算法、密钥、IV 必须完全一致。你现在至少丢了两个。
另外,你的加密结果转Base64的方式没问题,但建议用更现代的方式处理ArrayBuffer。