socket.io传输加密数据后WebCrypto AES-GCM解密返回DOMException问题
Socket.IO转发AES加密二进制数据报错问题解决方案
核心原因
- 类型变化:Socket.IO默认序列化逻辑不保留TypedArray类型信息,发送
Uint8Array类型的iv时,会自动提取其底层的ArrayBuffer作为二进制帧传输,因此客户端2收到的iv为ArrayBuffer类型,属于框架正常行为。 - 二进制内容错乱:当单次发送的对象包含多个独立
ArrayBuffer字段时,Socket.IO的二进制自动拆分重组逻辑容易出现字段映射错位,导致接收端拿到的iv、加密消息的二进制内容与发送端不一致,最终触发AES-GCM解密的DOMException错误。
解决方案
方案1:Base64编码传输(推荐,兼容性最高)
将二进制内容转换为字符串传输,彻底规避Socket.IO的二进制处理逻辑问题:
客户端1发送逻辑修改
let encryptedData = await encrypt(text); // 加密消息转base64 const messageBase64 = btoa(String.fromCharCode(...new Uint8Array(encryptedData.message))); // iv转base64 const ivBase64 = btoa(String.fromCharCode(...encryptedData.iv)); socket.emit('message', { message: messageBase64, iv: ivBase64 });
客户端2接收逻辑修改
socket.on('answer', async function(answer){ // base64转回对应二进制格式 const message = Uint8Array.from(atob(answer.message), c => c.charCodeAt(0)).buffer; const iv = Uint8Array.from(atob(answer.iv), c => c.charCodeAt(0)); let decryptedData = await decrypt(message, iv); });
方案2:合并二进制传输(性能更高)
将iv和加密消息合并为单个ArrayBuffer传输,避免多二进制字段的映射错误:
客户端1发送逻辑修改
let encryptedData = await encrypt(text); const msgUint8 = new Uint8Array(encryptedData.message); // 前12位存iv,后续存加密消息 const combined = new Uint8Array(12 + msgUint8.length); combined.set(encryptedData.iv, 0); combined.set(msgUint8, 12); socket.emit('message', combined.buffer);
客户端2接收逻辑修改
socket.on('answer', async function(combinedBuffer){ // 按偏移量拆分iv和加密消息 const iv = new Uint8Array(combinedBuffer, 0, 12); const message = new Uint8Array(combinedBuffer, 12).buffer; let decryptedData = await decrypt(message, iv); });
内容的提问来源于stack exchange,提问作者Sergei Hronov
相关产品推荐
相关产品推荐

