Introduction

In this tutorial, we will check how to decipher data with AES-128 in ECB mode, on the Arduino core running on the ESP32.

In this previous tutorial we have already checked how to cipher data with this algorithm, so now we will see how to decipher it. Note that most of the functions we will use here were already covered in the previous tutorial, so my recommendation is that you check it first.

We will use the mbed TLS libraries, which are available in the Arduino core and contain an implementation of the AES algorithm, amongst many other cryptographic functionalities.

The tests were performed using a DFRobot’s ESP32 module integrated in a ESP32 development board.

The code

In order to get access to the AES related functionality, we will first include the mbedtls/aes.h file.

#include "mbedtls/aes.h"

In order to keep things organized, we will declare a function to encrypt the data and another to decrypt it.

We will start by the encryption function, which we will call encrypt. This function will receive as input the plain text to encrypt, the encryption key and a byte buffer to store the output of the operation.

Remember from the previous post that AES operates on 16 bytes data blocks. In the case of the mbed TLS implementation, the encryption function supports only a single block of 16 bytes in ECB mode.

Since we are using AES-128, then the key needs to also have a length of 16 bytes. Finally, the output data buffer also needs to have a length of 16 bytes, so we need to make sure to pass to this function a buffer with enough size when calling it later.

Our function will return void since the actual output of the encryption will be copied to the buffer we pass to the function.

void encrypt(char * plainText, char * key, unsigned char * outputBuffer){
// Encryption code
}

Now for the function implementation, the first thing we need to do is declaring a variable of type mbedtls_aes_context, which will hold the context of the algorithm during the procedure.

mbedtls_aes_context aes;

After declaring the context, we need to initialize it by calling the mbedtls_aes_init function and passing as input a pointer to the context.

mbedtls_aes_init(&aes);

Next we need to set the encryption key by calling the mbedtls_aes_setkey_enc function. As first argument, it receives a pointer to the AES context, as second the encryption key (remember that we receive it as parameter of our function) and finally the size of the key, in bits.

Note that the key needs a cast to const unsigned char *.

mbedtls_aes_setkey_enc( &aes, (const unsigned char*) key, strlen(key) * 8 );

Once the key is set, we apply the actual encryption by calling the mbedtls_aes_crypt_ecb function.

As before, it receives a pointer to the AES context as first argument. As second argument, it receives the constant MBEDTLS_AES_ENCRYPT, which indicates that we want to encrypt data.

As third argument, it receives the plain text to encrypt (also an input of our function) and finally, as fourth argument, it receives the output buffer, to which the result of the operation will be copied. Note that the plain text needs a cast to const unsigned char *.

mbedtls_aes_crypt_ecb( &aes, MBEDTLS_AES_ENCRYPT, (const unsigned char*)plainText, outputBuffer);

To finalize the implementation of the function, we free the AES context we used before by calling the mbedtls_aes_free and passing again as input a pointer to the context. 

mbedtls_aes_free( &aes );

The final encrypt function can be seen below.

void encrypt(char * plainText, char * key, unsigned char * outputBuffer){

  mbedtls_aes_context aes;

  mbedtls_aes_init( &aes );
  mbedtls_aes_setkey_enc( &aes, (const unsigned char*) key, strlen(key) * 8 );
  mbedtls_aes_crypt_ecb( &aes, MBEDTLS_AES_ENCRYPT, (const unsigned char*)plainText, outputBuffer);
  mbedtls_aes_free( &aes );
}

Now we need to define the function to decrypt the...

Read more »