1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 20:38:10 +00:00

feat(core): use U5 HW keys to additionally encrypt storage items

[no changelog]
This commit is contained in:
tychovrahe 2024-03-06 15:53:20 +01:00 committed by TychoVrahe
parent f347a08fd1
commit e060ac68c5
3 changed files with 158 additions and 44 deletions

View File

@ -24,17 +24,25 @@
#include <stddef.h>
#include <stdint.h>
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);
// 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);
// 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);
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

View File

@ -22,6 +22,10 @@
#include <stdio.h>
#include <stm32u5xx_hal_cryp.h>
#include <string.h>
#include "memzero.h"
#define AES_BLOCK_SIZE 16
secbool secure_aes_init(void) {
RCC_OscInitTypeDef osc_init_def = {0};
@ -50,46 +54,33 @@ static void secure_aes_load_bhk(void) {
TAMP->BKP7R;
}
secbool secure_aes_encrypt(uint32_t* input, size_t size, uint32_t* output) {
CRYP_HandleTypeDef hcryp = {0};
uint32_t iv[] = {0, 0, 0, 0};
hcryp.Instance = SAES;
hcryp.Init.DataType = CRYP_NO_SWAP;
hcryp.Init.KeySelect = CRYP_KEYSEL_HSW;
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.HeaderWidthUnit = CRYP_HEADERWIDTHUNIT_BYTE;
hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS;
hcryp.Init.KeyMode = CRYP_KEYMODE_NORMAL;
if (HAL_CRYP_Init(&hcryp) != HAL_OK) {
return secfalse;
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;
}
secure_aes_load_bhk();
if (HAL_CRYP_Encrypt(&hcryp, input, size, output, HAL_MAX_DELAY) != HAL_OK) {
return secfalse;
}
HAL_CRYP_DeInit(&hcryp);
return sectrue;
}
secbool secure_aes_decrypt(uint32_t* input, size_t size, uint32_t* output) {
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;
@ -105,10 +96,103 @@ secbool secure_aes_decrypt(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_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_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);
return sectrue;
}
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 = 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_BYTE;
hcryp.Init.HeaderWidthUnit = CRYP_HEADERWIDTHUNIT_BYTE;
hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS;
hcryp.Init.KeyMode = CRYP_KEYMODE_NORMAL;
if (HAL_CRYP_Init(&hcryp) != HAL_OK) {
return secfalse;
}
if (keysel == CRYP_KEYSEL_HSW || keysel == CRYP_KEYSEL_SW) {
secure_aes_load_bhk();
}
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);

View File

@ -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