【问题标题】:Web Crypto API throws `DOMException` on AES decryptionWeb Crypto API 在 AES 解密时抛出“DOMException”
【发布时间】:2020-05-24 03:11:02
【问题描述】:

我想执行基本的 AES-CBC 解密。我有使用 128 位密钥 rawKey 加密的字符串 encData,初始化向量 defaultIV 为零。我只想使用 Web Crypto API,没有第三方库。有可能吗?

window.crypto.subtle.decrypt 的 Web Crypto API 在我使用它时抛出异常:Chromium 中的 DOMException(没有更多信息)和 Firefox 中的 OperationError: The operation failed for an operation-specific reason

这是什么问题?

密钥和加密数据没问题,我在在线解密中检查过(使用控制台输出的十六进制字符串)。


代码:

!async function script() {

// ArrayBuffer to Hex String. https://stackoverflow.com/a/40031979/11468937
function buf2hex(buffer) {
    return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}


const defaultIV = new Uint8Array(16);
const rawKey    = new Uint8Array([42, 40, 254, 9, 99, 201, 174, 52, 226, 21, 90, 155, 81, 50, 2, 9]);
const encData   = new Uint8Array([102, 80, 220, 73, 185, 233, 85, 7, 195, 196, 137, 107, 65, 150, 162, 161, 80, 82, 26, 18, 110, 247, 189, 176, 35, 197, 140, 4, 138, 75, 159, 197, 75, 88, 131, 23, 235, 125, 96, 81, 41, 170, 220, 45, 64, 55, 30, 68, 39, 6, 112, 194, 243, 209, 177, 173, 54, 71, 21, 172, 62, 147, 112, 76]);

console.log("defaultIV\n", defaultIV, buf2hex(defaultIV));
console.log("rawKey\n",    rawKey,    buf2hex(rawKey));
console.log("encData\n",   encData,   buf2hex(encData));


const key = await crypto.subtle.importKey(
    "raw",
    rawKey,
    "AES-CBC",
    true,
    ["decrypt"]
);
console.log("key", key);


// It throws "Uncaught (in promise) DOMException"
const decrypted  = await crypto.subtle.decrypt(
    {
        name: "AES-CBC",
        iv: defaultIV
    },
    key,
    encData
);
console.log("decrypted", decrypted);

}();

【问题讨论】:

  • 预期输出为:MEGA{"n":"SharedFile.jpg","c":"GRSM8+c1HUmlmyDuTJVrDwSDpqRV"} 我使用过aes.online-domain-tools.com
  • DOM 异常是文档对象模型。这是您的浏览器抱怨您的客户端代码。我会看看那个图书馆。
  • 在 Firefox 中我得到OperationError: The operation failed for an operation-specific reason
  • 我现在很茫然。你能告诉我你想要做什么吗?我对 JavaScript 非常有信心,所以我想我可以提供帮助,但我不熟悉密码学。示例:“我有一个 JSON 字符串加密和散列,我正在尝试解码”
  • 基本的 AES-CBC 解密。我有一个字符串encData,它使用128 位密钥rawKey 加密,初始化向量defaultIV 为零。我想使用Web Crypto API,没有第三方库。

标签: javascript webcrypto-api


【解决方案1】:

请参阅此帖子,如果可能,最好使用 AES-GCM:Webcrypto AES-CBC Decrypt: Operation Error - The operation failed for an operation-specific reason

您可以使用此测试套件测试您的浏览器版本支持的内容 - https://peculiarventures.github.io/pv-webcrypto-tests/

当然可以使用 WebCrypto 进行 AES-CBC:https://github.com/diafygi/webcrypto-examples#aes-cbc

【讨论】:

    【解决方案2】:

    填充 (PKCS #7)。这就是问题所在。我从第 3 方服务获得的加密文本没有填充(在加密之前添加)。

    Web Crypto API 不适用于没有填充加密的数据。

    AES-JS 具有易于使用的 API,但它仅适用于没有填充的文本(在我的情况下没关系),但如果您使用它来解密带有填充的密文,则需要手动将其从结果字符串。

    CryptoJS API 看起来很古老,但在两种情况下都可以正常工作,无论文本是否有填充。

    您需要将 ArrayBuffer 转换为其他内容:

    let key       = ab_to_hex(keyArrayBuffer);
    let iv        = ab_to_bin_str(ivArrayBuffer);
    let encrypted = ab_to_bin_str(encryptedArrayBuffer);
    
    function decrypt(key, iv, encrypted) {
        const plaintextArray = CryptoJS.AES.decrypt(
            { ciphertext: CryptoJS.enc.Latin1.parse(encrypted) },
            CryptoJS.enc.Hex.parse(key),
            { iv: CryptoJS.enc.Latin1.parse(iv) }
        );
        return CryptoJS.enc.Utf8.stringify(plaintextArray);
    }
    
    function ab_to_hex(buffer) {
        return Array.from(new Uint8Array(buffer)).map(n => ("0" + n.toString(16)).slice(-2)).join("");
    }
    
    function ab_to_bin_str(buffer) {
        return String.fromCharCode(...new Uint8Array(buffer));
    }
    
    

    【讨论】:

    • 这并不重要,但我应该注意我的字符串有一个填充,但它是ZeroPadding。我没有在控制台中看到拖尾零,但它们会影响字符串长度。 CryptoJS 默认自动删除 Pkcs7 填充(如果存在),但不会删除其他类型。所以你可以在第三个参数(iv)中指定填充类型,例如——padding: CryptoJS.pad.ZeroPadding
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-12
    • 2018-12-27
    • 1970-01-01
    • 2022-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多