Node.js v21.6.2中crypto.subtle解密失败问题求助
解决Node.js AES-CBC解密时的参数错误问题
问题描述
在Node.js v21.6.2中实现文件加密上传云端并本地解密功能,密钥生成和加密环节正常,但解密时出现两个问题:
- 提示iv并非ArrayBuffer类型(实际应为该类型)
- 加密数据对象为undefined
尝试直接传入iv、iv.buffer、iv.buffer.slice作为参数,仍收到以下错误:
node:internal/webidl:181 const err = new TypeError(message); ^ TypeError: Failed to execute 'decrypt' on 'SubtleCrypto': 3rd argument is not instance of ArrayBuffer, Buffer, TypedArray, or DataView. at codedTypeError (node:internal/webidl:181:15) at makeException (node:internal/webidl:190:10) at converters.BufferSource (node:internal/crypto/webidl:206:11) at SubtleCrypto.decrypt (node:internal/crypto/webcrypto:961:28) at decrypt (/Users/me/code/encryptiontest/aes/aes.js:31:43) at testEncryptionDecryption (/Users/me/code/encryptiontest/aes/aes.js:52:29) { code: 'ERR_INVALID_ARG_TYPE' }
原代码
const { subtle } = globalThis.crypto; async function generateAesKey(length = 256) { const key = await subtle.generateKey({ name: 'AES-CBC', length, }, true, ['encrypt', 'decrypt']); return key; } async function aesEncrypt(plaintext) { const ec = new TextEncoder(); const key = await generateAesKey(); const iv = crypto.getRandomValues(new Uint8Array(16)); const ciphertext = await crypto.subtle.encrypt({ name: 'AES-CBC', iv, }, key, ec.encode(plaintext)); return { key, iv, ciphertext, }; } async function decrypt(ciphertext, key, iv) { const dec = new TextDecoder(); const plaintext = await crypto.subtle.decrypt({ name: 'AES-CBC', iv, }, key, ciphertext); return dec.decode(plaintext); } // takes Uint8Array and returns ArrayBuffer function typedArrayToBuffer(array) { return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset); } async function testEncryptionDecryption() { const data = "Hello, world!"; console.log("ENCRYPTING DATA"); const { key, iv, encrypted } = await aesEncrypt(data); console.log(iv); console.log("DECRYPTING DATA"); console.log(typeof iv.buffer); const decrypted = await decrypt(encrypted, key, typedArrayToBuffer(iv)); console.log("Original:", data); console.log("Decrypted:", decrypted); } testEncryptionDecryption();
错误分析与修复方案
1. 核心错误:加密数据变量名不匹配
aesEncrypt函数返回的加密数据字段是ciphertext,但测试函数中解构赋值时误用了encrypted,导致传入decrypt的第一个参数是undefined——这才是错误提示中"3rd argument is not instance..."的根本原因(undefined不属于任何缓冲区类型)。
2. iv类型无需额外转换
Web Crypto API的decrypt方法接受的iv可以是Uint8Array、ArrayBuffer、DataView等BufferSource类型,你生成的iv本身就是Uint8Array,完全符合要求,不需要额外通过typedArrayToBuffer转换。
修正后的代码
const { subtle } = globalThis.crypto; async function generateAesKey(length = 256) { const key = await subtle.generateKey({ name: 'AES-CBC', length, }, true, ['encrypt', 'decrypt']); return key; } async function aesEncrypt(plaintext) { const ec = new TextEncoder(); const key = await generateAesKey(); const iv = crypto.getRandomValues(new Uint8Array(16)); const ciphertext = await crypto.subtle.encrypt({ name: 'AES-CBC', iv, }, key, ec.encode(plaintext)); return { key, iv, ciphertext, }; } async function decrypt(ciphertext, key, iv) { const dec = new TextDecoder(); const plaintext = await crypto.subtle.decrypt({ name: 'AES-CBC', iv, }, key, ciphertext); return dec.decode(plaintext); } async function testEncryptionDecryption() { const data = "Hello, world!"; console.log("ENCRYPTING DATA"); // 解构时使用正确的字段名ciphertext const { key, iv, ciphertext } = await aesEncrypt(data); console.log(iv); console.log("DECRYPTING DATA"); // 直接传入原始iv,无需转换 const decrypted = await decrypt(ciphertext, key, iv); console.log("Original:", data); console.log("Decrypted:", decrypted); } testEncryptionDecryption();
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

