Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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 );
}
@skxo

This comment has been minimized.

Copy link

@skxo skxo commented Jan 26, 2019

Hi,

how can you compile it please? can you give me the procedure to make it run on esp32?
thanks man

@m0923678421

This comment has been minimized.

Copy link

@m0923678421 m0923678421 commented Mar 14, 2019

Hi,

how can you compile it please? can you give me the procedure to make it run on esp32?
thanks man

#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;
Serial.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++ )
{
Serial.printf( "%02x[%c]%c", encrypted[i], (encrypted[i]>31)?encrypted[i]:' ', ((i&0xf)!=0xf)?' ':'\n' );
}
Serial.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?
Serial.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++ )
{
Serial.printf( "%02x[%c]%c", plaintext[i], (plaintext[i]>31)?plaintext[i]:' ', ((i&0xf)!=0xf)?' ':'\n' );
}
Serial.printf( "\n" );

esp_aes_free( &ctx );
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
encodetest();
}

void loop() {
// put your main code here, to run repeatedly:

}

@roysG

This comment has been minimized.

Copy link

@roysG roysG commented Aug 26, 2021

@m0923678421 , can you give example how to generate base64 hash?

@RichFalk

This comment has been minimized.

Copy link

@RichFalk RichFalk commented Oct 14, 2021

Note that the header file has moved and changed its name. It is now "aes/esp_aes.h"

One could also use "mbedtls/aes.h" though the names of the functions are a little different. This version of functions allows for a separate encrypt and decrypt key to be used in case you are mixing between these (so you don't have to reset the key each time) though the mbedtls code for AES is slightly larger code (~40 bytes more).

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