c++node.jscryptographyaes

Node crypto / tinyAES C++ round trip not working for 192/256 bit keys


I have created AES CBC ciphers via Node crypto w/ 16 byte keys - tinyAES in C++ decrypts the cipher correctly. Ciphers created in Node crypto AES CBC using 24 byte or 32 bytes are NOT correctly decrypted in tiny AES, the derived padding is incorrect and the padding value is > 16...

is this a known limitation of the tinyAES?

for context:

1 - I believe Node crypto is using OpenSSL.

2 - a Node crypto AES CBC round trip (within Node) using 16/24/32 byte keys works

3 - a tinyAES AES CBC round trip (within C++) using 16/24/32 byte keys works

4 - Node<->tinyAES 16 byte key AES CBC round trip works

5 - Node<->tinyAES 24|32 byte key AES CBC round trip does NOT work

example - AES CBC 192 bit:

std::string c_b64 = "6l9sPiHYKjK6LiIkJ7qcIg==";   // b64 cipher from Node crypto
std::string aek = "0.591.075170084239850551";  // AES key, 24 bytes
std::string iv = "0123456789abcdef";  // IV

tiny AES decrypting will NOT work but works in Node crypto

example - AES CBC 128bit:

std::string c_b64 = "0B/7mia9ITdfg4QG4AqL/w==";   // b64 cipher from Node crypto
std::string aek = "0.591.0751700842";  // AES key, 16 bytes
std::string iv = "0123456789abcdef";  // IV

tiny AES decrypting will work

is there any way to get a 192/256-bit Node/tinyAES round trip working?

update: this is my C++ test code:

#include "base64.h"
#include "aes.hpp"

#define AES192 1

// 192 bit / 24 byte data
std::string _aek = "0.591.075170084239850551";   // AES key
std::string c_b64 = "6l9sPiHYKjK6LiIkJ7qcIg==";  // cipher
std::string iv = "0123456789abcdef";  // IV
std::string cip_s = base64_decode(c_b64);
vector<uint8_t> c_buf(cip_s.begin(), cip_s.end());
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, reinterpret_cast<const uint8_t*>(_aek.data()), reinterpret_cast<const uint8_t*>(iv.data()));

// Decrypt using CBC mode
AES_CBC_decrypt_buffer(&ctx, c_buf.data(), c_buf.size());

// padding
size_t pad_v = c_buf[c_buf.size() - 1];
if (pad_v > AES_BLOCKLEN) {
    std::cout << "invalid padding: " << pad_v << std::endl;
}
for (size_t i = c_buf.size() - pad_v; i < c_buf.size(); i++) {
    if (c_buf[i] != pad_v) {
        std::cout << "padding bytes invalid: " << std::endl;
    }
}
// Calculate the actual data length
size_t rs_ln = c_buf.size() - pad_v;
// Resize the vector to remove padding
c_buf.resize(rs_ln);
// convert result text buffer to string
std::string rs_txt_dec = string(c_buf.begin(), c_buf.end());

std::cout << "AES dec: rs_txt_dec: " << rs_txt_dec << std::endl;

this outputs on my machine:

invalid padding: 158
Caught Exception: vector::_M_default_append

Solution

  • In the current implementation of the tinyAES library, several parameters are defined as macros in aes.h, namely the mutually exclusive constants AES256, AES192 and AES128. Depending on this parameter, further parameters are defined, namely AES_KEYLEN and AES_keyExpSize in aes.h and Nk and Nr in aes.c.
    It is therefore not possible to specify the AES variant at runtime or to use different AES variants at the same time. If this is to be possible, some changes must be made.

    The following is an example of such a customization (in C++, i.e. in my environment I have renamed aes.h, aes.c and test.c to aes.hpp, aes.cpp and test.cpp and the two .cpp files include the .hpp file).

    1. Replace the macros with functions:

    2. Replace Nk and Nr:

    3. Replace AES_keyExpSize:

    4. Add the KeyLength parameter:

    5. Test: