SubtleCrypto中ArrayBuffer密钥转字符串乱码问题咨询
解决ArrayBuffer密钥转字符串乱码的问题
你遇到的乱码问题很常见——因为密钥的ArrayBuffer是二进制原始数据,里面的字节很多都不属于可打印的ASCII/UTF-8字符范围,直接用String.fromCharCode转换会把无效的字节序列当成字符解析,就出现了类似“Sask锟斤拷锟矫兟�脙漏”的乱码(这些是编码错误导致的占位符)。
正确的转换方式:用Base64编码
Base64是专门用来将二进制数据转换为可打印ASCII字符串的编码方式,它能无损还原原始二进制,完全适合密钥这类二进制数据的字符串化需求。
1. 封装转换工具函数
先写两个通用函数,分别处理ArrayBuffer转Base64,以及Base64转回ArrayBuffer:
// ArrayBuffer 转 Base64字符串 function arrayBufferToBase64(buffer) { const uint8Array = new Uint8Array(buffer); // 先把每个字节转成对应字符,再用btoa编码 return btoa(String.fromCharCode(...uint8Array)); } // Base64字符串 转 ArrayBuffer function base64ToArrayBuffer(base64) { const binaryStr = atob(base64); const uint8Array = new Uint8Array(binaryStr.length); for (let i = 0; i < binaryStr.length; i++) { uint8Array[i] = binaryStr.charCodeAt(i); } return uint8Array.buffer; }
2. 修改你的加解密函数
现在可以在encrypt和decrypt里正确转换密钥了:
encrypt: function(key, data, iv) { // 把ArrayBuffer密钥转成Base64字符串 const base64Key = arrayBufferToBase64(key); console.log('Base64格式密钥:', base64Key); return crypto.subtle.importKey('raw', key, {name: 'AES-CBC'}, true, ['encrypt']) .then(function(importedKey) { return crypto.subtle.encrypt({name: 'AES-CBC', iv: new Uint8Array(iv)}, importedKey, data); }); }, decrypt: function(key, data, iv) { // 如果传入的是Base64密钥,先转回ArrayBuffer;如果还是ArrayBuffer则直接用 const keyBuffer = typeof key === 'string' ? base64ToArrayBuffer(key) : key; // 可选:如果需要打印密钥,转成Base64 console.log('Base64格式密钥:', arrayBufferToBase64(keyBuffer)); return crypto.subtle.importKey('raw', keyBuffer, {name: 'AES-CBC'}, true, ['decrypt']) .then(function(importedKey) { return crypto.subtle.decrypt({name: 'AES-CBC', iv: new Uint8Array(iv)}, importedKey, data); }); }
为什么原来的方法不行?
String.fromCharCode是把每个字节当作UTF-16编码的码点来生成字符,但密钥的二进制字节(比如随机生成的AES密钥)大多是0-255范围内的任意值,其中很多字节组合起来并不是合法的UTF-8/UTF-16序列,浏览器会用替换字符(�)或者解析出乱码来处理这些无效序列,这就是你看到的奇怪字符的原因。
Base64则是通过将3个二进制字节编码成4个可打印字符的方式,完全保留原始二进制信息,不会出现编码错误。
内容的提问来源于stack exchange,提问作者Ahmed
相关产品推荐
相关产品推荐

