我有使用 CryptoJS.AES 加密用户数据的代码,在不同的地方存储 key 、iv 和加密内容。 它还根据用户需求使用存储的 key 和 iv 解密加密内容。
我想使用 Subtle Crypto 浏览器 API 进行加密,已完成。
但我也希望能够使用 Subtle Crypto 解密旧数据(使用 CryptoJS.AES 加密)。
旧数据是使用以下代码生成的
var CryptoJS = require("crypto-js/core");
CryptoJS.AES = require("crypto-js/aes");
let encKey = generateRandomString();
let aesEncrypted = CryptoJS.AES.encrypt(content, encKey);
let encrypted = {
key: aesEncrypted.key.toString(),
iv: aesEncrypted.iv.toString(),
content: aesEncrypted.toString()
};
我尝试按如下方式解密它
let keyArrayBuffer = hexArrayToArrayBuffer(sliceArray(encrypted.key, 2));
let decKey = await importKey(keyArrayBuffer);
let decIv = hexArrayToArrayBuffer(sliceArray(encrypted.iv, 2));
let encContent = stringToArrayBuffer(encrypted.content);
let decryptedByteArray = await crypto.subtle.decrypt(
{ name: "AES-CBC", iv: decIv },
decKey,
encContent
);
let decrypted = new TextDecoder().decode(decrypted);
我收到DOMException
await crypto.subtle.decrypt
上没有回溯的错误
完整的复制品可以在 https://codesandbox.io/s/crypto-js-to-subtle-crypto-u0pgs?file=/src/index.js 找到
最佳答案
在 CryptoJS 代码中, key 作为字符串传递。因此,它被解释为密码,结合随机生成的 8 字节盐,派生出 32 字节 key 和 16 字节 IV,请参阅 here 。专有的(且相对不安全的)OpenSSL key 派生函数 EVP_BytesToKey
用于此。
CryptoJS.AES.encrypt()
返回一个 CipherParams
对象,该对象封装了各种参数,例如生成的 key 和 IV 作为 WordArray
,请参阅here 。应用于键或 IV WordArray
的 toString()
,返回十六进制编码的数据。 toString()
应用于 CipherParams
对象,返回 OpenSSL 格式的密文,即第一个 block (= 前 16 个字节)由 的 ASCII 编码组成Salted__
,后面是 8 字节盐和实际密文,全部经过 Base64 编码,请参阅 here 。这意味着实际的密文(在 Base64 解码后)从第二个 block 开始。
以下代码说明了如何使用 WebCrypto API 解密使用 CryptoJS 生成的密文
//
// CryptoJS
//
const content = "The quick brown fox jumps over the lazy dog";
const encKey = "This is my passphrase";
const aesEncrypted = CryptoJS.AES.encrypt(content, encKey);
const encrypted = {
key: aesEncrypted.key.toString(),
iv: aesEncrypted.iv.toString(),
content: aesEncrypted.toString()
};
//
// WebCrypto API
//
// https://stackoverflow.com/a/50868276
const fromHex = hexString => new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
// https://stackoverflow.com/a/41106346
const fromBase64 = base64String => Uint8Array.from(atob(base64String), c => c.charCodeAt(0));
async function decryptDemo(){
const rawKey = fromHex(encrypted.key);
const iv = fromHex(encrypted.iv);
const ciphertext = fromBase64(encrypted.content).slice(16);
const key = await window.crypto.subtle.importKey(
"raw",
rawKey,
"AES-CBC",
true,
["encrypt", "decrypt"]
);
const decrypted = await window.crypto.subtle.decrypt(
{
name: "AES-CBC",
iv: iv
},
key,
ciphertext
);
const decoder = new TextDecoder();
const plaintext = decoder.decode(decrypted);
console.log(plaintext);
}
decryptDemo();
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
关于javascript - 如何通过 Subtle Crypto 正确解密通过 CryptoJS 加密的文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64067812/