Hello AES World (Toradex)

Intro

Imagine a EU Cyber Resilience Act-motivated deployment scenario where some Toradex-base edge devices need to send data securely back and forth towards a cloud or bare-metal server. It would be handly to have a library that implements the AES cipher not only in software, but also utilises the integrated instruction sets for AES accelration in x86-64 and ARM. The good news is that there is such thing - is it simple, configurable, free and open-source.

In this tutorial we are about to demonstrate the usage of the cord-aes-cipher with standalone GCC build, without relying on CMake or other builds systems.

Creating the Torizon Project

Let's create a new project inside the Torizon IDE.

TOP
TOP

Makefile

Open the Makefile and add -march=armv8-a+crypto -mcpu=cortex-a53+crypto to the CCFLAGS variable. The string after appending our changes will look like:

CCFLAGS := -Iincludes/ -march=armv8-a+crypto -mcpu=cortex-a53+crypto

You can also change the compiler from g++ to pure-C gcc by setting the CC variable accordingly:

CC := gcc

As a result, the section should look as follows:

# tool macros
CC := gcc
CCFLAGS := -Iincludes/ -march=armv8-a+crypto -mcpu=cortex-a53+crypto
DBGFLAGS := -g
LDFLAGS :=
CCOBJFLAGS := $(CCFLAGS) -c
ARCH :=

Repository

Clone

Clone the repo outside the project directory. We will then need some manual copy-paste work. Navigate to a safe location on your filesytem and clone the repository:

$ git clone https://github.com/packetcord/cord-aes-cipher

Then, switch to version tag:

$ cd cord-aes-cipher/
$ git tag
v1.0
$ git checkout v1.0
Note: switching to 'v1.0'.

The copy-paste steps

$ cp cord-aes-cipher/includes/* aes/includes/
$ cp cord-aes-cipher/src/* aes/src/

And replace the main.cpp:

$ rm -f aes/src/main.cpp
$ cp cord-aes-cipher/main.c aes/src/

The project directory structure inside Torizon IDE now should look as on screenshot below:

TOP

Attempt to compile and required changes

At this point, if we try to deploy (or compile) the project, we should get an error:

0.142 aarch64-linux-gnu-g++ -Iincludes/ -march=armv8-a+crypto -mcpu=cortex-a53+crypto -c -o build-arm64/obj/aes_cipher.o src/aes_cipher.c
0.216 In file included from src/aes_cipher.c:5:
0.216 includes/aes_cipher.h:35:10: fatal error: emmintrin.h: No such file or directory
0.216    35 | #include <emmintrin.h>
0.216       |          ^~~~~~~~~~~~~
0.216 compilation terminated.
0.220 make: *** [Makefile:41: build-arm64/obj/aes_cipher.o] Error 1

The reason for this is that by default the library is configured for x86-64 AES-NI acceleration. Now, we need to change it to the NEON-AES instruction set that is present inside the Toradex SoM (on our Verdin, this is an NXP i.MX8 SoC with Aarch64 cores).

We go the the includes/aes_cipher.h file and toggle the hardware acceleration from:

//
// Hardware acceleration
//
#define X86_64_AESNI_ACCEL
// #define ARM_NEON_AES_ACCEL

to

//
// Hardware acceleration
//
// #define X86_64_AESNI_ACCEL
#define ARM_NEON_AES_ACCEL

Note: Commenting both lines will leave us only with software AES implementation.

Build and deploy

Ensure you have the righ settings configured inside .vscode/settings.json file and and try to deploy the application on the Toradex target once again. In my case, I use the Terminal > Run Task > run-container-torizon-release-arm64 from the Torizon IDE.

Upon successful execution, the following log is printed on the console:

[+] Running 1/1
 ✔ Container torizon-aes-1  Created                                                                                                                                            0.2s 
Attaching to aes-1
aes-1  | AES_EXP_KEY_LEN: 176
aes-1  | 
aes-1  | 
aes-1  | Plain:
aes-1  | 0x32 0x43 0xF6 0xA8 
aes-1  | 0x88 0x5A 0x30 0x8D 
aes-1  | 0x31 0x31 0x98 0xA2 
aes-1  | 0xE0 0x37 0x07 0x34 
aes-1  | 
aes-1  | Pure-SW implementation test...
aes-1  | 
aes-1  | Encrypted:
aes-1  | 0x39 0x25 0x84 0x1D 
aes-1  | 0x02 0xDC 0x09 0xFB 
aes-1  | 0xDC 0x11 0x85 0x97 
aes-1  | 0x19 0x6A 0x0B 0x32 
aes-1  | 
aes-1  | Decrypted:
aes-1  | 0x32 0x43 0xF6 0xA8 
aes-1  | 0x88 0x5A 0x30 0x8D 
aes-1  | 0x31 0x31 0x98 0xA2 
aes-1  | 0xE0 0x37 0x07 0x34 
aes-1  | 
aes-1  | Pure-SW implementation SUCCESS!
aes-1  | 
aes-1  | 
aes-1  | ARM NEON acceleration test...
aes-1  | 
aes-1  | Plain:
aes-1  | 0x32 0x43 0xF6 0xA8 
aes-1  | 0x88 0x5A 0x30 0x8D 
aes-1  | 0x31 0x31 0x98 0xA2 
aes-1  | 0xE0 0x37 0x07 0x34 
aes-1  | 
aes-1  | NEON accel. encrypted:
aes-1  | 0x39 0x25 0x84 0x1D 
aes-1  | 0x02 0xDC 0x09 0xFB 
aes-1  | 0xDC 0x11 0x85 0x97 
aes-1  | 0x19 0x6A 0x0B 0x32 
aes-1  | 
aes-1  | NEON accel. decrypted:
aes-1  | 0x32 0x43 0xF6 0xA8 
aes-1  | 0x88 0x5A 0x30 0x8D 
aes-1  | 0x31 0x31 0x98 0xA2 
aes-1  | 0xE0 0x37 0x07 0x34 
aes-1  | 
aes-1  | NEON accel. implementation SUCCESS!
aes-1 exited with code 0
 *  Terminal will be reused by tasks, press any key to close it. 

Using on x86-64

The library also runs on x86-64, with both the pure software implementation and the AES-NI acceleration instruction set. One can simply clone the repo to an x86-64 host and compile it as per the GitHub README guide, but using the last example command from the Build Instructions, namely:

gcc -I includes/ -march=native -msse2 -maes -o main main.c src/aes_cipher.c src/aes_helpers.c

And a few informative notes below:

Note 1: The GitHub README also contains interesting details around the AES ciphper implementation.
Note 2: We encourage you to try to run the example code on the integated Cortex-M core inside the SoC, with and without RTOS.

Outro

So, we demonstrated how simple it is to perform accelerated encryption on hererogeneous architectures. Hope you have enjoyed the tutorial.

Happy coding and (accelerated) encrypting!