@ -19,15 +19,15 @@
# include <string.h>
# include "chacha20poly1305/rfc7539.h"
# include "common.h"
# include "hmac.h"
# include "memzero.h"
# include "norcow.h"
# include "storage.h"
# include "pbkdf2.h"
# include "sha2.h"
# include "hmac.h"
# include "rand.h"
# include " memzero .h"
# include " chacha20poly1305/rfc7539 .h"
# include "sha2.h"
# include " storage .h"
# define LOW_MASK 0x55555555
@ -37,7 +37,8 @@
// Norcow storage key of the PIN entry log and PIN success log.
# define PIN_LOGS_KEY ((APP_STORAGE << 8) | 0x01)
// Norcow storage key of the combined salt, EDEK, ESAK and PIN verification code entry.
// Norcow storage key of the combined salt, EDEK, ESAK and PIN verification code
// entry.
# define EDEK_PVC_KEY ((APP_STORAGE << 8) | 0x02)
// Norcow storage key of the PIN set flag.
@ -53,7 +54,8 @@
# define PIN_EMPTY 1
// Maximum number of failed unlock attempts.
// NOTE: The PIN counter logic relies on this constant being less than or equal to 16.
// NOTE: The PIN counter logic relies on this constant being less than or equal
// to 16.
# define PIN_MAX_TRIES 16
// The total number of iterations to use in PBKDF2.
@ -90,7 +92,8 @@
// The length of the storage authentication key in bytes.
# define SAK_SIZE 16
// The combined length of the data encryption key and the storage authentication key in bytes.
// The combined length of the data encryption key and the storage authentication
// key in bytes.
# define KEYS_SIZE (DEK_SIZE + SAK_SIZE)
// The length of the PIN verification code in bytes.
@ -115,9 +118,9 @@
# define GUARD_KEY_MODULUS 6311
# define GUARD_KEY_REMAINDER 15
const char * const VERIFYING_PIN_MSG = " Verifying PIN " ;
const char * const PROCESSING_MSG = " Processing " ;
const char * const STARTING_MSG = " Starting up " ;
const char * const VERIFYING_PIN_MSG = " Verifying PIN " ;
const char * const PROCESSING_MSG = " Processing " ;
const char * const STARTING_MSG = " Starting up " ;
static secbool initialized = secfalse ;
static secbool unlocked = secfalse ;
@ -134,16 +137,19 @@ static uint32_t norcow_active_version = 0;
static const uint8_t TRUE_BYTE = 0x01 ;
static const uint8_t FALSE_BYTE = 0x00 ;
static void __handle_fault ( const char * msg , const char * file , int line , const char * func ) ;
static void __handle_fault ( const char * msg , const char * file , int line ,
const char * func ) ;
# define handle_fault(msg) (__handle_fault(msg, __FILE__, __LINE__, __func__))
static secbool storage_upgrade ( void ) ;
static secbool storage_set_encrypted ( const uint16_t key , const void * val , const uint16_t len ) ;
static secbool storage_get_encrypted ( const uint16_t key , void * val_dest , const uint16_t max_len , uint16_t * len ) ;
static secbool secequal ( const void * ptr1 , const void * ptr2 , size_t n ) {
const uint8_t * p1 = ptr1 ;
const uint8_t * p2 = ptr2 ;
static secbool storage_set_encrypted ( const uint16_t key , const void * val ,
const uint16_t len ) ;
static secbool storage_get_encrypted ( const uint16_t key , void * val_dest ,
const uint16_t max_len , uint16_t * len ) ;
static secbool secequal ( const void * ptr1 , const void * ptr2 , size_t n ) {
const uint8_t * p1 = ptr1 ;
const uint8_t * p2 = ptr2 ;
uint8_t diff = 0 ;
size_t i ;
for ( i = 0 ; i < n ; + + i ) {
@ -160,7 +166,8 @@ static secbool secequal(const void* ptr1, const void* ptr2, size_t n) {
return diff ? secfalse : sectrue ;
}
static secbool secequal32 ( const uint32_t * ptr1 , const uint32_t * ptr2 , size_t n ) {
static secbool secequal32 ( const uint32_t * ptr1 , const uint32_t * ptr2 ,
size_t n ) {
uint32_t diff = 0 ;
size_t i ;
for ( i = 0 ; i < n ; + + i ) {
@ -189,7 +196,8 @@ static secbool is_protected(uint16_t key) {
static secbool auth_init ( void ) {
uint8_t tag [ SHA256_DIGEST_LENGTH ] ;
memzero ( authentication_sum , sizeof ( authentication_sum ) ) ;
hmac_sha256 ( cached_sak , SAK_SIZE , authentication_sum , sizeof ( authentication_sum ) , tag ) ;
hmac_sha256 ( cached_sak , SAK_SIZE , authentication_sum ,
sizeof ( authentication_sum ) , tag ) ;
return norcow_set ( STORAGE_TAG_KEY , tag , STORAGE_TAG_SIZE ) ;
}
@ -202,16 +210,18 @@ static secbool auth_update(uint16_t key) {
}
uint8_t tag [ SHA256_DIGEST_LENGTH ] ;
hmac_sha256 ( cached_sak , SAK_SIZE , ( uint8_t * ) & key , sizeof ( key ) , tag ) ;
hmac_sha256 ( cached_sak , SAK_SIZE , ( uint8_t * ) & key , sizeof ( key ) , tag ) ;
for ( uint32_t i = 0 ; i < SHA256_DIGEST_LENGTH ; i + + ) {
authentication_sum [ i ] ^ = tag [ i ] ;
}
hmac_sha256 ( cached_sak , SAK_SIZE , authentication_sum , sizeof ( authentication_sum ) , tag ) ;
hmac_sha256 ( cached_sak , SAK_SIZE , authentication_sum ,
sizeof ( authentication_sum ) , tag ) ;
return norcow_set ( STORAGE_TAG_KEY , tag , STORAGE_TAG_SIZE ) ;
}
/*
* A secure version of norcow_set ( ) , which updates the storage authentication tag .
* A secure version of norcow_set ( ) , which updates the storage authentication
* tag .
*/
static secbool auth_set ( uint16_t key , const void * val , uint16_t len ) {
secbool found ;
@ -226,13 +236,13 @@ static secbool auth_set(uint16_t key, const void *val, uint16_t len) {
}
/*
* A secure version of norcow_get ( ) , which checks the storage authentication tag .
* A secure version of norcow_get ( ) , which checks the storage authentication
* tag .
*/
static secbool auth_get ( uint16_t key , const void * * val , uint16_t * len )
{
static secbool auth_get ( uint16_t key , const void * * val , uint16_t * len ) {
* val = NULL ;
* len = 0 ;
uint32_t sum [ SHA256_DIGEST_LENGTH / sizeof ( uint32_t ) ] = { 0 } ;
uint32_t sum [ SHA256_DIGEST_LENGTH / sizeof ( uint32_t ) ] = { 0 } ;
// Prepare inner and outer digest.
uint32_t odig [ SHA256_DIGEST_LENGTH / sizeof ( uint32_t ) ] ;
@ -269,10 +279,11 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
}
continue ;
}
g [ 0 ] = ( ( ( uint32_t ) k & 0xff ) < < 24 ) | ( ( ( uint32_t ) k & 0xff00 ) < < 8 ) | 0x8000 ; // Add SHA message padding.
g [ 0 ] = ( ( ( uint32_t ) k & 0xff ) < < 24 ) | ( ( ( uint32_t ) k & 0xff00 ) < < 8 ) |
0x8000 ; // Add SHA message padding.
sha256_Transform ( idig , g , h ) ;
sha256_Transform ( odig , h , h ) ;
for ( uint32_t i = 0 ; i < SHA256_DIGEST_LENGTH / sizeof ( uint32_t ) ; i + + ) {
for ( uint32_t i = 0 ; i < SHA256_DIGEST_LENGTH / sizeof ( uint32_t ) ; i + + ) {
sum [ i ] ^ = h [ i ] ;
}
}
@ -285,11 +296,11 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
memzero ( idig , sizeof ( idig ) ) ;
// Cache the authentication sum.
for ( size_t i = 0 ; i < SHA256_DIGEST_LENGTH / sizeof ( uint32_t ) ; i + + ) {
for ( size_t i = 0 ; i < SHA256_DIGEST_LENGTH / sizeof ( uint32_t ) ; i + + ) {
# if BYTE_ORDER == LITTLE_ENDIAN
REVERSE32 ( sum [ i ] , ( ( uint32_t * ) authentication_sum ) [ i ] ) ;
REVERSE32 ( sum [ i ] , ( ( uint32_t * ) authentication_sum ) [ i ] ) ;
# else
( ( uint32_t * ) authentication_sum ) [ i ] = sum [ i ] ;
( ( uint32_t * ) authentication_sum ) [ i ] = sum [ i ] ;
# endif
}
@ -300,11 +311,12 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
// Check storage authentication tag.
# if BYTE_ORDER == LITTLE_ENDIAN
for ( size_t i = 0 ; i < SHA256_DIGEST_LENGTH / sizeof ( uint32_t ) ; i + + ) {
for ( size_t i = 0 ; i < SHA256_DIGEST_LENGTH / sizeof ( uint32_t ) ; i + + ) {
REVERSE32 ( h [ i ] , h [ i ] ) ;
}
# endif
if ( tag_val = = NULL | | tag_len ! = STORAGE_TAG_SIZE | | sectrue ! = secequal ( h , tag_val , STORAGE_TAG_SIZE ) ) {
if ( tag_val = = NULL | | tag_len ! = STORAGE_TAG_SIZE | |
sectrue ! = secequal ( h , tag_val , STORAGE_TAG_SIZE ) ) {
handle_fault ( " storage tag check " ) ;
}
@ -319,10 +331,10 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
}
/*
* Generates a delay of random length . Use this to protect sensitive code against fault injection .
* Generates a delay of random length . Use this to protect sensitive code
* against fault injection .
*/
static void wait_random ( void )
{
static void wait_random ( void ) {
# ifndef TREZOR_STORAGE_TEST
int wait = random32 ( ) & 0xff ;
volatile int i = 0 ;
@ -342,8 +354,9 @@ static void wait_random(void)
# endif
}
static void derive_kek ( uint32_t pin , const uint8_t * random_salt , uint8_t kek [ SHA256_DIGEST_LENGTH ] , uint8_t keiv [ SHA256_DIGEST_LENGTH ] )
{
static void derive_kek ( uint32_t pin , const uint8_t * random_salt ,
uint8_t kek [ SHA256_DIGEST_LENGTH ] ,
uint8_t keiv [ SHA256_DIGEST_LENGTH ] ) {
# if BYTE_ORDER == BIG_ENDIAN
REVERSE32 ( pin , pin ) ;
# endif
@ -358,21 +371,25 @@ static void derive_kek(uint32_t pin, const uint8_t *random_salt, uint8_t kek[SHA
}
PBKDF2_HMAC_SHA256_CTX ctx ;
pbkdf2_hmac_sha256_Init ( & ctx , ( const uint8_t * ) & pin , sizeof ( pin ) , salt , sizeof ( salt ) , 1 ) ;
pbkdf2_hmac_sha256_Init ( & ctx , ( const uint8_t * ) & pin , sizeof ( pin ) , salt ,
sizeof ( salt ) , 1 ) ;
for ( int i = 1 ; i < = 5 ; i + + ) {
pbkdf2_hmac_sha256_Update ( & ctx , PIN_ITER_COUNT / 10 ) ;
if ( ui_callback & & ui_message ) {
progress = ( ( ui_total - ui_rem ) * 1000 + i * DERIVE_SECS * 100 ) / ui_total ;
progress =
( ( ui_total - ui_rem ) * 1000 + i * DERIVE_SECS * 100 ) / ui_total ;
ui_callback ( ui_rem - i * DERIVE_SECS / 10 , progress , ui_message ) ;
}
}
pbkdf2_hmac_sha256_Final ( & ctx , kek ) ;
pbkdf2_hmac_sha256_Init ( & ctx , ( const uint8_t * ) & pin , sizeof ( pin ) , salt , sizeof ( salt ) , 2 ) ;
pbkdf2_hmac_sha256_Init ( & ctx , ( const uint8_t * ) & pin , sizeof ( pin ) , salt ,
sizeof ( salt ) , 2 ) ;
for ( int i = 6 ; i < = 10 ; i + + ) {
pbkdf2_hmac_sha256_Update ( & ctx , PIN_ITER_COUNT / 10 ) ;
if ( ui_callback & & ui_message ) {
progress = ( ( ui_total - ui_rem ) * 1000 + i * DERIVE_SECS * 100 ) / ui_total ;
progress =
( ( ui_total - ui_rem ) * 1000 + i * DERIVE_SECS * 100 ) / ui_total ;
ui_callback ( ui_rem - i * DERIVE_SECS / 10 , progress , ui_message ) ;
}
}
@ -384,8 +401,7 @@ static void derive_kek(uint32_t pin, const uint8_t *random_salt, uint8_t kek[SHA
memzero ( & salt , sizeof ( salt ) ) ;
}
static secbool set_pin ( uint32_t pin )
{
static secbool set_pin ( uint32_t pin ) {
uint8_t buffer [ RANDOM_SALT_SIZE + KEYS_SIZE + POLY1305_TAG_SIZE ] ;
uint8_t * salt = buffer ;
uint8_t * ekeys = buffer + RANDOM_SALT_SIZE ;
@ -402,11 +418,11 @@ static secbool set_pin(uint32_t pin)
chacha20poly1305_encrypt ( & ctx , cached_keys , ekeys , KEYS_SIZE ) ;
rfc7539_finish ( & ctx , 0 , KEYS_SIZE , pvc ) ;
memzero ( & ctx , sizeof ( ctx ) ) ;
secbool ret = norcow_set ( EDEK_PVC_KEY , buffer , RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE ) ;
secbool ret =
norcow_set ( EDEK_PVC_KEY , buffer , RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE ) ;
memzero ( buffer , sizeof ( buffer ) ) ;
if ( ret = = sectrue )
{
if ( ret = = sectrue ) {
if ( pin = = PIN_EMPTY ) {
ret = norcow_set ( PIN_NOT_SET_KEY , & TRUE_BYTE , sizeof ( TRUE_BYTE ) ) ;
} else {
@ -418,8 +434,7 @@ static secbool set_pin(uint32_t pin)
return ret ;
}
static secbool check_guard_key ( const uint32_t guard_key )
{
static secbool check_guard_key ( const uint32_t guard_key ) {
if ( guard_key % GUARD_KEY_MODULUS ! = GUARD_KEY_REMAINDER ) {
return secfalse ;
}
@ -431,7 +446,8 @@ static secbool check_guard_key(const uint32_t guard_key)
return secfalse ;
}
// Check that the guard_key does not contain a run of 5 (or more) zeros or ones.
// Check that the guard_key does not contain a run of 5 (or more) zeros or
// ones.
uint32_t zero_runs = ~ guard_key ;
zero_runs = zero_runs & ( zero_runs > > 2 ) ;
zero_runs = zero_runs & ( zero_runs > > 1 ) ;
@ -449,35 +465,37 @@ static secbool check_guard_key(const uint32_t guard_key)
return sectrue ;
}
static uint32_t generate_guard_key ( void )
{
static uint32_t generate_guard_key ( void ) {
uint32_t guard_key = 0 ;
do {
guard_key = random_uniform ( ( UINT32_MAX / GUARD_KEY_MODULUS ) + 1 ) * GUARD_KEY_MODULUS + GUARD_KEY_REMAINDER ;
guard_key = random_uniform ( ( UINT32_MAX / GUARD_KEY_MODULUS ) + 1 ) *
GUARD_KEY_MODULUS +
GUARD_KEY_REMAINDER ;
} while ( sectrue ! = check_guard_key ( guard_key ) ) ;
return guard_key ;
}
static secbool expand_guard_key ( const uint32_t guard_key , uint32_t * guard_mask , uint32_t * guard )
{
static secbool expand_guard_key ( const uint32_t guard_key , uint32_t * guard_mask ,
uint32_t * guard ) {
if ( sectrue ! = check_guard_key ( guard_key ) ) {
handle_fault ( " guard key check " ) ;
return secfalse ;
}
* guard_mask = ( ( guard_key & LOW_MASK ) < < 1 ) | ( ( ~ guard_key ) & LOW_MASK ) ;
* guard = ( ( ( guard_key & LOW_MASK ) < < 1 ) & guard_key ) | ( ( ( ~ guard_key ) & LOW_MASK ) & ( guard_key > > 1 ) ) ;
* guard = ( ( ( guard_key & LOW_MASK ) < < 1 ) & guard_key ) |
( ( ( ~ guard_key ) & LOW_MASK ) & ( guard_key > > 1 ) ) ;
return sectrue ;
}
static secbool pin_logs_init ( uint32_t fails )
{
static secbool pin_logs_init ( uint32_t fails ) {
if ( fails > = PIN_MAX_TRIES ) {
return secfalse ;
}
// The format of the PIN_LOGS_KEY entry is:
// guard_key (1 word), pin_success_log (PIN_LOG_WORDS), pin_entry_log (PIN_LOG_WORDS)
uint32_t logs [ GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS ] ;
// guard_key (1 word), pin_success_log (PIN_LOG_WORDS), pin_entry_log
// (PIN_LOG_WORDS)
uint32_t logs [ GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS ] ;
logs [ 0 ] = generate_guard_key ( ) ;
@ -489,30 +507,34 @@ static secbool pin_logs_init(uint32_t fails)
}
uint32_t unused = guard | ~ guard_mask ;
for ( size_t i = 0 ; i < 2 * PIN_LOG_WORDS ; + + i ) {
for ( size_t i = 0 ; i < 2 * PIN_LOG_WORDS ; + + i ) {
logs [ GUARD_KEY_WORDS + i ] = unused ;
}
// Set the first word of the PIN entry log to indicate the requested number of fails.
logs [ GUARD_KEY_WORDS + PIN_LOG_WORDS ] = ( ( ( ( uint32_t ) 0xFFFFFFFF ) > > ( 2 * fails ) ) & ~ guard_mask ) | guard ;
// Set the first word of the PIN entry log to indicate the requested number of
// fails.
logs [ GUARD_KEY_WORDS + PIN_LOG_WORDS ] =
( ( ( ( uint32_t ) 0xFFFFFFFF ) > > ( 2 * fails ) ) & ~ guard_mask ) | guard ;
return norcow_set ( PIN_LOGS_KEY , logs , sizeof ( logs ) ) ;
}
/*
* Initializes the values of VERSION_KEY , EDEK_PVC_KEY , PIN_NOT_SET_KEY and PIN_LOGS_KEY using an empty PIN .
* This function should be called to initialize freshly wiped storage .
* Initializes the values of VERSION_KEY , EDEK_PVC_KEY , PIN_NOT_SET_KEY and
* PIN_LOGS_KEY using an empty PIN . This function should be called to initialize
* freshly wiped storage .
*/
static void init_wiped_storage ( void )
{
static void init_wiped_storage ( void ) {
if ( sectrue ! = initialized ) {
// We cannot initialize the storage contents if the hardware_salt is not set.
// We cannot initialize the storage contents if the hardware_salt is not
// set.
return ;
}
random_buffer ( cached_keys , sizeof ( cached_keys ) ) ;
uint32_t version = NORCOW_VERSION ;
ensure ( auth_init ( ) , " set_storage_auth_tag failed " ) ;
ensure ( storage_set_encrypted ( VERSION_KEY , & version , sizeof ( version ) ) , " set_storage_version failed " ) ;
ensure ( storage_set_encrypted ( VERSION_KEY , & version , sizeof ( version ) ) ,
" set_storage_version failed " ) ;
ensure ( pin_logs_init ( 0 ) , " init_pin_logs failed " ) ;
ui_total = DERIVE_SECS ;
ui_rem = ui_total ;
@ -523,8 +545,8 @@ static void init_wiped_storage(void)
}
}
void storage_init ( PIN_UI_WAIT_CALLBACK callback , const uint8_t * salt , const uint16_t salt_len )
{
void storage_init ( PIN_UI_WAIT_CALLBACK callback , const uint8_t * salt ,
const uint16_t salt_len ) {
initialized = secfalse ;
unlocked = secfalse ;
norcow_init ( & norcow_active_version ) ;
@ -549,31 +571,34 @@ void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt, const uint
memzero ( cached_keys , sizeof ( cached_keys ) ) ;
}
static secbool pin_fails_reset ( void )
{
static secbool pin_fails_reset ( void ) {
const void * logs = NULL ;
uint16_t len = 0 ;
if ( sectrue ! = norcow_get ( PIN_LOGS_KEY , & logs , & len ) | | len ! = WORD_SIZE * ( GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS ) ) {
if ( sectrue ! = norcow_get ( PIN_LOGS_KEY , & logs , & len ) | |
len ! = WORD_SIZE * ( GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS ) ) {
return secfalse ;
}
uint32_t guard_mask ;
uint32_t guard ;
wait_random ( ) ;
if ( sectrue ! = expand_guard_key ( * ( const uint32_t * ) logs , & guard_mask , & guard ) ) {
if ( sectrue ! =
expand_guard_key ( * ( const uint32_t * ) logs , & guard_mask , & guard ) ) {
return secfalse ;
}
uint32_t unused = guard | ~ guard_mask ;
const uint32_t * success_log = ( ( const uint32_t * ) logs ) + GUARD_KEY_WORDS ;
const uint32_t * success_log = ( ( const uint32_t * ) logs ) + GUARD_KEY_WORDS ;
const uint32_t * entry_log = success_log + PIN_LOG_WORDS ;
for ( size_t i = 0 ; i < PIN_LOG_WORDS ; + + i ) {
if ( entry_log [ i ] = = unused ) {
return sectrue ;
}
if ( success_log [ i ] ! = guard ) {
if ( sectrue ! = norcow_update_word ( PIN_LOGS_KEY , sizeof ( uint32_t ) * ( i + GUARD_KEY_WORDS ) , entry_log [ i ] ) ) {
if ( sectrue ! = norcow_update_word (
PIN_LOGS_KEY , sizeof ( uint32_t ) * ( i + GUARD_KEY_WORDS ) ,
entry_log [ i ] ) ) {
return secfalse ;
}
}
@ -581,8 +606,7 @@ static secbool pin_fails_reset(void)
return pin_logs_init ( 0 ) ;
}
secbool storage_pin_fails_increase ( void )
{
secbool storage_pin_fails_increase ( void ) {
if ( sectrue ! = initialized ) {
return secfalse ;
}
@ -591,7 +615,8 @@ secbool storage_pin_fails_increase(void)
uint16_t len = 0 ;
wait_random ( ) ;
if ( sectrue ! = norcow_get ( PIN_LOGS_KEY , & logs , & len ) | | len ! = WORD_SIZE * ( GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS ) ) {
if ( sectrue ! = norcow_get ( PIN_LOGS_KEY , & logs , & len ) | |
len ! = WORD_SIZE * ( GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS ) ) {
handle_fault ( " no PIN logs " ) ;
return secfalse ;
}
@ -599,12 +624,14 @@ secbool storage_pin_fails_increase(void)
uint32_t guard_mask ;
uint32_t guard ;
wait_random ( ) ;
if ( sectrue ! = expand_guard_key ( * ( const uint32_t * ) logs , & guard_mask , & guard ) ) {
if ( sectrue ! =
expand_guard_key ( * ( const uint32_t * ) logs , & guard_mask , & guard ) ) {
handle_fault ( " guard key expansion " ) ;
return secfalse ;
}
const uint32_t * entry_log = ( ( const uint32_t * ) logs ) + GUARD_KEY_WORDS + PIN_LOG_WORDS ;
const uint32_t * entry_log =
( ( const uint32_t * ) logs ) + GUARD_KEY_WORDS + PIN_LOG_WORDS ;
for ( size_t i = 0 ; i < PIN_LOG_WORDS ; + + i ) {
wait_random ( ) ;
if ( ( entry_log [ i ] & guard_mask ) ! = guard ) {
@ -618,20 +645,22 @@ secbool storage_pin_fails_increase(void)
word = ( word > > 2 ) | ( word > > 1 ) ;
wait_random ( ) ;
if ( sectrue ! = norcow_update_word ( PIN_LOGS_KEY , sizeof ( uint32_t ) * ( i + GUARD_KEY_WORDS + PIN_LOG_WORDS ) , ( word & ~ guard_mask ) | guard ) ) {
if ( sectrue ! =
norcow_update_word (
PIN_LOGS_KEY ,
sizeof ( uint32_t ) * ( i + GUARD_KEY_WORDS + PIN_LOG_WORDS ) ,
( word & ~ guard_mask ) | guard ) ) {
handle_fault ( " PIN logs update " ) ;
return secfalse ;
}
return sectrue ;
}
}
handle_fault ( " PIN log exhausted " ) ;
return secfalse ;
}
static uint32_t hamming_weight ( uint32_t value )
{
static uint32_t hamming_weight ( uint32_t value ) {
value = value - ( ( value > > 1 ) & 0x55555555 ) ;
value = ( value & 0x33333333 ) + ( ( value > > 2 ) & 0x33333333 ) ;
value = ( value + ( value > > 4 ) ) & 0x0F0F0F0F ;
@ -640,14 +669,14 @@ static uint32_t hamming_weight(uint32_t value)
return value & 0x3F ;
}
static secbool pin_get_fails ( uint32_t * ctr )
{
static secbool pin_get_fails ( uint32_t * ctr ) {
* ctr = PIN_MAX_TRIES ;
const void * logs = NULL ;
uint16_t len = 0 ;
wait_random ( ) ;
if ( sectrue ! = norcow_get ( PIN_LOGS_KEY , & logs , & len ) | | len ! = WORD_SIZE * ( GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS ) ) {
if ( sectrue ! = norcow_get ( PIN_LOGS_KEY , & logs , & len ) | |
len ! = WORD_SIZE * ( GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS ) ) {
handle_fault ( " no PIN logs " ) ;
return secfalse ;
}
@ -655,18 +684,21 @@ static secbool pin_get_fails(uint32_t *ctr)
uint32_t guard_mask ;
uint32_t guard ;
wait_random ( ) ;
if ( sectrue ! = expand_guard_key ( * ( const uint32_t * ) logs , & guard_mask , & guard ) ) {
if ( sectrue ! =
expand_guard_key ( * ( const uint32_t * ) logs , & guard_mask , & guard ) ) {
handle_fault ( " guard key expansion " ) ;
return secfalse ;
}
const uint32_t unused = guard | ~ guard_mask ;
const uint32_t * success_log = ( ( const uint32_t * ) logs ) + GUARD_KEY_WORDS ;
const uint32_t * success_log = ( ( const uint32_t * ) logs ) + GUARD_KEY_WORDS ;
const uint32_t * entry_log = success_log + PIN_LOG_WORDS ;
volatile int current = - 1 ;
volatile size_t i ;
for ( i = 0 ; i < PIN_LOG_WORDS ; + + i ) {
if ( ( entry_log [ i ] & guard_mask ) ! = guard | | ( success_log [ i ] & guard_mask ) ! = guard | | ( entry_log [ i ] & success_log [ i ] ) ! = entry_log [ i ] ) {
if ( ( entry_log [ i ] & guard_mask ) ! = guard | |
( success_log [ i ] & guard_mask ) ! = guard | |
( entry_log [ i ] & success_log [ i ] ) ! = entry_log [ i ] ) {
handle_fault ( " PIN logs format check " ) ;
return secfalse ;
}
@ -688,10 +720,11 @@ static secbool pin_get_fails(uint32_t *ctr)
return secfalse ;
}
// Strip the guard bits from the current entry word and duplicate each data bit.
// Strip the guard bits from the current entry word and duplicate each data
// bit.
wait_random ( ) ;
uint32_t word = entry_log [ current ] & ~ guard_mask ;
word = ( ( word > > 1 ) | word ) & LOW_MASK ;
word = ( ( word > > 1 ) | word ) & LOW_MASK ;
word = word | ( word < < 1 ) ;
// Verify that the entry word has form 0*1*.
if ( ( word & ( word + 1 ) ) ! = 0 ) {
@ -705,12 +738,12 @@ static secbool pin_get_fails(uint32_t *ctr)
// Count the number of set bits in the two current words of the success log.
wait_random ( ) ;
* ctr = hamming_weight ( success_log [ current - 1 ] ^ entry_log [ current - 1 ] ) + hamming_weight ( success_log [ current ] ^ entry_log [ current ] ) ;
* ctr = hamming_weight ( success_log [ current - 1 ] ^ entry_log [ current - 1 ] ) +
hamming_weight ( success_log [ current ] ^ entry_log [ current ] ) ;
return sectrue ;
}
secbool storage_is_unlocked ( void )
{
secbool storage_is_unlocked ( void ) {
if ( sectrue ! = initialized ) {
return secfalse ;
}
@ -718,24 +751,25 @@ secbool storage_is_unlocked(void)
return unlocked ;
}
void storage_lock ( void )
{
void storage_lock ( void ) {
unlocked = secfalse ;
memzero ( cached_keys , sizeof ( cached_keys ) ) ;
memzero ( authentication_sum , sizeof ( authentication_sum ) ) ;
}
static secbool decrypt_dek ( const uint8_t * kek , const uint8_t * keiv )
{
static secbool decrypt_dek ( const uint8_t * kek , const uint8_t * keiv ) {
const void * buffer = NULL ;
uint16_t len = 0 ;
if ( sectrue ! = initialized | | sectrue ! = norcow_get ( EDEK_PVC_KEY , & buffer , & len ) | | len ! = RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE ) {
if ( sectrue ! = initialized | |
sectrue ! = norcow_get ( EDEK_PVC_KEY , & buffer , & len ) | |
len ! = RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE ) {
handle_fault ( " no EDEK " ) ;
return secfalse ;
}
const uint8_t * ekeys = ( const uint8_t * ) buffer + RANDOM_SALT_SIZE ;
const uint32_t * pvc = ( const uint32_t * ) buffer + ( RANDOM_SALT_SIZE + KEYS_SIZE ) / sizeof ( uint32_t ) ;
const uint8_t * ekeys = ( const uint8_t * ) buffer + RANDOM_SALT_SIZE ;
const uint32_t * pvc = ( const uint32_t * ) buffer +
( RANDOM_SALT_SIZE + KEYS_SIZE ) / sizeof ( uint32_t ) ;
_Static_assert ( ( ( RANDOM_SALT_SIZE + KEYS_SIZE ) & 3 ) = = 0 , " PVC unaligned " ) ;
_Static_assert ( ( PVC_SIZE & 3 ) = = 0 , " PVC size unaligned " ) ;
@ -743,13 +777,15 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
uint8_t tag [ POLY1305_TAG_SIZE ] __attribute__ ( ( aligned ( sizeof ( uint32_t ) ) ) ) ;
chacha20poly1305_ctx ctx ;
// Decrypt the data encryption key and the storage authentication key and check the PIN verification code.
// Decrypt the data encryption key and the storage authentication key and
// check the PIN verification code.
rfc7539_init ( & ctx , kek , keiv ) ;
chacha20poly1305_decrypt ( & ctx , ekeys , keys , KEYS_SIZE ) ;
rfc7539_finish ( & ctx , 0 , KEYS_SIZE , tag ) ;
memzero ( & ctx , sizeof ( ctx ) ) ;
wait_random ( ) ;
if ( secequal32 ( ( const uint32_t * ) tag , pvc , PVC_SIZE / sizeof ( uint32_t ) ) ! = sectrue ) {
if ( secequal32 ( ( const uint32_t * ) tag , pvc , PVC_SIZE / sizeof ( uint32_t ) ) ! =
sectrue ) {
memzero ( keys , sizeof ( keys ) ) ;
memzero ( tag , sizeof ( tag ) ) ;
return secfalse ;
@ -759,9 +795,12 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
memzero ( tag , sizeof ( tag ) ) ;
// Check that the authenticated version number matches the norcow version.
// NOTE: storage_get_encrypted() calls auth_get(), which initializes the authentication_sum.
// NOTE: storage_get_encrypted() calls auth_get(), which initializes the
// authentication_sum.
uint32_t version ;
if ( sectrue ! = storage_get_encrypted ( VERSION_KEY , & version , sizeof ( version ) , & len ) | | len ! = sizeof ( version ) | | version ! = norcow_active_version ) {
if ( sectrue ! =
storage_get_encrypted ( VERSION_KEY , & version , sizeof ( version ) , & len ) | |
len ! = sizeof ( version ) | | version ! = norcow_active_version ) {
handle_fault ( " storage version check " ) ;
return secfalse ;
}
@ -769,8 +808,7 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
return sectrue ;
}
static secbool unlock ( uint32_t pin )
{
static secbool unlock ( uint32_t pin ) {
if ( sectrue ! = initialized ) {
return secfalse ;
}
@ -786,7 +824,8 @@ static secbool unlock(uint32_t pin)
wait_random ( ) ;
if ( ctr > = PIN_MAX_TRIES ) {
storage_wipe ( ) ;
error_shutdown ( " Too many wrong PIN " , " attempts. Storage has " , " been wiped. " , NULL ) ;
error_shutdown ( " Too many wrong PIN " , " attempts. Storage has " , " been wiped. " ,
NULL ) ;
return secfalse ;
}
@ -810,17 +849,20 @@ static secbool unlock(uint32_t pin)
}
}
// Read the random salt from EDEK_PVC_KEY and use it to derive the KEK and KEIV from the PIN.
// Read the random salt from EDEK_PVC_KEY and use it to derive the KEK and
// KEIV from the PIN.
const void * salt = NULL ;
uint16_t len = 0 ;
if ( sectrue ! = initialized | | sectrue ! = norcow_get ( EDEK_PVC_KEY , & salt , & len ) | | len ! = RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE ) {
if ( sectrue ! = initialized | |
sectrue ! = norcow_get ( EDEK_PVC_KEY , & salt , & len ) | |
len ! = RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE ) {
memzero ( & pin , sizeof ( pin ) ) ;
handle_fault ( " no EDEK " ) ;
return secfalse ;
}
uint8_t kek [ SHA256_DIGEST_LENGTH ] ;
uint8_t keiv [ SHA256_DIGEST_LENGTH ] ;
derive_kek ( pin , ( const uint8_t * ) salt , kek , keiv ) ;
derive_kek ( pin , ( const uint8_t * ) salt , kek , keiv ) ;
memzero ( & pin , sizeof ( pin ) ) ;
// First, we increase PIN fail counter in storage, even before checking the
@ -843,7 +885,8 @@ static secbool unlock(uint32_t pin)
wait_random ( ) ;
if ( ctr + 1 > = PIN_MAX_TRIES ) {
storage_wipe ( ) ;
error_shutdown ( " Too many wrong PIN " , " attempts. Storage has " , " been wiped. " , NULL ) ;
error_shutdown ( " Too many wrong PIN " , " attempts. Storage has " ,
" been wiped. " , NULL ) ;
}
return secfalse ;
}
@ -856,8 +899,7 @@ static secbool unlock(uint32_t pin)
return pin_fails_reset ( ) ;
}
secbool storage_unlock ( uint32_t pin )
{
secbool storage_unlock ( uint32_t pin ) {
ui_total = DERIVE_SECS ;
ui_rem = ui_total ;
if ( pin = = PIN_EMPTY ) {
@ -877,8 +919,8 @@ secbool storage_unlock(uint32_t pin)
* If val_dest is not NULL and max_len > = len , then the data is decrypted
* to val_dest using cached_dek as the decryption key .
*/
static secbool storage_get_encrypted ( const uint16_t key , void * val_dest , const uint16_t max_len , uint16_t * len )
{
static secbool storage_get_encrypted ( const uint16_t key , void * val_dest ,
const uint16_t max_len , uint16_t * len ) {
const void * val_stored = NULL ;
if ( sectrue ! = auth_get ( key , & val_stored , len ) ) {
@ -899,14 +941,15 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const u
return secfalse ;
}
const uint8_t * iv = ( const uint8_t * ) val_stored ;
const uint8_t * tag_stored = ( const uint8_t * ) val_stored + CHACHA20_IV_SIZE ;
const uint8_t * ciphertext = ( const uint8_t * ) val_stored + CHACHA20_IV_SIZE + POLY1305_TAG_SIZE ;
const uint8_t * iv = ( const uint8_t * ) val_stored ;
const uint8_t * tag_stored = ( const uint8_t * ) val_stored + CHACHA20_IV_SIZE ;
const uint8_t * ciphertext =
( const uint8_t * ) val_stored + CHACHA20_IV_SIZE + POLY1305_TAG_SIZE ;
uint8_t tag_computed [ POLY1305_TAG_SIZE ] ;
chacha20poly1305_ctx ctx ;
rfc7539_init ( & ctx , cached_dek , iv ) ;
rfc7539_auth ( & ctx , ( const uint8_t * ) & key , sizeof ( key ) ) ;
chacha20poly1305_decrypt ( & ctx , ciphertext , ( uint8_t * ) val_dest , * len ) ;
rfc7539_auth ( & ctx , ( const uint8_t * ) & key , sizeof ( key ) ) ;
chacha20poly1305_decrypt ( & ctx , ciphertext , ( uint8_t * ) val_dest , * len ) ;
rfc7539_finish ( & ctx , sizeof ( key ) , * len , tag_computed ) ;
memzero ( & ctx , sizeof ( ctx ) ) ;
@ -926,15 +969,16 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const u
* Finds the data stored under key and writes its length to len . If val_dest is
* not NULL and max_len > = len , then the data is copied to val_dest .
*/
secbool storage_get ( const uint16_t key , void * val_dest , const uint16_t max_len , uint16_t * len )
{
secbool storage_get ( const uint16_t key , void * val_dest , const uint16_t max_len ,
uint16_t * len ) {
const uint8_t app = key > > 8 ;
// APP == 0 is reserved for PIN related values
if ( sectrue ! = initialized | | app = = APP_STORAGE ) {
return secfalse ;
}
// If the top bit of APP is set, then the value is not encrypted and can be read from a locked device.
// If the top bit of APP is set, then the value is not encrypted and can be
// read from a locked device.
secbool ret = secfalse ;
if ( ( app & FLAG_PUBLIC ) ! = 0 ) {
const void * val_stored = NULL ;
@ -960,16 +1004,18 @@ secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len,
}
/*
* Encrypts the data at val using cached_dek as the encryption key and stores the ciphertext under key .
* Encrypts the data at val using cached_dek as the encryption key and stores
* the ciphertext under key .
*/
static secbool storage_set_encrypted ( const uint16_t key , const void * val , const uint16_t len )
{
static secbool storage_set_encrypted ( const uint16_t key , const void * val ,
const uint16_t len ) {
if ( len > UINT16_MAX - CHACHA20_IV_SIZE - POLY1305_TAG_SIZE ) {
return secfalse ;
}
// Preallocate space on the flash storage.
if ( sectrue ! = auth_set ( key , NULL , CHACHA20_IV_SIZE + POLY1305_TAG_SIZE + len ) ) {
if ( sectrue ! =
auth_set ( key , NULL , CHACHA20_IV_SIZE + POLY1305_TAG_SIZE + len ) ) {
return secfalse ;
}
@ -985,11 +1031,14 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val, const
// Encrypt all blocks except for the last one.
chacha20poly1305_ctx ctx ;
rfc7539_init ( & ctx , cached_dek , buffer ) ;
rfc7539_auth ( & ctx , ( const uint8_t * ) & key , sizeof ( key ) ) ;
rfc7539_auth ( & ctx , ( const uint8_t * ) & key , sizeof ( key ) ) ;
size_t i ;
for ( i = 0 ; i + CHACHA20_BLOCK_SIZE < len ; i + = CHACHA20_BLOCK_SIZE , offset + = CHACHA20_BLOCK_SIZE ) {
chacha20poly1305_encrypt ( & ctx , ( ( const uint8_t * ) val ) + i , buffer , CHACHA20_BLOCK_SIZE ) ;
if ( sectrue ! = norcow_update_bytes ( key , offset , buffer , CHACHA20_BLOCK_SIZE ) ) {
for ( i = 0 ; i + CHACHA20_BLOCK_SIZE < len ;
i + = CHACHA20_BLOCK_SIZE , offset + = CHACHA20_BLOCK_SIZE ) {
chacha20poly1305_encrypt ( & ctx , ( ( const uint8_t * ) val ) + i , buffer ,
CHACHA20_BLOCK_SIZE ) ;
if ( sectrue ! =
norcow_update_bytes ( key , offset , buffer , CHACHA20_BLOCK_SIZE ) ) {
memzero ( & ctx , sizeof ( ctx ) ) ;
memzero ( buffer , sizeof ( buffer ) ) ;
return secfalse ;
@ -997,7 +1046,7 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val, const
}
// Encrypt final block and compute message authentication tag.
chacha20poly1305_encrypt ( & ctx , ( ( const uint8_t * ) val ) + i , buffer , len - i ) ;
chacha20poly1305_encrypt ( & ctx , ( ( const uint8_t * ) val ) + i , buffer , len - i ) ;
secbool ret = norcow_update_bytes ( key , offset , buffer , len - i ) ;
if ( sectrue = = ret ) {
rfc7539_finish ( & ctx , sizeof ( key ) , len , buffer ) ;
@ -1008,8 +1057,7 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val, const
return ret ;
}
secbool storage_set ( const uint16_t key , const void * val , const uint16_t len )
{
secbool storage_set ( const uint16_t key , const void * val , const uint16_t len ) {
const uint8_t app = key > > 8 ;
// APP == 0 is reserved for PIN related values
@ -1030,8 +1078,7 @@ secbool storage_set(const uint16_t key, const void *val, const uint16_t len)
return ret ;
}
secbool storage_delete ( const uint16_t key )
{
secbool storage_delete ( const uint16_t key ) {
const uint8_t app = key > > 8 ;
// APP == 0 is reserved for storage related values
@ -1050,8 +1097,7 @@ secbool storage_delete(const uint16_t key)
return ret ;
}
secbool storage_set_counter ( const uint16_t key , const uint32_t count )
{
secbool storage_set_counter ( const uint16_t key , const uint32_t count ) {
const uint8_t app = key > > 8 ;
if ( ( app & FLAG_PUBLIC ) = = 0 ) {
return secfalse ;
@ -1065,11 +1111,11 @@ secbool storage_set_counter(const uint16_t key, const uint32_t count)
return storage_set ( key , value , sizeof ( value ) ) ;
}
secbool storage_next_counter ( const uint16_t key , uint32_t * count )
{
secbool storage_next_counter ( const uint16_t key , uint32_t * count ) {
const uint8_t app = key > > 8 ;
// APP == 0 is reserved for PIN related values
if ( sectrue ! = initialized | | app = = APP_STORAGE | | ( app & FLAG_PUBLIC ) = = 0 ) {
if ( sectrue ! = initialized | | app = = APP_STORAGE | |
( app & FLAG_PUBLIC ) = = 0 ) {
return secfalse ;
}
@ -1079,7 +1125,7 @@ secbool storage_next_counter(const uint16_t key, uint32_t *count)
uint16_t len = 0 ;
const uint32_t * val_stored = NULL ;
if ( sectrue ! = norcow_get ( key , ( const void * * ) & val_stored , & len ) ) {
if ( sectrue ! = norcow_get ( key , ( const void * * ) & val_stored , & len ) ) {
* count = 0 ;
return storage_set_counter ( key , 0 ) ;
}
@ -1104,22 +1150,21 @@ secbool storage_next_counter(const uint16_t key, uint32_t *count)
}
}
secbool storage_has_pin ( void )
{
secbool storage_has_pin ( void ) {
if ( sectrue ! = initialized ) {
return secfalse ;
}
const void * val = NULL ;
uint16_t len ;
if ( sectrue ! = norcow_get ( PIN_NOT_SET_KEY , & val , & len ) | | ( len > 0 & & * ( uint8_t * ) val ! = FALSE_BYTE ) ) {
if ( sectrue ! = norcow_get ( PIN_NOT_SET_KEY , & val , & len ) | |
( len > 0 & & * ( uint8_t * ) val ! = FALSE_BYTE ) ) {
return secfalse ;
}
return sectrue ;
}
uint32_t storage_get_pin_rem ( void )
{
uint32_t storage_get_pin_rem ( void ) {
if ( sectrue ! = initialized ) {
return 0 ;
}
@ -1131,15 +1176,15 @@ uint32_t storage_get_pin_rem(void)
return PIN_MAX_TRIES - ctr ;
}
secbool storage_change_pin ( uint32_t oldpin , uint32_t newpin )
{
secbool storage_change_pin ( uint32_t oldpin , uint32_t newpin ) {
if ( sectrue ! = initialized ) {
return secfalse ;
}
ui_total = 2 * DERIVE_SECS ;
ui_rem = ui_total ;
ui_message = ( oldpin ! = PIN_EMPTY & & newpin = = PIN_EMPTY ) ? VERIFYING_PIN_MSG : PROCESSING_MSG ;
ui_message = ( oldpin ! = PIN_EMPTY & & newpin = = PIN_EMPTY ) ? VERIFYING_PIN_MSG
: PROCESSING_MSG ;
if ( sectrue ! = unlock ( oldpin ) ) {
return secfalse ;
@ -1150,8 +1195,7 @@ secbool storage_change_pin(uint32_t oldpin, uint32_t newpin)
return ret ;
}
void storage_wipe ( void )
{
void storage_wipe ( void ) {
norcow_wipe ( ) ;
norcow_active_version = NORCOW_VERSION ;
memzero ( authentication_sum , sizeof ( authentication_sum ) ) ;
@ -1159,17 +1203,19 @@ void storage_wipe(void)
init_wiped_storage ( ) ;
}
static void __handle_fault ( const char * msg , const char * file , int line , const char * func )
{
static void __handle_fault ( const char * msg , const char * file , int line ,
const char * func ) {
static secbool in_progress = secfalse ;
// If fault handling is already in progress, then we are probably facing a fault injection attack, so wipe.
// If fault handling is already in progress, then we are probably facing a
// fault injection attack, so wipe.
if ( secfalse ! = in_progress ) {
storage_wipe ( ) ;
__fatal_error ( " Fault detected " , msg , file , line , func ) ;
}
// We use the PIN fail counter as a fault counter. Increment the counter, check that it was incremented and halt.
// We use the PIN fail counter as a fault counter. Increment the counter,
// check that it was incremented and halt.
in_progress = sectrue ;
uint32_t ctr ;
if ( sectrue ! = pin_get_fails ( & ctr ) ) {
@ -1190,10 +1236,10 @@ static void __handle_fault(const char *msg, const char *file, int line, const ch
}
/*
* Reads the PIN fail counter in version 0 format . Returns the current number of failed PIN entries .
* Reads the PIN fail counter in version 0 format . Returns the current number of
* failed PIN entries .
*/
static secbool v0_pin_get_fails ( uint32_t * ctr )
{
static secbool v0_pin_get_fails ( uint32_t * ctr ) {
const uint16_t V0_PIN_FAIL_KEY = 0x0001 ;
// The PIN_FAIL_KEY points to an area of words, initialized to
// 0xffffffff (meaning no PIN failures). The first non-zero word
@ -1208,7 +1254,7 @@ static secbool v0_pin_get_fails(uint32_t *ctr)
uint16_t len = 0 ;
if ( secfalse ! = norcow_get ( V0_PIN_FAIL_KEY , & val , & len ) ) {
for ( unsigned int i = 0 ; i < len / sizeof ( uint32_t ) ; i + + ) {
uint32_t word = ( ( const uint32_t * ) val ) [ i ] ;
uint32_t word = ( ( const uint32_t * ) val ) [ i ] ;
if ( word ! = 0 ) {
* ctr = hamming_weight ( ~ word ) ;
return sectrue ;
@ -1221,8 +1267,7 @@ static secbool v0_pin_get_fails(uint32_t *ctr)
return sectrue ;
}
static secbool storage_upgrade ( void )
{
static secbool storage_upgrade ( void ) {
const uint16_t V0_PIN_KEY = 0x0000 ;
const uint16_t V0_PIN_FAIL_KEY = 0x0001 ;
uint16_t key = 0 ;
@ -1237,7 +1282,8 @@ static secbool storage_upgrade(void)
// Set the new storage version number.
uint32_t version = NORCOW_VERSION ;
if ( sectrue ! = storage_set_encrypted ( VERSION_KEY , & version , sizeof ( version ) ) ) {
if ( sectrue ! =
storage_set_encrypted ( VERSION_KEY , & version , sizeof ( version ) ) ) {
return secfalse ;
}
@ -1246,7 +1292,7 @@ static secbool storage_upgrade(void)
ui_rem = ui_total ;
ui_message = PROCESSING_MSG ;
if ( sectrue = = norcow_get ( V0_PIN_KEY , & val , & len ) ) {
set_pin ( * ( const uint32_t * ) val ) ;
set_pin ( * ( const uint32_t * ) val ) ;
} else {
set_pin ( PIN_EMPTY ) ;
}