Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C - tiny-aes-c and Javascript CryptoJS interoperability

Using tiny-aes-c. Consider the following C code:

int main(int argc, char const *argv[])
{
    uint8_t key[6] = { 's','e','c','r','e','t' };
    uint8_t iv[16]  = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };

    uint8_t in[6]  = { 'm','e','s','a','g','e'};

    uint8_t out[6] = {0x17, 0x8d, 0xc3, 0xa1, 0x56, 0x34};
    struct AES_ctx ctx;

    AES_init_ctx_iv(&ctx, key, iv);
    AES_CTR_xcrypt_buffer(&ctx, in, 6);    

    printf("idx\t encrypted\t expected");
    for(int i=0 ; i<6 ; i++){
        printf("\n[%i]\t %.2x\t\t %.2x" , i , in[i], out[i]);
    }

    return 0;
}

The code encrypts a message and compares the results with the expected output. The code works fine and the output is as follows:

idx      encrypted       expected
[0]      17              17
[1]      8d              8d
[2]      c3              c3
[3]      a1              a1
[4]      56              56
[5]      34              34

I have another service, a NodeJS server which uses CryptoJS.
My question is: How can I transform the C results ({0x17, 0x8d, 0xc3, 0xa1, 0x56, 0x34}) so it will match something CryptoJS could handle?


Edit: Elaborating a bit. for the purpose of this discussion, the C result is transmitted over the network, so it should be transformed to a String. As far as I know, CryptoJS uses base64 as an input for it's AES method, decrypts to bytes that later can be converted to plain text:

var bytes  = CryptoJS.AES.decrypt(BASE_64_STRING, SECRET);
var plaintext = bytes.toString(CryptoJS.enc.Utf8);

The encrypted result for the same message + secret with CryptoJS is: U2FsdGVkX1/TAYUIFnXzC76zb+sd8ol+2DfKCkwITfY= (JS Fiddle) and changes on each run.

Update 2:
Thanks to @MDTech.us_MAN answer I've made some changes to both the JS and C code, but I'm still missing a puzzle pice.

C:

int main(int argc, char const *argv[])
{
    uint8_t key[16] = { 's','e','c','r','e','t','s','e','c','r','e','t','1','2','3','4' };
    uint8_t iv[16]  = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
    uint8_t in[7]  = { 'm','e','s','s','a','g','e'};

    struct AES_ctx ctx;

    AES_init_ctx_iv(&ctx, key, iv);
    AES_CTR_xcrypt_buffer(&ctx, in, 7);

    printf("Encrypted: ");
    for(int i=0 ; i<7 ; i++){
        printf("%.2x" , in[i]);
    }

    return 0;
}

The encrypted HEX string C output: cba9d5bc84113c, when converted to Base64 result is :y6nVvIQRPA==

On the JS side, I'm explicitly using CTR mode with no padding, and initiating (hopefully) same iv like so:

const CryptoJS = require("crypto-js");
let iv = CryptoJS.enc.Hex.parse('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'); // 16 Bytes (same as the C code)
let message = CryptoJS.AES.decrypt("y6nVvIQRPA==", "secretsecret1234", { iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
console.log(message.toString());

The decrypted result: a47172dfe151c7 and not the expected result "message".

What am I missing?

like image 590
Shlomi Schwartz Avatar asked May 10 '18 14:05

Shlomi Schwartz


People also ask

What is CryptoJS AES?

CryptoJS is a growing collection of standard and secure cryptographic algorithms implemented in JavaScript using best practices and patterns. They are fast, and they have a consistent and simple interface.

How to decrypt with CryptoJS?

We can use CryptoJS javascript library to encrypt and decrypt the ciphertext. First, Import the library, you either download the library or use CDN link. Now we will use AES algorithm to encrypt the text. Decryption is the reverse of encryption i.e converting encrypted text to ciphertext.

Is CryptoJS open source?

crypto-js - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers.

How Crypto js works?

CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key. DES is a previously dominant algorithm for encryption, and was published as an official Federal Information Processing Standard (FIPS).


1 Answers

You should read the CryptoJS documentation more carefully. By default it uses CBC mode for the encryption so you should change your tiny-AES implementation to use that.

CryptoJS supports the following modes:

  • CBC (the default)

Also note that CryptoJS has padding enabled by default, while tiny-AES doesn't have it at all. Therefore, messages must be multiples of 16. (Or you can manually use your own padding implementation)

No padding is provided so for CBC and ECB all buffers should be mutiples of 16 bytes. For padding PKCS7 is recommendable.

Then, notice that CryptoJS autoselects the AES variant by the key size:

CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key.

So, you must consider all of these factors in your tiny-AES code.

like image 184
Maxwell175 Avatar answered Oct 23 '22 23:10

Maxwell175