Skip to content

Instantly share code, notes, and snippets.

@cnlohr
Created November 7, 2018 19:50
Show Gist options
  • Save cnlohr/96128ef4126bcc878b1b5a7586c624ef to your computer and use it in GitHub Desktop.
Save cnlohr/96128ef4126bcc878b1b5a7586c624ef to your computer and use it in GitHub Desktop.
Example of using hardware AES 256 Crypto in CBC mode on the ESP32 using ESP-IDF
#include <string.h>
#include <stdio.h>
#include <hwcrypto/aes.h>
/*
For Encryption time: 1802.40us (9.09 MB/s) at 16kB blocks.
*/
static inline int32_t _getCycleCount(void) {
int32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
return ccount;
}
char plaintext[16384];
char encrypted[16384];
int encodetest()
{
uint8_t key[32];
uint8_t iv[16];
//If you have cryptographically random data in the start of your payload, you do not need
//an IV. If you start a plaintext payload, you will need an IV.
memset( iv, 0, sizeof( iv ) );
//Right now, I am using a key of all zeroes. This should change. You should fill the key
//out with actual data.
memset( key, 0, sizeof( key ) );
memset( plaintext, 0, sizeof( plaintext ) );
strcpy( plaintext, "Hello, world, how are you doing today?" );
//Just FYI - you must be encrypting/decrypting data that is in BLOCKSIZE chunks!!!
esp_aes_context ctx;
esp_aes_init( &ctx );
esp_aes_setkey( &ctx, key, 256 );
int32_t start = _getCycleCount();
esp_aes_crypt_cbc( &ctx, ESP_AES_ENCRYPT, sizeof(plaintext), iv, (uint8_t*)plaintext, (uint8_t*)encrypted );
int32_t end = _getCycleCount();
float enctime = (end-start)/240.0;
printf( "Encryption time: %.2fus (%f MB/s)\n", enctime, (sizeof(plaintext)*1.0)/enctime );
//See encrypted payload, and wipe out plaintext.
memset( plaintext, 0, sizeof( plaintext ) );
int i;
for( i = 0; i < 128; i++ )
{
printf( "%02x[%c]%c", encrypted[i], (encrypted[i]>31)?encrypted[i]:' ', ((i&0xf)!=0xf)?' ':'\n' );
}
printf( "\n" );
//Must reset IV.
//XXX TODO: Research further: I found out if you don't reset the IV, the first block will fail
//but subsequent blocks will pass. Is there some strange cryptoalgebra going on that permits this?
printf( "IV: %02x %02x\n", iv[0], iv[1] );
memset( iv, 0, sizeof( iv ) );
//Use the ESP32 to decrypt the CBC block.
esp_aes_crypt_cbc( &ctx, ESP_AES_DECRYPT, sizeof(encrypted), iv, (uint8_t*)encrypted, (uint8_t*)plaintext );
//Verify output
for( i = 0; i < 128; i++ )
{
printf( "%02x[%c]%c", plaintext[i], (plaintext[i]>31)?plaintext[i]:' ', ((i&0xf)!=0xf)?' ':'\n' );
}
printf( "\n" );
esp_aes_free( &ctx );
}
@regisgrison
Copy link

Thank you for this, here is my final version:

#include <string.h>
#include <aes/esp_aes.h>

// AES-256 Key => replace with your own
#define AES_KEY     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, \
                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \
                    0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F

// IV => should be a real random value
#define AES_IV      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F

/* 
  For  Encryption time: 1802.40us  (9.09 MB/s) at 16kB blocks.
*/
static inline int32_t _getCycleCount(void) {
  int32_t ccount;
  __asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
  return ccount;
}

char plaintext[16];
char encrypted[16];

void encodetest()
{
	uint8_t key[32] = {AES_KEY};
	uint8_t encryptionIV[16] = {AES_IV};
	uint8_t decryptionIV[16] = {AES_IV};

	memset( plaintext, 0, sizeof( plaintext ) );
	strcpy( plaintext, "Hello, ESP32!" );

	esp_aes_context ctx;
	esp_aes_init( &ctx );
	esp_aes_setkey( &ctx, key, 256 );
	int32_t start = _getCycleCount();
 	esp_aes_crypt_cbc( &ctx, ESP_AES_ENCRYPT, sizeof(plaintext), encryptionIV, (uint8_t*)plaintext, (uint8_t*)encrypted );
	int32_t end = _getCycleCount();
	float enctime = (end-start)/240.0;
	xprintf( "Encryption time: %.2fus  (%f MB/s)\n", enctime, (sizeof(plaintext)*1.0)/enctime );

	//See encrypted payload, and wipe out plaintext.
	memset( plaintext, 0, sizeof( plaintext ) );
	int i;
	for( i = 0; i < 16; i++ )
	{
		xprintf( "%02x[%c]%c", encrypted[i], (encrypted[i]>31)?encrypted[i]:' ', ((i&0xf)!=0xf)?' ':'\n' );
	}
	xprintf( "\n" );

	//Use the ESP32 to decrypt the CBC block.
	esp_aes_crypt_cbc( &ctx, ESP_AES_DECRYPT, sizeof(encrypted), decryptionIV, (uint8_t*)encrypted, (uint8_t*)plaintext );

	//Verify output
	for( i = 0; i < 16; i++ )
	{
		xprintf( "%02x[%c]%c", plaintext[i],  (plaintext[i]>31)?plaintext[i]:' ', ((i&0xf)!=0xf)?' ':'\n' );
	}
	xprintf( "\n" );

	esp_aes_free( &ctx );
}

void xprintf(const char *format, ...)
{
  char buffer[256];  // or smaller or static &c.
  va_list args;
  va_start(args, format);
  vsprintf(buffer, format, args);
  va_end(args);
  Serial.print(buffer);
}

void setup() {
  Serial.begin(115200);
  // wait for console to start
  delay(1000);
  encodetest();
}

void loop() {
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment