Merge branch 'bugfix/aes_fault_inj' into 'master'

mbedtls: Add simple fault injection check for hardware AES peripheral

See merge request idf/esp-idf!5023
This commit is contained in:
Angus Gratton 2019-05-21 13:44:32 +08:00
commit ba51e9fb5c
3 changed files with 109 additions and 8 deletions

View file

@ -23,5 +23,8 @@
#define IDF_PERFORMANCE_MIN_EVENT_DISPATCH 25000
#define IDF_PERFORMANCE_MIN_EVENT_DISPATCH_PSRAM 21000
// esp_sha() time to process 32KB of input data from RAM
#define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA1_32KB 5000
#define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA512_32KB 4500
#define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA1_32KB 5000
#define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA512_32KB 4500
// AES-CBC hardware throughput (accounts for worst-case performance with PSRAM workaround)
#define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.5

View file

@ -27,6 +27,7 @@
*/
#include <string.h>
#include "mbedtls/aes.h"
#include "mbedtls/platform_util.h"
#include "esp32/aes.h"
#include "soc/dport_reg.h"
#include "soc/hwcrypto_reg.h"
@ -118,19 +119,45 @@ static inline void esp_aes_setkey_hardware( esp_aes_context *ctx, int mode)
*
* Call only while holding esp_aes_acquire_hardware().
*/
static inline void esp_aes_block(const void *input, void *output)
static void esp_aes_block(const void *input, void *output)
{
const uint32_t *input_words = (const uint32_t *)input;
uint32_t i0, i1, i2, i3;
uint32_t *output_words = (uint32_t *)output;
uint32_t *mem_block = (uint32_t *)AES_TEXT_BASE;
for(int i = 0; i < 4; i++) {
mem_block[i] = input_words[i];
}
/* Storing i0,i1,i2,i3 in registers not an array
helps a lot with optimisations at -Os level */
i0 = input_words[0];
DPORT_REG_WRITE(AES_TEXT_BASE, i0);
i1 = input_words[1];
DPORT_REG_WRITE(AES_TEXT_BASE + 4, i1);
i2 = input_words[2];
DPORT_REG_WRITE(AES_TEXT_BASE + 8, i2);
i3 = input_words[3];
DPORT_REG_WRITE(AES_TEXT_BASE + 12, i3);
DPORT_REG_WRITE(AES_START_REG, 1);
while (DPORT_REG_READ(AES_IDLE_REG) != 1) { }
esp_dport_access_read_buffer(output_words, (uint32_t)&mem_block[0], 4);
esp_dport_access_read_buffer(output_words, AES_TEXT_BASE, 4);
/* Physical security check: Verify the AES accelerator actually ran, and wasn't
skipped due to external fault injection while starting the peripheral.
Note that i0,i1,i2,i3 are copied from input buffer in case input==output.
Bypassing this check requires at least one additional fault.
*/
if(i0 == output_words[0] && i1 == output_words[1] && i2 == output_words[2] && i3 == output_words[3]) {
// calling two zeroing functions to narrow the
// window for a double-fault here
memset(output, 0, 16);
mbedtls_platform_zeroize(output, 16);
}
}
/*

View file

@ -0,0 +1,71 @@
/* mbedTLS AES performance test
*/
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <esp_system.h>
#include "mbedtls/aes.h"
#include "unity.h"
#include "sdkconfig.h"
#include "esp_timer.h"
#include "esp_heap_caps.h"
#include "test_utils.h"
TEST_CASE("mbedtls AES performance", "[aes]")
{
const unsigned CALLS = 256;
const unsigned CALL_SZ = 32*1024;
mbedtls_aes_context ctx;
int64_t start, end;
uint8_t iv[16];
uint8_t key[16];
memset(iv, 0xEE, 16);
memset(key, 0x44, 16);
// allocate internal memory
uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL);
TEST_ASSERT_NOT_NULL(buf);
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, key, 128);
start = esp_timer_get_time();
for (int c = 0; c < CALLS; c++) {
memset(buf, 0xAA, CALL_SZ);
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, CALL_SZ, iv, buf, buf);
}
end = esp_timer_get_time();
/* Sanity check: make sure the last ciphertext block matches
what we expect to see.
Last block produced via this Python:
import os, binascii
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
key = b'\x44' * 16
iv = b'\xee' * 16
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
encryptor = cipher.encryptor()
ct = encryptor.update(b'\xaa' * 256 * 32 * 1024) + encryptor.finalize()
print(binascii.hexlify(ct[-16:]))
*/
const uint8_t expected_last_block[] = {
0x50, 0x81, 0xe0, 0xe1, 0x15, 0x2f, 0x14, 0xe9,
0x97, 0xa0, 0xc6, 0xe6, 0x36, 0xf3, 0x5c, 0x25,
};
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_last_block, buf + CALL_SZ - 16, 16);
free(buf);
float usecs = end - start;
// bytes/usec = MB/sec
float mb_sec = (CALL_SZ * CALLS) / usecs;
printf("Encryption rate %.3fMB/sec\n", mb_sec);
#ifdef CONFIG_MBEDTLS_HARDWARE_AES
// Don't put a hard limit on software AES performance (software is approx 2.3MB/sec on Release config)
TEST_PERFORMANCE_GREATER_THAN(AES_CBC_THROUGHPUT_MBSEC, "%.3fMB/sec", mb_sec);
#endif
}