使用 crypto API 解密数据时如何修复此 OperationError 错误?
How to fix this OperationError error when decrypting data with crypto API?
我已经使用 crypto API 成功加密了数据。完成后,我将初始化向量和加密数据保存为单个 base64 字符串。
解密时,我将这两个信息还原为与原始匹配的Uint8Array。但是解密总是失败并出现以下错误:
error decrypt Error: OperationError
代码如下:
// generate key
generateKey (){
crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
}
// encrypt
async encrypt(data, secretKey) {
const initializationVector = crypto.getRandomValues(new Uint8Array(96));
const encodedData = new TextEncoder().encode(JSON.stringify(data));
const encryptedBuffer = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: initializationVector,
tagLength: 128,
},
secretKey,
encodedData
);
const encryptedDataBase64 = btoa(new Uint8Array(encryptedBuffer));
const initializationVectorBase64 = btoa(initializationVector);
return `${encryptedDataBase64}.${initializationVectorBase64}`;
}
// convert base64 string to uint8array
base64ToUint8Array(base64String) {
return new Uint8Array(
atob(base64String)
.split(",")
.map((n) => +n)
);
}
//decrypt
async decrypt(encryptedData, secretKey) {
const { 0: data, 1: iv } = encryptedData.split(".");
const initializationVector = base64ToUint8Array(iv);
const _data = base64ToUint8Array(data);
const decryptedData = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: initializationVector,
tagLength: 128,
},
secretKey,
_data
);
return new TextDecoder().decode(decryptedData)
}
我在加密和解密期间检查了初始化向量和数据 Uint8Array。它们与原始版本相匹配。所以我不知道我哪里做错了。
感谢您的帮助!
从 ArrayBuffer
到 Base64 的转换不正确,反之亦然。此外,在创建 IV 或实例化 Uint8Array
时,长度必须以字节而不是位为单位指定。一个可能的修复是:
(async () => {
var key = await generateKey();
var plaintext = {"data": "The quick brown fox jumps over the lazy dog"};
var ciphertext = await encrypt(plaintext, key);
console.log(ciphertext.replace(/(.{48})/g,'\n'));
var decrypted = await decrypt(ciphertext, key);
console.log(JSON.parse(decrypted));
})();
// generate key
function generateKey (){
return crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
}
// encrypt
async function encrypt(data, secretKey) {
const initializationVector = crypto.getRandomValues(new Uint8Array(12)); // Fix: length in bytes
const encodedData = new TextEncoder().encode(JSON.stringify(data));
const encryptedBuffer = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: initializationVector,
tagLength: 128,
},
secretKey,
encodedData
);
const encryptedDataBase64 = ab2b64(encryptedBuffer); // Fix: Apply proper ArrayBuffer to Base64 conversion
const initializationVectorBase64 = ab2b64(initializationVector); // Fix: Apply proper ArrayBuffer to Base64 conversion
return `${encryptedDataBase64}.${initializationVectorBase64}`;
}
// decrypt
async function decrypt(encryptedData, secretKey) {
const { 0: data, 1: iv } = encryptedData.split(".");
const initializationVector = b642ab(iv); // Fix: Apply proper Base64 to ArrayBuffer conversion
const _data = b642ab(data); // Fix: Apply proper Base64 to ArrayBuffer conversion
const decryptedData = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: initializationVector,
tagLength: 128,
},
secretKey,
_data
);
return new TextDecoder().decode(decryptedData)
}
// or
function ab2b64(arrayBuffer) {
return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
}
// or
function b642ab(base64string){
return Uint8Array.from(atob(base64string), c => c.charCodeAt(0));
}
我已经使用 crypto API 成功加密了数据。完成后,我将初始化向量和加密数据保存为单个 base64 字符串。
解密时,我将这两个信息还原为与原始匹配的Uint8Array。但是解密总是失败并出现以下错误:
error decrypt Error: OperationError
代码如下:
// generate key
generateKey (){
crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
}
// encrypt
async encrypt(data, secretKey) {
const initializationVector = crypto.getRandomValues(new Uint8Array(96));
const encodedData = new TextEncoder().encode(JSON.stringify(data));
const encryptedBuffer = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: initializationVector,
tagLength: 128,
},
secretKey,
encodedData
);
const encryptedDataBase64 = btoa(new Uint8Array(encryptedBuffer));
const initializationVectorBase64 = btoa(initializationVector);
return `${encryptedDataBase64}.${initializationVectorBase64}`;
}
// convert base64 string to uint8array
base64ToUint8Array(base64String) {
return new Uint8Array(
atob(base64String)
.split(",")
.map((n) => +n)
);
}
//decrypt
async decrypt(encryptedData, secretKey) {
const { 0: data, 1: iv } = encryptedData.split(".");
const initializationVector = base64ToUint8Array(iv);
const _data = base64ToUint8Array(data);
const decryptedData = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: initializationVector,
tagLength: 128,
},
secretKey,
_data
);
return new TextDecoder().decode(decryptedData)
}
我在加密和解密期间检查了初始化向量和数据 Uint8Array。它们与原始版本相匹配。所以我不知道我哪里做错了。
感谢您的帮助!
从 ArrayBuffer
到 Base64 的转换不正确,反之亦然。此外,在创建 IV 或实例化 Uint8Array
时,长度必须以字节而不是位为单位指定。一个可能的修复是:
(async () => {
var key = await generateKey();
var plaintext = {"data": "The quick brown fox jumps over the lazy dog"};
var ciphertext = await encrypt(plaintext, key);
console.log(ciphertext.replace(/(.{48})/g,'\n'));
var decrypted = await decrypt(ciphertext, key);
console.log(JSON.parse(decrypted));
})();
// generate key
function generateKey (){
return crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
}
// encrypt
async function encrypt(data, secretKey) {
const initializationVector = crypto.getRandomValues(new Uint8Array(12)); // Fix: length in bytes
const encodedData = new TextEncoder().encode(JSON.stringify(data));
const encryptedBuffer = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: initializationVector,
tagLength: 128,
},
secretKey,
encodedData
);
const encryptedDataBase64 = ab2b64(encryptedBuffer); // Fix: Apply proper ArrayBuffer to Base64 conversion
const initializationVectorBase64 = ab2b64(initializationVector); // Fix: Apply proper ArrayBuffer to Base64 conversion
return `${encryptedDataBase64}.${initializationVectorBase64}`;
}
// decrypt
async function decrypt(encryptedData, secretKey) {
const { 0: data, 1: iv } = encryptedData.split(".");
const initializationVector = b642ab(iv); // Fix: Apply proper Base64 to ArrayBuffer conversion
const _data = b642ab(data); // Fix: Apply proper Base64 to ArrayBuffer conversion
const decryptedData = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: initializationVector,
tagLength: 128,
},
secretKey,
_data
);
return new TextDecoder().decode(decryptedData)
}
// or
function ab2b64(arrayBuffer) {
return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
}
// or
function b642ab(base64string){
return Uint8Array.from(atob(base64string), c => c.charCodeAt(0));
}