From 638e3d10a9bb44e7541980415e291c82e7cc4cf7 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Thu, 4 Oct 2018 20:07:09 +0200 Subject: [PATCH] Use ESP32's hardware AES --- .vscode/c_cpp_properties.json | 1 + esp_idf_lmic_config.h | 3 +- src/aes/mbedtls_aes.c | 28 +++++++ src/aes/other.c | 145 ++++++++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 src/aes/mbedtls_aes.c create mode 100644 src/aes/other.c diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 199c206..9357e78 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -16,6 +16,7 @@ "${IDF_PATH}/components/soc/include", "${IDF_PATH}/components/soc/esp32/include", "${IDF_PATH}/components/tcpip_adapter/include", + "${IDF_PATH}/components/mbedtls/mbedtls/include", "${workspaceRoot}/examples/provisioning/build/include", "${workspaceRoot}/examples/hello_world/build/include", "${workspaceRoot}/examples/send_recv/build/include", diff --git a/esp_idf_lmic_config.h b/esp_idf_lmic_config.h index 2384279..4b5e903 100755 --- a/esp_idf_lmic_config.h +++ b/esp_idf_lmic_config.h @@ -54,7 +54,8 @@ #define US_PER_OSTICK 16 #define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK) -#define USE_ORIGINAL_AES +//#define USE_ORIGINAL_AES +#define USE_MBEDTLS_AES #if LMIC_DEBUG_LEVEL > 0 || LMIC_X_DEBUG_LEVEL > 0 #include diff --git a/src/aes/mbedtls_aes.c b/src/aes/mbedtls_aes.c new file mode 100644 index 0000000..4dcee9c --- /dev/null +++ b/src/aes/mbedtls_aes.c @@ -0,0 +1,28 @@ +/******************************************************************************* + * + * ttn-esp32 - The Things Network device library for ESP-IDF / SX127x + * + * Copyright (c) 2018 Manuel Bleichenbacher + * + * Licensed under MIT License + * https://opensource.org/licenses/MIT + * + * AES encryption using ESP32's hardware AES unit. + *******************************************************************************/ + +#include "mbedtls/aes.h" +#include "../lmic/oslmic.h" + +#if defined(USE_MBEDTLS_AES) + +void lmic_aes_encrypt(u1_t *data, u1_t *key) +{ + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_enc(&ctx, key, 128); + mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, data, data); + mbedtls_aes_free(&ctx); +} + + +#endif diff --git a/src/aes/other.c b/src/aes/other.c new file mode 100644 index 0000000..ef87a4f --- /dev/null +++ b/src/aes/other.c @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2016 Matthijs Kooijman + * + * LICENSE + * + * Permission is hereby granted, free of charge, to anyone + * obtaining a copy of this document and accompanying files, + * to do whatever they want with them without any restriction, + * including, but not limited to, copying, modification and + * redistribution. + * + * NO WARRANTY OF ANY KIND IS PROVIDED. + *******************************************************************************/ + +/* + * The original LMIC AES implementation integrates raw AES encryption + * with CMAC and AES-CTR in a single piece of code. Most other AES + * implementations (only) offer raw single block AES encryption, so this + * file contains an implementation of CMAC and AES-CTR, and offers the + * same API through the os_aes() function as the original AES + * implementation. This file assumes that there is an encryption + * function available with this signature: + * + * extern "C" void lmic_aes_encrypt(u1_t *data, u1_t *key); + * + * That takes a single 16-byte buffer and encrypts it wit the given + * 16-byte key. + */ + +#include "../lmic/oslmic.h" + +#if !defined(USE_ORIGINAL_AES) + +// This should be defined elsewhere +void lmic_aes_encrypt(u1_t *data, u1_t *key); + +// global area for passing parameters (aux, key) and for storing round keys +u4_t AESAUX[16/sizeof(u4_t)]; +u4_t AESKEY[11*16/sizeof(u4_t)]; + +// Shift the given buffer left one bit +static void shift_left(xref2u1_t buf, u1_t len) { + while (len--) { + u1_t next = len ? buf[1] : 0; + + u1_t val = (*buf << 1); + if (next & 0x80) + val |= 1; + *buf++ = val; + } +} + +// Apply RFC4493 CMAC, using AESKEY as the key. If prepend_aux is true, +// AESAUX is prepended to the message. AESAUX is used as working memory +// in any case. The CMAC result is returned in AESAUX as well. +static void os_aes_cmac(xref2u1_t buf, u2_t len, u1_t prepend_aux) { + if (prepend_aux) + lmic_aes_encrypt(AESaux, AESkey); + else + memset (AESaux, 0, 16); + + while (len > 0) { + u1_t need_padding = 0; + for (u1_t i = 0; i < 16; ++i, ++buf, --len) { + if (len == 0) { + // The message is padded with 0x80 and then zeroes. + // Since zeroes are no-op for xor, we can just skip them + // and leave AESAUX unchanged for them. + AESaux[i] ^= 0x80; + need_padding = 1; + break; + } + AESaux[i] ^= *buf; + } + + if (len == 0) { + // Final block, xor with K1 or K2. K1 and K2 are calculated + // by encrypting the all-zeroes block and then applying some + // shifts and xor on that. + u1_t final_key[16]; + memset(final_key, 0, sizeof(final_key)); + lmic_aes_encrypt(final_key, AESkey); + + // Calculate K1 + u1_t msb = final_key[0] & 0x80; + shift_left(final_key, sizeof(final_key)); + if (msb) + final_key[sizeof(final_key)-1] ^= 0x87; + + // If the final block was not complete, calculate K2 from K1 + if (need_padding) { + msb = final_key[0] & 0x80; + shift_left(final_key, sizeof(final_key)); + if (msb) + final_key[sizeof(final_key)-1] ^= 0x87; + } + + // Xor with K1 or K2 + for (u1_t i = 0; i < sizeof(final_key); ++i) + AESaux[i] ^= final_key[i]; + } + + lmic_aes_encrypt(AESaux, AESkey); + } +} + +// Run AES-CTR using the key in AESKEY and using AESAUX as the +// counter block. The last byte of the counter block will be incremented +// for every block. The given buffer will be encrypted in place. +static void os_aes_ctr (xref2u1_t buf, u2_t len) { + u1_t ctr[16]; + while (len) { + // Encrypt the counter block with the selected key + memcpy(ctr, AESaux, sizeof(ctr)); + lmic_aes_encrypt(ctr, AESkey); + + // Xor the payload with the resulting ciphertext + for (u1_t i = 0; i < 16 && len > 0; i++, len--, buf++) + *buf ^= ctr[i]; + + // Increment the block index byte + AESaux[15]++; + } +} + +u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) { + switch (mode & ~AES_MICNOAUX) { + case AES_MIC: + os_aes_cmac(buf, len, /* prepend_aux */ !(mode & AES_MICNOAUX)); + return os_rmsbf4(AESaux); + + case AES_ENC: + // TODO: Check / handle when len is not a multiple of 16 + for (u1_t i = 0; i < len; i += 16) + lmic_aes_encrypt(buf+i, AESkey); + break; + + case AES_CTR: + os_aes_ctr(buf, len); + break; + } + return 0; +} + +#endif // !defined(USE_ORIGINAL_AES) \ No newline at end of file