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

C - tiny-aes-c and Javascript CryptoJS interoperability - Stack Overflow

programmeradmin0浏览0评论

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 pares 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?

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 pares 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?

Share Improve this question edited May 13, 2018 at 9:23 Shlomi Schwartz asked May 10, 2018 at 14:09 Shlomi SchwartzShlomi Schwartz 8,91330 gold badges119 silver badges198 bronze badges 4
  • what type can CryptoJS handle? how you get the C result? in what format? your question is unclear to me. – apple apple Commented May 10, 2018 at 14:14
  • Please see my edits :) – Shlomi Schwartz Commented May 10, 2018 at 14:23
  • the most simple solution I think up now is transmit the C result in base64. or in hex then convert to base64 if the C part cannot change. – apple apple Commented May 10, 2018 at 14:29
  • I tried it, however the output of cryptoJS is longer than what I get. – Shlomi Schwartz Commented May 10, 2018 at 14:30
Add a ment  | 

3 Answers 3

Reset to default 7 +500

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 remendable.

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.

You are doing two things

  1. Encrypt
  2. Convert to base64

Upon receiving, you must do the reverse operations of both of these, in the reverse order they were applied before transmitting

  1. Convert from base64
  2. Decrypt

You can also swap the order of the steps, but then the order must be swapped on both the transmitting and receiving sides.

Also make sure the secret is on the same format on both sides.

Thanks to @MDTech.us_MAN and this stack overflow question, I've found a solution, after fixing the mode and the padding, the difference was the way I was parsing the secret on the JS side. In the following example, the secret is parsed as a HEX string:

const CryptoJS = require("crypto-js");
let iv = CryptoJS.enc.Hex.parse('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'); // 16 Bytes
let secret = CryptoJS.enc.Hex.parse('73656372657473656372657431323334'); // 16 Bytes == "secretsecret1234"
let message = CryptoJS.AES.decrypt("y6nVvIQRPA==", secret, { iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
console.log(message.toString(CryptoJS.enc.Utf8)); // -> message
发布评论

评论列表(0)

  1. 暂无评论