I am using OpenSSL in a Desktop software and WolfCrypt (which is also open source) in its embedded counterpart. For this project I must use AES in ECB mode, even though I know ECB is not the most secure mode of operation for AES. According to this thread (broken link), WolfCrypt supports ECB mode, even though it is not properly documented.
I could encode and decode data in OpenSSL without a problem, but I could not do so in WolfCrypt. It seems wolfCrypt is buggy in ECB mode with 192 and 256 bits-long keys (but it seems to work with 128 bits-long keys). I noticed this behavior using the following code. This code encrypts a chunk of data, decrypts it and compares the results with the original data. If the data match, a success message is displayed. Only 128 bits-long keys seem to yield correct results.
I tested this code in VS 2013 (Windows 7) using WolfSSL 3.8.0.
Am I doing something wrong here or is WolfCrypt really buggy?
#include <stdlib.h>
#include <stdio.h>
#include <wolfssl/wolfcrypt/aes.h>
#define POINTER_TO_INDEX(v, i) ( &( ( v )[ i ] ) )
#define BITS_TO_BYTES(x) ( ( x ) / 8 )
#define MAX_KEY_BITS ( 256 )
#define MAX_KEY_LENGTH BITS_TO_BYTES( MAX_KEY_BITS )
#define DATA_LENGTH ( 768 )
byte aes_key[MAX_KEY_LENGTH];
byte aes_iv[MAX_KEY_LENGTH];
byte original_data[DATA_LENGTH];
byte encrypted_data[DATA_LENGTH];
byte decrypted_data[DATA_LENGTH];
Aes aes_encrypt;
Aes aes_decrypt;
void wait_before_exit(void)
{
printf("\nPress 'q' to quit.\n");
while (1)
{
char c = getchar();
if (c == 'q' || c == 'Q') return;
}
}
int main(int argc, char* argv[])
{
int actual_key_length = 0;
printf("Choose key length:\n ( A ) 128 bits\n ( B ) 192 bits\n ( C ) 256 bits\n");
while (actual_key_length == 0)
{
char c = getchar();
switch (c)
{
case 'A': case 'a':
actual_key_length = BITS_TO_BYTES(128);
break;
case 'B': case 'b':
actual_key_length = BITS_TO_BYTES(192);
break;
case 'C': case 'c':
actual_key_length = BITS_TO_BYTES(256);
break;
}
}
// generate aes_key and aes_iv.
for (int i = 0; i < actual_key_length; i++)
{
aes_key[i] = (byte)rand();
aes_iv[i] = (byte)rand();
}
// initialize AES engines.
if (wc_AesSetKeyDirect(&aes_encrypt, (const byte *)aes_key, actual_key_length, (const byte *)aes_iv, AES_ENCRYPTION))
{
printf("Cannot create AES engine for encryption.\n");
wait_before_exit();
return 0;
}
if (wc_AesSetKeyDirect(&aes_decrypt, (const byte *)aes_key, actual_key_length, (const byte *)aes_iv, AES_DECRYPTION))
{
printf("Cannot create AES engine for decryption.\n");
wait_before_exit();
return 0;
}
// generate original data.
for (int i = 0; i < DATA_LENGTH; i++)
{
original_data[i] = (byte)rand();
}
// encrypt data.
for (int i = 0; i < DATA_LENGTH; i += actual_key_length)
{
wc_AesEncryptDirect(&aes_encrypt, POINTER_TO_INDEX(encrypted_data, i), (const byte*)POINTER_TO_INDEX(original_data, i));
}
// decrypt data.
for (int i = 0; i < DATA_LENGTH; i += actual_key_length)
{
wc_AesDecryptDirect(&aes_decrypt, POINTER_TO_INDEX(decrypted_data, i), (const byte*)POINTER_TO_INDEX(encrypted_data, i));
}
// check data.
for (int i = 0; i < DATA_LENGTH; i++)
{
if (original_data[i] != decrypted_data[i])
{
printf("Data mismatch at index %i: original value was %i but decrypted value is %i.\n", i, original_data[i], decrypted_data[i]);
wait_before_exit();
return 0;
}
}
printf("Decrypted data matches original data.\n");
wait_before_exit();
return 0;
}
Don't mix up the key size and the block size. AES supports keys of 128, 192, and 256 bit, but has a fixed block size of 128 bit. The block size is also the IV size for CBC mode, but ECB mode doesn't have an IV and that's partially why it is so bad.
You need to advance your loops by the block size and not by the key size:
int block_length = BITS_TO_BYTES(128);
for (int i = 0; i < DATA_LENGTH; i += block_length) {...}