I’m currently working on a project that needs the implementation of an AES256 bit encryption and decryption algorithm to an embedded device like an atmega328. The easiest and faster way to achieve this is by using the AVR cryptolib from here: http://avrcryptolib.das-labor.org/trac/wiki 

Here are different steps to get the library working (I assume you have avr-gcc and subversion installed):

Step 1:  download the library.

mkdir avr_cryptolib
mkdir myproject
cd avr_cryptolib
svn co http://das-labor.org/svn/microcontroller-2/crypto-lib .

Step 2: Copy aes/ and gf256mul/ directories to myproject folder, create main.c and Makefile files.

cp -R aes/ ../myproject/
cp -R gf256mul/ ../myproject/
cd ../myproject/
touch Makefile
touch main.c

Step 3: Create a Makefile to compile the code:

– The necessary files to run the example are explained here: http://avrcryptolib.das-labor.org/trac/wiki/AES

– Makefile:

############################################
#
#  Makefile to compile the AES256 libraries
#
############################################

TARGET=main

# Here all the dirs to include to find .h files
DIR= .
DIR+= aes/
DIR+= gf256mul/

# Here C source files
SRC= $(TARGET).c
SRC+= aes/aes_dec.c
SRC+= aes/aes_enc.c
SRC+= aes/aes_sbox.c
SRC+= aes/aes_invsbox.c
SRC+= aes/aes_keyschedule.c
SRC+= aes/aes256_enc.c
SRC+= aes/aes256_dec.c

# Here ASM source files, Make them always end in a capital 'S', ex: asmfile.S
ASRC= gf256mul/gf256mul.S

# frequency in hz
F_CPU=16000000

# Microcontroller to be used
MCU=atmega328

# Optimization 1, 2, 3 and s for size
OPT = s

# You should not have to change anything below here

# Here we add the prefix -I for the compiler ex: '-I ../dir/subdir/'
IDIR = ${addprefix -I , $(DIR)}

# Compiler C flags
CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -O$(OPT) -ffunction-sections
LDFLAGS = -lm --gc-sections -Wl

# Compiler
CC      = avr-gcc
AR      = avr-ar
OBJCOPY = avr-objcopy
SIZE    = avr-size

# C files and ASM files to object files
OBJ = $(SRC:%.c=%.o) $(ASRC:%.S=%.o) 

all: $(TARGET).elf $(TARGET).hex size

clean:
	rm -rf *.o *.hex *.elf $(OBJ)

# Compile: create object files from C and ASM source files.
%.o: %.c
	$(CC) $(CFLAGS) $(IDIR) -c $< -o $@

%.o: %.S
	$(CC) $(CFLAGS) $(IDIR) -c $< -o $@

$(TARGET).elf: $(OBJ)
	$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)

%.hex: %.elf
	$(OBJCOPY) -O ihex -R .eeprom -R .fuse -R .lock -R .signature $< $@ 	 program: $(TARGET).hex 	avrdude -p m328p -P /dev/ttyUSB0     -c stk500v1   -b 57600 -U flash:w:$(TARGET).hex 	 # Display the size of generated elf file ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf size: 	@if test -f $(TARGET).elf; then echo; $(ELFSIZE); 2>/dev/null; echo; fi

Step 4: Create a main.c file with a test function example:

How to use the library ? how to work  with it ? As easy as it sounds, you have only to concern about 3 functions: aes256_init, aes256_encrypt and aes256_decrypt. Here I show a simple example:

void aes256_test(void)
{
    // aes256 is 32 byte key
    uint8_t key[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20, 21,22,23,24,25,26,27,28,29,30,31};

    // aes256 is 16 byte data size
    uint8_t data[16] = "text to encrypt";

    // declare the context where the round keys are stored
    aes256_ctx_t ctx;

    // Initialize the AES256 with the desired key
    aes256_init(key, &ctx);

    // Encrypt data 
    // "text to encrypt" (ascii) -> '9798D10A63E4E167122C4C07AF49C3A9'(hexa)
    aes256_enc(data, &ctx);

    // Decrypt data
    // '9798D10A63E4E167122C4C07AF49C3A9'(hexa) -> "text to encrypt" (ascii)
    aes256_dec(data, &ctx);
}

-The complete code with sending encryption and decryption results out of UART can be found here.
– main.c:

// Generic libraries
#include 
#include <avr/io.h>
#include <util/delay.h>

// AES
#include "aes.h"

