Search code examples
javascriptencryptionsubtlecrypto

Crypto Subtle Decrypt Parameter Not Type "CryptoKey"


I'm trying to decrypt a string using SubtleCrypto that was pre-generated.

Instead of getting decrypted text I'm getting the error: Failed to execute 'decrypt' on 'SubtleCrypto': parameter 2 is not of type 'CryptoKey'.

console.log(window.crypto.subtle.decrypt({name:"AES-CBC", iv:""}, "1234567890123456", "i4+WxNH8XYMnAm7RsRkfOw=="));

I've tried researching the error but haven't come across anything related to such a basic example. What am I doing wrong?


Solution

  • The parameters have the wrong types: IV and data must be passed as BufferSource, the key as CryptoKey, see SubtleCrypto.decrypt(). A CryptoKey is returned by SubtleCrypto.importKey(), which is used to import the key.

    WebCrypto API (as low level API) does not provide support for data conversion, e.g. Base64 encoded data or strings to BufferSource, so other helper methods must be used for this.

    The following code decrypts the ciphertext:

    var keyData = str2ab("1234567890123456");
    var iv = new Uint8Array(16).buffer;
    var ciphertext = b642ab("i4+WxNH8XYMnAm7RsRkfOw==");
    
    (async () => {
      var decrypted = await decrypt();
      var decryptedStr = new TextDecoder().decode(decrypted);
      console.log(decryptedStr);
    })();
    
    async function decrypt() {
      var key = await importKey();
      try {
        return await crypto.subtle.decrypt(
          { name: "AES-CBC", iv: iv },
          key,
          ciphertext
        );
      } catch (ex) {
        console.error("Error: Name: ", ex.name, ", Message: ", ex.message);
      }
    }
    
    async function importKey() {
      var key = await crypto.subtle.importKey(
        "raw",
        keyData,
        { name: "AES-CBC" },
        true,
        ["decrypt", "encrypt"]
      );
      return key;
    }
    
    // Helper -----------------------------------------------
    
    // https://stackoverflow.com/a/11058858
    function str2ab(str) {
      const buf = new ArrayBuffer(str.length);
      const bufView = new Uint8Array(buf);
      for (let i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
      }
      return buf;
    }
    
    // https://stackoverflow.com/a/21797381/9014097
    function b642ab(base64) {
      var binary_string = window.atob(base64);
      var len = binary_string.length;
      var bytes = new Uint8Array(len);
      for (var i = 0; i < len; i++) {
        bytes[i] = binary_string.charCodeAt(i);
      }
      return bytes.buffer;
    }