Search code examples
javascriptcencryptionaes

Problem with JavaScript AES 256 decryption of data that is encrypted in C


When I do AES-256 CTR encryption in C using tiny-AES-c library (https://github.com/kokke/tiny-AES-c) I unable to decrypt it properly in JavaScript. For JavaScript decryption I'm using library https://github.com/ricmoo/aes-js

After encryption I do base 64 encode and before decryption base 64 decode and that part works fine.

In fields below you can see my C and JavaScript code:

C code

// AES start
struct AES_ctx ctx;
uint8_t enc_buf[32];
uint8_t iv[16] = 
    {0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff};
uint8_t key[32] = 
    {0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4};
uint8_t test_str[32] = { 0, };
uint8_t test_str_size = 32;

AES_init_ctx_iv(&ctx, key, iv);

for (unsigned int i = 0; i < test_str_size; i++) {
    test_str[i] = 'A';
}

for (unsigned int i = 0; i < test_str_size / 32; i++) {
    memcpy(enc_buf, test_str + i * 32, 32);
    AES_CTR_xcrypt_buffer(&ctx, enc_buf, 32);
}
// AES end

JavaScript

var key = [96,61,235,16,21,202,113,190,43,115,174,240,133,125,119,129,31,53,44,7,59,97,8,215,45,152,16,163,9,20,223,244];

var encryptedBytes = aesjs.utils.hex.toBytes(ascii_to_hexa(parsedStr));
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(240));
var decrypted = aesCtr.decrypt(encryptedBytes);
console.log('%c AES decrypted: ', 'color: blue', decrypted.toString());

I'm unable to decrypt original data.

Does anyone can help me with this problem? Is there any libraries that is known to be compatible between C and JavaScript?

Thank you in advance.


Solution

  • You need to pass entire IV as initial counter value:

    var key = [0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4];
    var iv = [0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff];
    var parsedStr = '4a9e3cb0185657721fdbca54892184431b2f28dc122058471572c77dce243ad5';
    
    var encryptedBytes = aesjs.utils.hex.toBytes(parsedStr);
    var aesCtr = new aesjs.ModeOfOperation.ctr(key, iv);
    var decrypted = aesCtr.decrypt(encryptedBytes);
    console.log('%c AES decrypted: ', 'color: blue', decrypted.toString());
    

    Output:

    [Log]  AES decrypted:  – "65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65" (_display, line 40)
    

    Note that it would automatically create aesjs.Counter from the given value if you don't pass an object of aesjs.Counter type. It is equivalent to passing new aesjs.Counter(iv).

    Also note you shouldn't reuse IV for CTR mode. It is supposed to be a random nonce for each packet, so no known plaintext attack is possible.