Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encryption Program That Works With NodeJs and mbedtls

Tags:

c

node.js

aes

First, let me start by stating that I am not a cryptographer by any means, and I am not very good at writing c code either, so please excuse me if the answer to this question is obvious or answered. I am developing a messaging program and cannot use TLS on the target platform. As a result, I need to find a way to encrypt each message using a symmetric pre shared key cipher, like AES.

I am seeking a method to encrypt and decrypt data between an mbedtls program (such as aescrypt2) on one end, and a nodejs program on the other. Mbedtls, formerly polarssl, is a library which provides encryption for embedded devices. Included with the source code are some sample programs, like aescrypt2, rsaencrypt, ecdsa and crypt_and_hash.

Aescrypt2 works fine when the resulting encrypted data is also decrypted using aescrypt2, but I cannot seem to get data encrypted with aescrypt to decrypt using nodejs crypto or any other program for that matter, including openssl. For example:

echo 'this is a test message' >test.txt
aescrypt 0 test.txt test.out hex:E76B2413958B00E193
aescrypt 1 test.out test.denc hex:E76B2413958B00E193
cat test.denc
this is a test message

With openssl:

openssl enc -in out.test -out outfile.txt -d -aes256 -k E76B2413958B00E193
bad magic number

Some sample node code that doesn't currently work

    var crypto = require('crypto');
    var AESCrypt = {};

AESCrypt.decrypt = function(cryptkey, iv, encryptdata) {
    encryptdata = new Buffer(encryptdata, 'base64').toString('binary');

    var decipher = crypto.createDecipheriv('aes-256-cbc', cryptkey, iv),
        decoded = decipher.update(encryptdata, 'binary', 'utf8');

    decoded += decipher.final('utf8');
    return decoded;
}

AESCrypt.encrypt = function(cryptkey, iv, cleardata) {
    var encipher = crypto.createCipheriv('aes-256-cbc', cryptkey, iv),
         encryptdata = encipher.update(cleardata, 'utf8', 'binary');

    encryptdata += encipher.final('binary');
    encode_encryptdata = new Buffer(encryptdata, 'binary').toString('base64');
    return encode_encryptdata;
}

var cryptkey   = crypto.createHash('sha256').update('Nixnogen').digest(),
    iv         = 'a2xhcgAAAAAAAAAA',
    buf        = "Here is some data for the encrypt", // 32 chars
    enc        = AESCrypt.encrypt(cryptkey, iv, buf);
    var dec        = AESCrypt.decrypt(cryptkey, iv, enc);

console.warn("encrypt length: ", enc.length);
console.warn("encrypt in Base64:", enc);
console.warn("decrypt all: " + dec);

This results in either errors or garbage text every time. I have tried tweaking a variety of things as well.

I've tried this a hundred different ways, including using the -pass pass:password arg to no avail. Using nodejs, I have either gotten bad decrypt errors, or garbled nonsense back upon decryption. I have tried following many tutorials on the net, such as this one, and suggestions from this thread, and everything else I can find. I have read that different encryption programs use different standards, so compatibility across platforms/programs/languages is not always guaranteed, but I imagine somebody has been in this predicement before and knows a solution?

How would I, using nodejs, decrypt data encrypted by aescrypt2 (or a program like it)? I have only been able to make it work using a system exec call and having node execute aescrypt2 to decrypt/encrypt the data, which is not ideal, as it slows things down considerably. I am open to using a different program than aescrypt2. The only requirements are that it must run on Linux, cannot use openssl libs (because they are not supported on the target system), the program should be small and simple, due to space limitations, and foremost, the encryption/decryption needs to be compatible with nodejs. Any help would be much appreciated.

like image 207
Chev_603 Avatar asked Oct 30 '22 03:10

Chev_603


1 Answers

How would I, using nodejs, decrypt data encrypted by aescrypt2 (or a program like it)?

Sorry to say, but there's no better answer than: by doing the exact same thing that aescrypt2 does when decrypting a file. You've linked to the source by yourself, so just perform the same steps in node.js as they do in C in the decrypt branch.

First of all, get familiar with the layout of the file containing the encrypted data:

    /*
     *  The encrypted file must be structured as follows:
     *
     *        00 .. 15              Initialization Vector
     *        16 .. 31              AES Encrypted Block #1
     *           ..
     *      N*16 .. (N+1)*16 - 1    AES Encrypted Block #N
     *  (N+1)*16 .. (N+1)*16 + 32   HMAC-SHA-256(ciphertext)
     */

So you need to extract the IV, the encrypted blocks and the HMAC from the file, not try to decrypt the whole thing as you try with openssl (your openssl example also does not use the right IV but rather tries to derive it from the key provided - read the man page).

Next, get the key right. The actual key used to encrypt/decrypt is not the one provided on the command line, but rather 8192 iterations of hashing the IV with the key passed on the command line, using SHA256.

Finally, they decrypt, using AES-256-ECB (your openssl and node.js examples use CBC!), every 16 bytes and XOR the result with the pervious 16 bytes (the IV is used for the first 16 bytes).

There's maybe more to it, I just listed the most obvious things I saw when reading through the aescrypt2.c code.

So my advise is: try to write the same logic in node.js and try to find node.js crypto calls for the respective mbedtls counterparts.

I'm not a crypto expert, but I bet that the aescrypt implementation has so many steps that feel complicated (like generating the actual key used), because they know how to do crypto and are just doing it the right way.

like image 89
grasbueschel Avatar answered Nov 12 '22 11:11

grasbueschel