From e060ac68c5c27d237474834fc413a438b26920e2 Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Wed, 6 Mar 2024 15:53:20 +0100 Subject: [PATCH] feat(core): use U5 HW keys to additionally encrypt storage items [no changelog] --- core/embed/trezorhal/secure_aes.h | 24 +++-- core/embed/trezorhal/stm32u5/secure_aes.c | 108 +++++++++++++++++++--- storage/storage.c | 24 ++++- 3 files changed, 135 insertions(+), 21 deletions(-) diff --git a/core/embed/trezorhal/secure_aes.h b/core/embed/trezorhal/secure_aes.h index 78dedce73..69eac50dc 100644 --- a/core/embed/trezorhal/secure_aes.h +++ b/core/embed/trezorhal/secure_aes.h @@ -24,17 +24,25 @@ #include #include +typedef enum { + SECURE_AES_KEY_DHUK, + SECURE_AES_KEY_BHK, + SECURE_AES_KEY_XORK, +} secure_aes_keysel_t; + // Initializes secure AES module secbool secure_aes_init(void); -// Encrypts a block of data using AES-256 EBB and (DHUK xor BHK) key -// Input and output must be aligned to 32 bits, size is in bytes -secbool secure_aes_encrypt(uint32_t* input, size_t size, uint32_t* output); - -// Decrypts a block of data using AES-256 ECB and (DHUK xor BHK) key -// Input and output must be aligned to 32 bits, size is in bytes -secbool secure_aes_decrypt(uint32_t* input, size_t size, uint32_t* output); +// Encrypts a block of data using AES-256 ECB and HW key (DHUK, BHK or XORK) +// For optimal speed input and output should be aligned to 32 bits, size is in +// bytes +secbool secure_aes_ecb_encrypt_hw(const uint8_t* input, size_t size, + uint8_t* output, secure_aes_keysel_t key); -void secure_aes_test(); +// Decrypts a block of data using AES-256 ECB and HW key (DHUK, BHK or XORK) +// For optimal speed input and output should be aligned to 32 bits, size is in +// bytes +secbool secure_aes_ecb_decrypt_hw(const uint8_t* input, size_t size, + uint8_t* output, secure_aes_keysel_t key); #endif // TREZOR_HAL_SECURE_AES_H diff --git a/core/embed/trezorhal/stm32u5/secure_aes.c b/core/embed/trezorhal/stm32u5/secure_aes.c index 4d6e37600..61fa3cd8a 100644 --- a/core/embed/trezorhal/stm32u5/secure_aes.c +++ b/core/embed/trezorhal/stm32u5/secure_aes.c @@ -22,6 +22,10 @@ #include #include +#include +#include "memzero.h" + +#define AES_BLOCK_SIZE 16 secbool secure_aes_init(void) { RCC_OscInitTypeDef osc_init_def = {0}; @@ -50,20 +54,40 @@ static void secure_aes_load_bhk(void) { TAMP->BKP7R; } -secbool secure_aes_encrypt(uint32_t* input, size_t size, uint32_t* output) { +static uint32_t get_keysel(secure_aes_keysel_t key) { + switch (key) { + case SECURE_AES_KEY_DHUK: + return CRYP_KEYSEL_HW; + case SECURE_AES_KEY_BHK: + return CRYP_KEYSEL_SW; + case SECURE_AES_KEY_XORK: + return CRYP_KEYSEL_HSW; + default: + return 0; + } +} + +secbool secure_aes_ecb_encrypt_hw(const uint8_t* input, size_t size, + uint8_t* output, secure_aes_keysel_t key) { CRYP_HandleTypeDef hcryp = {0}; uint32_t iv[] = {0, 0, 0, 0}; + if (size % AES_BLOCK_SIZE != 0) { + return secfalse; + } + + uint32_t keysel = get_keysel(key); + hcryp.Instance = SAES; hcryp.Init.DataType = CRYP_NO_SWAP; - hcryp.Init.KeySelect = CRYP_KEYSEL_HSW; + hcryp.Init.KeySelect = keysel; hcryp.Init.KeySize = CRYP_KEYSIZE_256B; hcryp.Init.pKey = NULL; hcryp.Init.pInitVect = iv; hcryp.Init.Algorithm = CRYP_AES_ECB; hcryp.Init.Header = NULL; hcryp.Init.HeaderSize = 0; - hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD; + hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_BYTE; hcryp.Init.HeaderWidthUnit = CRYP_HEADERWIDTHUNIT_BYTE; hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; hcryp.Init.KeyMode = CRYP_KEYMODE_NORMAL; @@ -72,10 +96,37 @@ secbool secure_aes_encrypt(uint32_t* input, size_t size, uint32_t* output) { return secfalse; } - secure_aes_load_bhk(); + if (keysel == CRYP_KEYSEL_HSW || keysel == CRYP_KEYSEL_SW) { + secure_aes_load_bhk(); + } - if (HAL_CRYP_Encrypt(&hcryp, input, size, output, HAL_MAX_DELAY) != HAL_OK) { - return secfalse; + if ((size_t)input % sizeof(uint32_t) != 0 || + (size_t)output % sizeof(uint32_t) != 0) { + size_t tmp_size = size; + while (tmp_size >= AES_BLOCK_SIZE) { + uint32_t input_buffer[AES_BLOCK_SIZE / sizeof(uint32_t)]; + uint32_t output_buffer[AES_BLOCK_SIZE / sizeof(uint32_t)]; + memcpy(input_buffer, input, AES_BLOCK_SIZE); + if (HAL_CRYP_Encrypt(&hcryp, input_buffer, AES_BLOCK_SIZE, output_buffer, + HAL_MAX_DELAY) != HAL_OK) { + memzero(input_buffer, sizeof(input_buffer)); + memzero(output_buffer, sizeof(output_buffer)); + return secfalse; + } + memcpy(output, output_buffer, AES_BLOCK_SIZE); + input += AES_BLOCK_SIZE; + output += AES_BLOCK_SIZE; + tmp_size -= AES_BLOCK_SIZE; + + memzero(input_buffer, sizeof(input_buffer)); + memzero(output_buffer, sizeof(output_buffer)); + } + + } else { + if (HAL_CRYP_Encrypt(&hcryp, (uint32_t*)input, size, (uint32_t*)output, + HAL_MAX_DELAY) != HAL_OK) { + return secfalse; + } } HAL_CRYP_DeInit(&hcryp); @@ -83,13 +134,20 @@ secbool secure_aes_encrypt(uint32_t* input, size_t size, uint32_t* output) { return sectrue; } -secbool secure_aes_decrypt(uint32_t* input, size_t size, uint32_t* output) { +secbool secure_aes_ecb_decrypt_hw(const uint8_t* input, size_t size, + uint8_t* output, secure_aes_keysel_t key) { CRYP_HandleTypeDef hcryp = {0}; uint32_t iv[] = {0, 0, 0, 0}; + if (size % AES_BLOCK_SIZE != 0) { + return secfalse; + } + + uint32_t keysel = get_keysel(key); + hcryp.Instance = SAES; hcryp.Init.DataType = CRYP_NO_SWAP; - hcryp.Init.KeySelect = CRYP_KEYSEL_HSW; + hcryp.Init.KeySelect = keysel; hcryp.Init.KeySize = CRYP_KEYSIZE_256B; hcryp.Init.pKey = NULL; hcryp.Init.pInitVect = iv; @@ -104,11 +162,37 @@ secbool secure_aes_decrypt(uint32_t* input, size_t size, uint32_t* output) { if (HAL_CRYP_Init(&hcryp) != HAL_OK) { return secfalse; } + if (keysel == CRYP_KEYSEL_HSW || keysel == CRYP_KEYSEL_SW) { + secure_aes_load_bhk(); + } - secure_aes_load_bhk(); - - if (HAL_CRYP_Decrypt(&hcryp, input, size, output, HAL_MAX_DELAY) != HAL_OK) { - return secfalse; + if ((size_t)input % sizeof(uint32_t) != 0 || + (size_t)output % sizeof(uint32_t) != 0) { + size_t tmp_size = size; + while (tmp_size >= AES_BLOCK_SIZE) { + uint32_t input_buffer[AES_BLOCK_SIZE / sizeof(uint32_t)]; + uint32_t output_buffer[AES_BLOCK_SIZE / sizeof(uint32_t)]; + memcpy(input_buffer, input, AES_BLOCK_SIZE); + if (HAL_CRYP_Decrypt(&hcryp, input_buffer, AES_BLOCK_SIZE, output_buffer, + HAL_MAX_DELAY) != HAL_OK) { + memzero(input_buffer, sizeof(input_buffer)); + memzero(output_buffer, sizeof(output_buffer)); + return secfalse; + } + memcpy(output, output_buffer, AES_BLOCK_SIZE); + input += AES_BLOCK_SIZE; + output += AES_BLOCK_SIZE; + tmp_size -= AES_BLOCK_SIZE; + + memzero(input_buffer, sizeof(input_buffer)); + memzero(output_buffer, sizeof(output_buffer)); + } + + } else { + if (HAL_CRYP_Decrypt(&hcryp, (uint32_t*)input, size, (uint32_t*)output, + HAL_MAX_DELAY) != HAL_OK) { + return secfalse; + } } HAL_CRYP_DeInit(&hcryp); diff --git a/storage/storage.c b/storage/storage.c index 444a00a03..069b51483 100644 --- a/storage/storage.c +++ b/storage/storage.c @@ -36,6 +36,10 @@ #include "optiga.h" #endif +#ifdef STM32U5 +#include "secure_aes.h" +#endif + // The APP namespace which is reserved for storage related values. #define APP_STORAGE 0x00 @@ -491,7 +495,17 @@ static void derive_kek(const uint8_t *pin, size_t pin_len, pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10); ui_progress(PIN_PBKDF2_MS / 10); } + +#ifdef STM32U5 + uint8_t pre_kek[SHA256_DIGEST_LENGTH] = {0}; + pbkdf2_hmac_sha256_Final(&ctx, pre_kek); + ensure(secure_aes_ecb_encrypt_hw(pre_kek, SHA256_DIGEST_LENGTH, kek, + SECURE_AES_KEY_XORK), + "secure_aes derive kek failed"); + memzero(pre_kek, sizeof(pre_kek)); +#else pbkdf2_hmac_sha256_Final(&ctx, kek); +#endif pbkdf2_hmac_sha256_Init(&ctx, pin, pin_len, salt, salt_len, 2); for (int i = 6; i <= 10; i++) { @@ -541,8 +555,16 @@ static void stretch_pin_optiga(const uint8_t *pin, size_t pin_len, pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10); ui_progress(PIN_PBKDF2_MS / 10); } +#ifdef STM32U5 + uint8_t stretched_pin_tmp[OPTIGA_PIN_SECRET_SIZE] = {0}; + pbkdf2_hmac_sha256_Final(&ctx, stretched_pin_tmp); + ensure(secure_aes_ecb_encrypt_hw(stretched_pin_tmp, OPTIGA_PIN_SECRET_SIZE, + stretched_pin, SECURE_AES_KEY_XORK), + "secure_aes pin stretch failed"); + memzero(stretched_pin_tmp, sizeof(stretched_pin_tmp)); +#else pbkdf2_hmac_sha256_Final(&ctx, stretched_pin); - +#endif memzero(&ctx, sizeof(ctx)); } #endif