fritz
fritz

Reputation: 163

Javascript decrypt for aes-gcm not working, but in Python it works

I want to port a small python library to JavaScript, running in Node.JS. I get an encrypted message, the initialization vector and the key.

In python3 these are the imports:

from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from binascii import unhexlify
import sys
import string
from Cryptodome.Cipher import AES

And the decrypt works like this:

frame = unhexlify(frame)
encryption_key = unhexlify(str_key)
init_vector = unhexlify(str_iv)
cipher = AES.new(encryption_key, AES.MODE_GCM, nonce=init_vector)
decrypted_msg = cipher.decrypt(frame).hex()    

The key is a hexstring like this (example): 36C66639E48A8CA4D6BC8B282A793BBB

IV is this (example): 4B464D675000000900000023

Message like this: 88D5AB4F97515AAFC6B88D2F85DAA7A0E3C0C40D004535C397C9D037AB7DBDA329107615444894A1A0DD7E85F02D496CECD3FF46AF5FB3C9229CFE8F3EE4606AB2E1F409F36AAD2E50900A4396FC6C2E083F373233A69616950758BFC7D63A9E9B6E99E21B2CBC2B934772CA51FD4D69830711CAB1F8CFF25F0A329337CBA51904F0CAED88D61968743C8454BA922EB00038182C22FE316D16F2A9F544D6F75D51A4E92A1C4EF8AB19A2B7FEAA32D0726C0ED80229AE6C0F7621A4209251ACE2B2BC66FF0327A653BB686C756BE033C7A281F1D2A7E1FA31C3983E15F8FD16CC5787E6F517166814146853FF110167419A3CFDA44BE438C96F0E38BF83D9

It results in this: 0f8006870e0c07e5091b01092f0f00ff88800223090c07e5091b01092f0f00ff888009060100010800ff060000328902020f00161e09060100020800ff060000000002020f00161e09060100010700ff060000000002020f00161b09060100020700ff060000000002020f00161b09060100200700ff12092102020fff162309060100340700ff12000002020fff162309060100480700ff12000002020fff1623090601001f0700ff12000002020ffe162109060100330700ff12000002020ffe162109060100470700ff12000002020ffe1621090601000d0700ff1203e802020ffd16a98558d8881285f5e85e5949158f1dbf4b91e4561312ee738fb5

(which is the expected outcome)

I've now tried to establish the same in Javascript using the WebCrypto API. But I can't manage it to work. Here's my simple code snippet:

const ba = require('binascii');
const crypto = require('crypto').webcrypto;

const myKey = "36C66639E48A8CA4D6BC8B282A793BBB";
const iv = "4B464D675000000900000023";
const cipherText = "88D5AB4F97515AAFC6B88D2F85DAA7A0E3C0C40D004535C397C9D037AB7DBDA329107615444894A1A0DD7E85F02D496CECD3FF46AF5FB3C9229CFE8F3EE4606AB2E1F409F36AAD2E50900A4396FC6C2E083F373233A69616950758BFC7D63A9E9B6E99E21B2CBC2B934772CA51FD4D69830711CAB1F8CFF25F0A329337CBA51904F0CAED88D61968743C8454BA922EB00038182C22FE316D16F2A9F544D6F75D51A4E92A1C4EF8AB19A2B7FEAA32D0726C0ED80229AE6C0F7621A4209251ACE2B2BC66FF0327A653BB686C756BE033C7A281F1D2A7E1FA31C3983E15F8FD16CC5787E6F517166814146853FF110167419A3CFDA44BE438C96F0E38BF83D9";

function importKey(rawKey) {
    console.log('e_key: ', rawKey);
    console.log('e_key: ', ba.unhexlify(rawKey));
    return crypto.subtle.importKey(
        "raw", //can be "jwk" or "raw"
        rawKey, 
        {   //this is the algorithm options
            name: "AES-GCM",
            length: 256
        },
        false, //whether the key is extractable (i.e. can be used in exportKey)
        ["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey"
    )
}


function decrypt(data, key, iv) {
    console.log(data);
    return crypto.subtle.decrypt(
        {
            name: "AES-GCM",
            iv: iv, //The initialization vector you used to encrypt
            //additionalData: ArrayBuffer, //The addtionalData you used to encrypt (if any)
            //tagLength: 0, //The tagLength you used to encrypt (if any)
        },
        key, //from generateKey or importKey above
        new ArrayBuffer(data) //ArrayBuffer of the data
    ).then(function(decrypted){
        //returns an ArrayBuffer containing the decrypted data
        console.log(new Uint8Array(decrypted));
    }).catch(function(err){
        console.error(err);
    });
}

const main = async function() {
    var keys = await importKey(myKey)
    var decryptedData = await decrypt(cipherText, keys, iv);
    console.log(decryptedData);
    
};

main();

When executed, it results in:

DOMException [OperationError]: The provided data is too small.
    at asyncAesGcmCipher (node:internal/crypto/aes:202:30)
    at Object.aesCipher (node:internal/crypto/aes:229:28)
    at cipherOrWrap (node:internal/crypto/webcrypto:665:10)
    at SubtleCrypto.decrypt (node:internal/crypto/webcrypto:680:10)
    at decrypt (/Users/fritz/dev/test/simple.js:26:23)

I tried to keep things 1:1 as in python, but can't decrypt this string. I tried for all entities (myKey, iv and cipherText) with and with unhexlify, etc. No luck.

Is this JavaScript AES-GCM not compatible with the python library? Thanks a lot,

Cheers Fritz

Upvotes: 2

Views: 1218

Answers (1)

fritz
fritz

Reputation: 163

Found the answer here: https://stackoverflow.com/a/49244840/13548905 the missing part was the authentication tag, which in fact is IV + "00000002". When added, decrypt worked.

Upvotes: 1

Related Questions