ESP32 Arduino: Encryption using AES-128 in ECB mode

In this tutorial, we are going to check how to use AES-128 in ECB mode, using the Arduino core running on the ESP32 and the mbed TLS library. The tests were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.

 

Introduction

In this tutorial, we are going to check how to use AES-128 in ECB mode, using the Arduino core running on the ESP32 and the mbed TLS library.

The mbed TLS library is already available by default on the Arduino core, so there is no need to install additional software.

If you need a more conceptual introduction about AES and the ECB mode, please consult the introduction section of this previous, which includes a brief explanation about it.

As mentioned there, ECB (Electronic Code Book) mode is not recommended due to the fact that it exposes patterns in the encrypted message. Thus, we are just using it for demonstration purposes.

The tests were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.


The code

The first thing we need to do is including the aes.h file from the mbed TLS library, which exposes the set of functionalities needed to use the AES encryption algorithm.

#include "mbedtls/aes.h"

We will write the remaining code on the Arduino setup function, since we are only going to perform the encryption of a testing string. The first thing we need to do is opening a serial connection, to later output the results of our program.

Serial.begin(115200);

Then we need to create a variable variable of struct type mbedtls_aes_context, which will be used in the next functions calls. This variable will hold the algorithm context.

mbedtls_aes_context aes;

Now we need to define a key for the encryption. Since we are using AES-128, the key needs to have a length of 128 bits (16 bytes). I will be using an arbitrary key for demonstration purposes that is not secure at all. You can check here a guide on how to generate a proper AES key with mbed TLS.

char * key = "abcdefghijklmnop";

Then we need to define the plain text data to be encrypted. Remember from the previous post that AES operates on 16 bytes data blocks. Nonetheless, the ECB encryption function from mbed TLS supports only a single block of data [1], so we need to specify a plain text string with just 16 bytes.

char *input = "Tech tutorials x";

Additionally, we need a 16 bytes buffer to store the output data. Since it will be a simple byte buffer, we declare it as unsigned char.

unsigned char output[16];

Now we will start to call the functions needed to encrypt the data. The first thing we need to do is initializing the AES context we have just created, before using it in another function calls [2]. We do it by calling the mbedtls_aes_init function, which receives a pointer to the context.

mbedtls_aes_init( &aes );

After initializing the context, we need to set the encryption key, which will be used to cipher the plaint text data. We do it by calling the mbedtls_aes_setkey_enc function.

As first input, it receives a pointer to the AES context we have just initialized, as second the encryption key we have just declared and as third and final parameter it receives the size of the key used, in bits [3].

This function call receives the key as constant, so we need to make a cast when passing our previously defined key.

In our case, we are using AES-128, so we need to pass the value 128 to the key length. Naturally, this value should be coherent with the actual size of our key string, which has indeed 128 bits (16 bytes).

Since each char has a size of 1 byte, we can pass the key length in a more dynamic format by getting the string length (which is equal to the number of bytes) and multiplying by the number of bits in a byte (8).

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

To do the actual encryption in ECB mode, we need to call the mbedtls_aes_crypt_ecb function.

This function receives as first input a pointer to the AES context, as second the operation mode (encryption or decryption), as third the 16 bytes length input data and as fourth a 16 bit length output buffer.

Since we want to encrypt data, we pass the constant MBEDTLS_AES_ENCRYPT as second argument of the function call.

As third argument we pass our previously defined input data, making the cast to constant like we did before when setting the key. As fourth argument, we pass the buffer we declared to hold the output data.

mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, (const unsigned char*)input, output);

To finalize the mbed TLS function calls, we need to free the AES context we have used with a call to the mbedtls_aes_free function, which also receives as input a pointer to the context.

mbedtls_aes_free( &aes );

Now that we have obtained the bytes of the encrypted data, we will iterate them and print them in a user friendly format, namely in hexadecimal. We will do that by using the sprintf function to format each of the bytes in a two characters length hexadecimal string.