// prototype functions
static void UART_init(void);
static void UART_send_char(char c);
static void UART_send_str(char *str);
static void test(void);
static char hexa_to_ascii(uint8_t input);
static void print_hex(uint8_t *ptr, uint8_t size);

/*!	\fn 	int main(void)
*	\brief	Main functon
*/
int main(void)
{
    // init UART
    UART_init();

    while(1)
    {
        // encrypt and decrypt the message with the key
        test();
    }

    return 0;
}

/*!	\fn 	static void UART_init(void)
*	\brief	Init UART to 19200 baudrate
*/
static void UART_init(void)
{
    // U2Xn to 1
    UCSR0A = (1<<U2X0);

    // configure Baudrate to 19200 with U2X0 enabled
    UBRR0L = 103;
    UBRR0H = 0;

    UCSR0B = (1<<TXEN0);
    UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
}

/*!	\fn 	static void UART_send_char(char c)
*	\brief	Send a char through UART0
*/
static void UART_send_char(char c)
{
    // wait until the last char has been sent
    while(!(UCSR0A & (1<<UDRE0)));

    // load the new char to transmit
    UDR0 = c;
}

/*!	\fn 	static void UART_send_str(char *str);
*	\brief	Send a string through UART0
*/
static void UART_send_str(char *data)
{
    while(*data != 0)
    {
        UART_send_char(*data++);
    }
}

/*!	\fn 	static test(uint8_t input)
*	\brief	Example of use AVR-cryptolib libraries.
*/
static void test(void)
{
    // aes256 is 32 byte key
    uint8_t key[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21, 22,23,24,25,26,27,28,29,30,31};

    // aes256 is 16 byte data size
    uint8_t data[16] = "text to encrypt";

    // the context where the round keys are stored
    aes256_ctx_t ctx;

    UART_send_str("\n** AES256-TEST **\n");

    // Initialize the AES256 with the desired key
    aes256_init(key, &ctx);
    UART_send_str("Key: '");
    print_hex(key, 32);
    UART_send_str("'\n");

    // Encrypt text and show the result in hexa
    aes256_enc(data, &ctx);
    UART_send_str("Encrypted: '");
    print_hex(data, 16);
    UART_send_str("'\n");

    // Decrypt data and show the result in ascii
    aes256_dec(data, &ctx);
    UART_send_str("Decrypted: '");
    UART_send_str(data);
    UART_send_str("'\n");

}

/*!	\fn 	static char hexa_to_ascii(uint8_t input)
*	\brief	Convert the lower nibble of hexa number to his ascii 
*           representation. Usefull to print hexadecimal
*           values trought UART.\n
*           For example: hexa_to_ascii(0x0A) would return ascii 'A'.
* 
*   \param  uint8_t input - The value to be converted
*   \return char - The ascii representation of the lower nibble of the input
*/
static char hexa_to_ascii(uint8_t input)
{

    input &= 0x0F;

    if (input < 10)
    {
        input = input + '0';
    }
    else
    {
        input = input + 'A' - 10;
    }

    return (char)input;
}

/*!	\fn 	static void print_hex(uint8_t *ptr, uint8_t size)
*	\brief	Print hexadecimal representation of an array of uint8_t.
* 
*   \param  uint8_t *ptr - The pointer to the array of uint8_t
*   \param  uint8_t size - The size of the array
*/
static void print_hex(uint8_t *ptr, uint8_t size)
{
    uint8_t i;

    for(i=0; i<size; i++)     {         UART_send_char(hexa_to_ascii(ptr[i]>>4));
        UART_send_char(hexa_to_ascii(ptr[i]&0x0F));
    }
}

Step 5: Compile

– The next command generates main.hex file you must load inside atmega328p.

make

5 thoughts on “AES 256 bit encryption using AVR cryptolib

  1. In this case “data” is encrypt with aes256 in ECB mode? But if I want to encrypt data with aes256 in CBC or CTR mode with AVR-Crypto-Lib is possible? If yes, please, get me more details about this.
    Thank You!

  2. The real reason for most uses of encryption? Well all it has to do is stop the guy who finds or stole your laptop etc. from taking a peek at it before he sells it down the alley for $40 for some drugs. Then stop the dodgy buyer looking before a hacked copy of Windows 7 is installed over the top. That kind of thing.

  3. The exact requirements for the IV depend on the chosen chaining mode, but a random 128 bit value is usually fine. It should be different for each message you encrypt. Store it alongside the ciphertext, typically as a prefix.

Leave a Reply

Your email address will not be published. Required fields are marked *