最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Web Crypto API throws `DOMException` on AES decryption - Stack Overflow

programmeradmin2浏览0评论

I want to perform basic AES-CBC decryption. I have the string encData that is encrypted with the 128-bits key rawKey, the initialization vector defaultIV is zero. I want to use only Web Crypto API, without 3th-party libraries. Is it possible to do?

window.crypto.subtle.decrypt of Web Crypto API throws the exception when I use it: DOMException (and no more information) in Chromium and OperationError: The operation failed for an operation-specific reason in Firefox.

What is it the problem?

The key and encrypted data is OK, I have checked it in an online decryption (use the hex string from the console output).


The code:

!async function script() {

// ArrayBuffer to Hex String. 
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);

}();

I want to perform basic AES-CBC decryption. I have the string encData that is encrypted with the 128-bits key rawKey, the initialization vector defaultIV is zero. I want to use only Web Crypto API, without 3th-party libraries. Is it possible to do?

window.crypto.subtle.decrypt of Web Crypto API throws the exception when I use it: DOMException (and no more information) in Chromium and OperationError: The operation failed for an operation-specific reason in Firefox.

What is it the problem?

The key and encrypted data is OK, I have checked it in an online decryption (use the hex string from the console output).


The code:

!async function script() {

// ArrayBuffer to Hex String. https://stackoverflow./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);

}();
Share Improve this question edited Feb 8, 2020 at 2:16 KeyKi asked Feb 7, 2020 at 23:57 KeyKiKeyKi 3,2433 gold badges15 silver badges30 bronze badges 6
  • The expected output is: MEGA{"n":"SharedFile.jpg","c":"GRSM8+c1HUmlmyDuTJVrDwSDpqRV"} I have used aes.online-domain-tools. – KeyKi Commented Feb 8, 2020 at 0:14
  • DOM Exception is the document object model. It's your browser plaining about your client side code. I'll look into that library. – Sydney Y Commented Feb 8, 2020 at 0:51
  • In Firefox I get OperationError: The operation failed for an operation-specific reason. – KeyKi Commented Feb 8, 2020 at 0:56
  • I'm at a loss right now. Can you tell me what it is you are trying to do? I'm pretty confident in JavaScript so I think I can help, but I'm not familiar with cryptography. Example: "I have a JSON string encrypted and hashed that I am trying to decode" – Sydney Y Commented Feb 8, 2020 at 1:57
  • A basic AES-CBC decryption. I have a string encData that is encrypted with a 128-bits key rawKey, an initialization vector defaultIV is zero. I wanted to use Web Crypto API, without 3th-party libraries. – KeyKi Commented Feb 8, 2020 at 2:11
 |  Show 1 more ment

2 Answers 2

Reset to default 7

A padding (PKCS #7). It was the problem. My encrypted text that I get from a 3th-party service has no padding (that adds before encryption).

Web Crypto API does not work with data encrypted without the padding.

AES-JS has easy to use API, but it works only with a text without the padding (In my case it's OK), but if you use it to decrypt a cipher text with the padding you need to manually remove it from the result string.

CryptoJS API looks ancient, but it works fine in both case, when the text has the padding or not.

You need to transform ArrayBuffer to something other:

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));
}

See this post, better to use AES-GCM if possible: Webcrypto AES-CBC Decrypt: Operation Error - The operation failed for an operation-specific reason

You can test your browser version for what it supports using this test suite - https://peculiarventures.github.io/pv-webcrypto-tests/

It is certainly possible to do AES-CBC with WebCrypto: https://github./diafygi/webcrypto-examples#aes-cbc

发布评论

评论列表(0)

  1. 暂无评论