使用Crypto-JS加密ArrayBuffer二进制数据遇阻,求解决方案
问题分析与解决方案
额外字节的成因
你遇到的c2、c3这类额外字节,本质是错误地将二进制数据以UTF-8字符串的方式处理导致的编码膨胀。
当你把二进制转成十六进制字符串后直接传入CryptoJS.AES.encrypt,Crypto-JS会默认把这个字符串当作UTF-8编码来解析成它内部的WordArray格式。但十六进制字符串对应的某些字节(比如0xBA)属于Latin-1字符集,在UTF-8中需要用两个字节(c3 ba)来表示——这就导致解析后的字节流比原始二进制数据多了很多额外的编码字节,最终加密出的密文自然不符合预期。
正确加密二进制数据的方法
Crypto-JS原生支持处理二进制数据,核心是直接将Uint8Array/ArrayBuffer转换成它的原生二进制格式WordArray,完全绕过UTF-8编码转换,避免字节膨胀问题。
步骤1:实现Uint8Array与WordArray的转换工具函数
// 将Uint8Array转换为CryptoJS的WordArray function uint8ArrayToWordArray(u8Array) { const words = []; for (let i = 0; i < u8Array.length; i++) { words[i >>> 2] |= (u8Array[i] & 0xff) << (24 - (i % 4) * 8); } return CryptoJS.lib.WordArray.create(words, u8Array.length); } // 将解密后的WordArray转换回Uint8Array function wordArrayToUint8Array(wordArray) { const u8Array = new Uint8Array(wordArray.sigBytes); let offset = 0; for (let i = 0; i < wordArray.words.length; i++) { const word = wordArray.words[i]; u8Array[offset++] = (word >> 24) & 0xff; u8Array[offset++] = (word >> 16) & 0xff; u8Array[offset++] = (word >> 8) & 0xff; u8Array[offset++] = word & 0xff; } return u8Array.slice(0, wordArray.sigBytes); }
步骤2:修改加密解密代码
保留你原来的密钥和IV处理逻辑,替换二进制数据的处理部分:
// 密钥与IV初始化(保持你的原有代码) var iv_hexString = this.buf2hex([146, 66, 191, 151, 23, 3, 113, 119, 231, 131, 133, 112, 79, 32, 114, 136]); var key_hexString = this.buf2hex([123, 217, 20, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 115, 222, 209, 241, 24, 175, 144, 175, 53, 196, 29, 24, 23, 17, 218, 131, 226, 53, 209]); var key = CryptoJS.enc.Hex.parse(key_hexString); var iv = CryptoJS.enc.Hex.parse(iv_hexString); // 你的二进制消息 let myMessage = new Uint8Array([0x0a, 0x11, 0x00, 0xff, 0x30, 0x53, 22, 0x6a, 0x8f, 0x05, 0x16, 0x15, 0x88, 0xb5]); // 转换为CryptoJS原生的WordArray const messageWordArray = uint8ArrayToWordArray(myMessage); // 加密(直接传入WordArray,而非字符串) let encrypted = CryptoJS.AES.encrypt(messageWordArray, key, { mode: CryptoJS.mode.CTR, iv: iv, padding: CryptoJS.pad.NoPadding }); // 密文转十六进制字符串用于传输 console.log('Cipher Text = ', encrypted.ciphertext.toString()); // 解密流程:将十六进制密文转回WordArray const ciphertextWordArray = CryptoJS.enc.Hex.parse(encrypted.ciphertext.toString()); var decryptedWordArray = CryptoJS.AES.decrypt( { ciphertext: ciphertextWordArray }, key, { mode: CryptoJS.mode.CTR, iv: iv, padding: CryptoJS.pad.NoPadding } ); // 转换回Uint8Array得到原始二进制数据 const decryptedUint8 = wordArrayToUint8Array(decryptedWordArray); console.log('Decrypted Binary Data: ', decryptedUint8);
关键说明
- 直接使用
WordArray处理二进制数据,完全避免了UTF-8编码转换带来的字节变形问题。 - 加密后的密文可以安全地转成十六进制或Base64字符串进行传输,解密时再转回
WordArray即可。
内容的提问来源于stack exchange,提问作者monkey
相关产品推荐
相关产品推荐