We will need to use the %02x format specifier on the sprintf function to indicate we want to print each byte as a hexadecimal string with two characters, padded with a leading zero if needed. You can read more about format specifiers here.

The final source code can be seen below and already includes these prints.

#include "mbedtls/aes.h"

void setup() {

  Serial.begin(115200);

  mbedtls_aes_context aes;

  char * key = "abcdefghijklmnop";

  char *input = "Tech tutorials x";
  unsigned char output[16];

  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*)input, output);
  mbedtls_aes_free( &aes );

  for (int i = 0; i < 16; i++) {

    char str[3];

    sprintf(str, "%02x", (int)output[i]);
    Serial.print(str);
  }
}

void loop() {}


Testing the code

In order to test the code developed on this ESP32 tutorial, simply compile it and upload it to your device using the Arduino IDE.

When it finishes, open the serial monitor. You should get an output similar to figure 1, which shows the encrypted data in hexadecimal format.

ESP32 AES ECB mode output mbed tls

Figure 1 – Output of the program.

At the time of writing I hadn’t found a suitable online tool to test the encryption and compare it against the results obtained on the ESP32, so we can test it using the Python program introduced in the previous post.

As can be seen in figure 2, if we encrypt the same data with the same key in ECB mode, we get the same result as in the ESP32.

ESP32 AES ECB Mode result Python comparison

Figure 2 – Comparison of the ESP32 result with the encryption on a Python program, using the pycrypto library.

You can check the full Python testing code below. Please consider that, as explained in detail in the previous post, to use the Python code below we first need to install pycrypto. The mentioned post contains an explanation on how to do it.

from Crypto.Cipher import AES

key = 'abcdefghijklmnop'

cipher = AES.new(key, AES.MODE_ECB)
msg =cipher.encrypt('Tech tutorials x')

print(msg.encode("hex"))
print(msg.encode("hex") == "567a3b23b683d8488d5d40d2a56e31d2")


References

[1] https://tls.mbed.org/api/aes_8h.html#a0e59fdda18a145e702984268b9ab291a

[2] https://tls.mbed.org/api/aes_8h.html#aa72dac8d698ab861843ef74ce8ebf62c

[3] https://tls.mbed.org/api/aes_8h.html#acec17c6592b98876106d035c372b1efa

Advertisements

11 Replies to “ESP32 Arduino: Encryption using AES-128 in ECB mode”

  1. Hello, can anyone please explain me on how to take input from the user to encrypt the code like iexample its by default set to Tech Turtorials X .i am trying but everytime i get stuck during manipulation or typecasting

    Liked by 1 person

  2. What is the proper method to fill the input block if you don’t have a multiple of 16 bytes in your input data? I tried zeros but I don’t seem to get the right result. For example suppose you needed to encrypt “foobar”.

    Liked by 1 person

  3. Hi, could you please explain why AES-128-ECB cipher method in PHP returns different content?
    I’m doing it like this:
    $key = ‘abcdefghijklmnop’;
    $cipher_method = ‘AES-128-ECB’;
    $ivlen = openssl_cipher_iv_length($cipher=$cipher_method);
    $iv = openssl_random_pseudo_bytes($ivlen);
    $ciphertext = openssl_encrypt(‘Tech tutorials x’, $cipher_method, $key, $options=0, $iv);

    It outputs: jmTOhz8XTbskI/zYFFgOFQ==
    It is not the same as in ESP32 (567a3b23b683d8488d5d40d2a56e31d2)

    Liked by 1 person

    1. Hi!

      Unfortunately my knowledge on PHP is very basic and I never worked with encryption there, so I cannot help much.

      But from a quick look at your function calls, it seems that you are using a method other than ECB, since you are passing to the function an IV (initialization vector).

      Thus, that is most likely why the results are not matching.

      Do you know what is the encryption mode the PHP lib is using?

      Also, those options parameter you are passing may introduce some changes in the encryption result.

      Best regards,
      Nuno Santos

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s