mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 04:18:10 +00:00
refactor(storage): Simplify progress callbacks and expose constants.
This commit is contained in:
parent
6ca1182d85
commit
91592717da
@ -78,17 +78,9 @@ const uint32_t V0_PIN_EMPTY = 1;
|
|||||||
// up constant storage space.
|
// up constant storage space.
|
||||||
#define MAX_WIPE_CODE_LEN 50
|
#define MAX_WIPE_CODE_LEN 50
|
||||||
|
|
||||||
// Maximum number of failed unlock attempts.
|
|
||||||
// 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.
|
// The total number of iterations to use in PBKDF2.
|
||||||
#define PIN_ITER_COUNT 20000
|
#define PIN_ITER_COUNT 20000
|
||||||
|
|
||||||
// The number of seconds required to derive the KEK and KEIV.
|
|
||||||
#define DERIVE_SECS 1
|
|
||||||
|
|
||||||
// The length of the guard key in words.
|
// The length of the guard key in words.
|
||||||
#define GUARD_KEY_WORDS 1
|
#define GUARD_KEY_WORDS 1
|
||||||
|
|
||||||
@ -101,9 +93,6 @@ const uint32_t V0_PIN_EMPTY = 1;
|
|||||||
// The length of the hashed hardware salt in bytes.
|
// The length of the hashed hardware salt in bytes.
|
||||||
#define HARDWARE_SALT_SIZE SHA256_DIGEST_LENGTH
|
#define HARDWARE_SALT_SIZE SHA256_DIGEST_LENGTH
|
||||||
|
|
||||||
// The length of the random salt in bytes.
|
|
||||||
#define RANDOM_SALT_SIZE 4
|
|
||||||
|
|
||||||
// The length of the data encryption key in bytes.
|
// The length of the data encryption key in bytes.
|
||||||
#define DEK_SIZE 32
|
#define DEK_SIZE 32
|
||||||
|
|
||||||
@ -472,54 +461,59 @@ static secbool is_not_wipe_code(const uint8_t *pin, size_t pin_len) {
|
|||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static secbool ui_progress(uint32_t elapsed_ms) {
|
||||||
|
// elapsed_ms = number of elapsed milliseconds in the ongoing substep.
|
||||||
|
if (ui_callback && ui_message) {
|
||||||
|
uint32_t progress = 0;
|
||||||
|
if (ui_total > 1000000) {
|
||||||
|
// Avoid overflow, precise enough.
|
||||||
|
progress = (ui_total - ui_rem) / (ui_total / 1000);
|
||||||
|
} else {
|
||||||
|
progress = ((ui_total - ui_rem) * 1000 + elapsed_ms) / ui_total;
|
||||||
|
}
|
||||||
|
return ui_callback(ui_rem - elapsed_ms / 1000, progress, ui_message);
|
||||||
|
} else {
|
||||||
|
return secfalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void derive_kek(const uint8_t *pin, size_t pin_len,
|
static void derive_kek(const uint8_t *pin, size_t pin_len,
|
||||||
const uint8_t *random_salt, const uint8_t *ext_salt,
|
const uint8_t *storage_salt, const uint8_t *ext_salt,
|
||||||
uint8_t kek[SHA256_DIGEST_LENGTH],
|
uint8_t kek[SHA256_DIGEST_LENGTH],
|
||||||
uint8_t keiv[SHA256_DIGEST_LENGTH]) {
|
uint8_t keiv[SHA256_DIGEST_LENGTH]) {
|
||||||
uint8_t salt[HARDWARE_SALT_SIZE + RANDOM_SALT_SIZE + EXTERNAL_SALT_SIZE] = {
|
uint8_t salt[HARDWARE_SALT_SIZE + STORAGE_SALT_SIZE + EXTERNAL_SALT_SIZE] = {
|
||||||
0};
|
0};
|
||||||
size_t salt_len = 0;
|
size_t salt_len = 0;
|
||||||
|
|
||||||
memcpy(salt + salt_len, hardware_salt, HARDWARE_SALT_SIZE);
|
memcpy(salt + salt_len, hardware_salt, HARDWARE_SALT_SIZE);
|
||||||
salt_len += HARDWARE_SALT_SIZE;
|
salt_len += HARDWARE_SALT_SIZE;
|
||||||
|
|
||||||
memcpy(salt + salt_len, random_salt, RANDOM_SALT_SIZE);
|
memcpy(salt + salt_len, storage_salt, STORAGE_SALT_SIZE);
|
||||||
salt_len += RANDOM_SALT_SIZE;
|
salt_len += STORAGE_SALT_SIZE;
|
||||||
|
|
||||||
if (ext_salt != NULL) {
|
if (ext_salt != NULL) {
|
||||||
memcpy(salt + salt_len, ext_salt, EXTERNAL_SALT_SIZE);
|
memcpy(salt + salt_len, ext_salt, EXTERNAL_SALT_SIZE);
|
||||||
salt_len += EXTERNAL_SALT_SIZE;
|
salt_len += EXTERNAL_SALT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t progress = (ui_total - ui_rem) * 1000 / ui_total;
|
ui_progress(0);
|
||||||
if (ui_callback && ui_message) {
|
|
||||||
ui_callback(ui_rem, progress, ui_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
PBKDF2_HMAC_SHA256_CTX ctx = {0};
|
PBKDF2_HMAC_SHA256_CTX ctx = {0};
|
||||||
pbkdf2_hmac_sha256_Init(&ctx, pin, pin_len, salt, salt_len, 1);
|
pbkdf2_hmac_sha256_Init(&ctx, pin, pin_len, salt, salt_len, 1);
|
||||||
for (int i = 1; i <= 5; i++) {
|
for (int i = 1; i <= 5; i++) {
|
||||||
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
|
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
|
||||||
if (ui_callback && ui_message) {
|
ui_progress(i * PIN_DERIVE_SECS * 100);
|
||||||
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_Final(&ctx, kek);
|
||||||
|
|
||||||
pbkdf2_hmac_sha256_Init(&ctx, pin, pin_len, salt, salt_len, 2);
|
pbkdf2_hmac_sha256_Init(&ctx, pin, pin_len, salt, salt_len, 2);
|
||||||
for (int i = 6; i <= 10; i++) {
|
for (int i = 6; i <= 10; i++) {
|
||||||
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
|
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
|
||||||
if (ui_callback && ui_message) {
|
ui_progress(i * PIN_DERIVE_SECS * 100);
|
||||||
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, keiv);
|
pbkdf2_hmac_sha256_Final(&ctx, keiv);
|
||||||
|
|
||||||
ui_rem -= DERIVE_SECS;
|
ui_rem -= PIN_DERIVE_SECS;
|
||||||
memzero(&ctx, sizeof(PBKDF2_HMAC_SHA256_CTX));
|
memzero(&ctx, sizeof(PBKDF2_HMAC_SHA256_CTX));
|
||||||
memzero(&salt, sizeof(salt));
|
memzero(&salt, sizeof(salt));
|
||||||
}
|
}
|
||||||
@ -527,24 +521,24 @@ static void derive_kek(const uint8_t *pin, size_t pin_len,
|
|||||||
static secbool set_pin(const uint8_t *pin, size_t pin_len,
|
static secbool set_pin(const uint8_t *pin, size_t pin_len,
|
||||||
const uint8_t *ext_salt) {
|
const uint8_t *ext_salt) {
|
||||||
// Encrypt the cached keys using the new PIN and set the new PVC.
|
// Encrypt the cached keys using the new PIN and set the new PVC.
|
||||||
uint8_t buffer[RANDOM_SALT_SIZE + KEYS_SIZE + POLY1305_TAG_SIZE] = {0};
|
uint8_t buffer[STORAGE_SALT_SIZE + KEYS_SIZE + POLY1305_TAG_SIZE] = {0};
|
||||||
uint8_t *rand_salt = buffer;
|
uint8_t *rand_salt = buffer;
|
||||||
uint8_t *ekeys = buffer + RANDOM_SALT_SIZE;
|
uint8_t *ekeys = buffer + STORAGE_SALT_SIZE;
|
||||||
uint8_t *pvc = buffer + RANDOM_SALT_SIZE + KEYS_SIZE;
|
uint8_t *pvc = buffer + STORAGE_SALT_SIZE + KEYS_SIZE;
|
||||||
|
|
||||||
uint8_t kek[SHA256_DIGEST_LENGTH] = {0};
|
uint8_t kek[SHA256_DIGEST_LENGTH] = {0};
|
||||||
uint8_t keiv[SHA256_DIGEST_LENGTH] = {0};
|
uint8_t keiv[SHA256_DIGEST_LENGTH] = {0};
|
||||||
chacha20poly1305_ctx ctx = {0};
|
chacha20poly1305_ctx ctx = {0};
|
||||||
random_buffer(rand_salt, RANDOM_SALT_SIZE);
|
random_buffer(rand_salt, STORAGE_SALT_SIZE);
|
||||||
derive_kek(pin, pin_len, rand_salt, ext_salt, kek, keiv);
|
derive_kek_set(pin, pin_len, rand_salt, ext_salt, kek, keiv);
|
||||||
rfc7539_init(&ctx, kek, keiv);
|
rfc7539_init(&ctx, kek, keiv);
|
||||||
memzero(kek, sizeof(kek));
|
memzero(kek, sizeof(kek));
|
||||||
memzero(keiv, sizeof(keiv));
|
memzero(keiv, sizeof(keiv));
|
||||||
chacha20poly1305_encrypt(&ctx, cached_keys, ekeys, KEYS_SIZE);
|
chacha20poly1305_encrypt(&ctx, cached_keys, ekeys, KEYS_SIZE);
|
||||||
rfc7539_finish(&ctx, 0, KEYS_SIZE, pvc);
|
rfc7539_finish(&ctx, 0, KEYS_SIZE, pvc);
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
secbool ret =
|
secbool ret = norcow_set(EDEK_PVC_KEY, buffer,
|
||||||
norcow_set(EDEK_PVC_KEY, buffer, RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE);
|
STORAGE_SALT_SIZE + KEYS_SIZE + PVC_SIZE);
|
||||||
memzero(buffer, sizeof(buffer));
|
memzero(buffer, sizeof(buffer));
|
||||||
|
|
||||||
if (ret == sectrue) {
|
if (ret == sectrue) {
|
||||||
@ -668,7 +662,7 @@ static void init_wiped_storage(void) {
|
|||||||
ensure(set_wipe_code(WIPE_CODE_EMPTY, WIPE_CODE_EMPTY_LEN),
|
ensure(set_wipe_code(WIPE_CODE_EMPTY, WIPE_CODE_EMPTY_LEN),
|
||||||
"set_wipe_code failed");
|
"set_wipe_code failed");
|
||||||
|
|
||||||
ui_total = DERIVE_SECS;
|
ui_total = PIN_DERIVE_SECS;
|
||||||
ui_rem = ui_total;
|
ui_rem = ui_total;
|
||||||
ui_message = PROCESSING_MSG;
|
ui_message = PROCESSING_MSG;
|
||||||
ensure(set_pin(PIN_EMPTY, PIN_EMPTY_LEN, NULL), "init_pin failed");
|
ensure(set_pin(PIN_EMPTY, PIN_EMPTY_LEN, NULL), "init_pin failed");
|
||||||
@ -956,15 +950,15 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv) {
|
|||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
if (sectrue != initialized ||
|
if (sectrue != initialized ||
|
||||||
sectrue != norcow_get(EDEK_PVC_KEY, &buffer, &len) ||
|
sectrue != norcow_get(EDEK_PVC_KEY, &buffer, &len) ||
|
||||||
len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
|
len != STORAGE_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
|
||||||
handle_fault("no EDEK");
|
handle_fault("no EDEK");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t *ekeys = (const uint8_t *)buffer + RANDOM_SALT_SIZE;
|
const uint8_t *ekeys = (const uint8_t *)buffer + STORAGE_SALT_SIZE;
|
||||||
const uint32_t *pvc = (const uint32_t *)buffer +
|
const uint32_t *pvc = (const uint32_t *)buffer +
|
||||||
(RANDOM_SALT_SIZE + KEYS_SIZE) / sizeof(uint32_t);
|
(STORAGE_SALT_SIZE + KEYS_SIZE) / sizeof(uint32_t);
|
||||||
_Static_assert(((RANDOM_SALT_SIZE + KEYS_SIZE) & 3) == 0, "PVC unaligned");
|
_Static_assert(((STORAGE_SALT_SIZE + KEYS_SIZE) & 3) == 0, "PVC unaligned");
|
||||||
_Static_assert((PVC_SIZE & 3) == 0, "PVC size unaligned");
|
_Static_assert((PVC_SIZE & 3) == 0, "PVC size unaligned");
|
||||||
|
|
||||||
uint8_t keys[KEYS_SIZE] = {0};
|
uint8_t keys[KEYS_SIZE] = {0};
|
||||||
@ -1006,8 +1000,8 @@ static secbool unlock(const uint8_t *pin, size_t pin_len,
|
|||||||
// storage_upgrade_unlocked().
|
// storage_upgrade_unlocked().
|
||||||
uint32_t legacy_pin = 0;
|
uint32_t legacy_pin = 0;
|
||||||
if (get_lock_version() <= 2) {
|
if (get_lock_version() <= 2) {
|
||||||
ui_total += DERIVE_SECS;
|
ui_total += PIN_DERIVE_SECS;
|
||||||
ui_rem += DERIVE_SECS;
|
ui_rem += PIN_DERIVE_SECS;
|
||||||
legacy_pin = pin_to_int(pin, pin_len);
|
legacy_pin = pin_to_int(pin, pin_len);
|
||||||
unlock_pin = (const uint8_t *)&legacy_pin;
|
unlock_pin = (const uint8_t *)&legacy_pin;
|
||||||
unlock_pin_len = sizeof(legacy_pin);
|
unlock_pin_len = sizeof(legacy_pin);
|
||||||
@ -1034,20 +1028,12 @@ static secbool unlock(const uint8_t *pin, size_t pin_len,
|
|||||||
// Sleep for 2^ctr - 1 seconds before checking the PIN.
|
// Sleep for 2^ctr - 1 seconds before checking the PIN.
|
||||||
uint32_t wait = (1 << ctr) - 1;
|
uint32_t wait = (1 << ctr) - 1;
|
||||||
ui_total += wait;
|
ui_total += wait;
|
||||||
uint32_t progress = 0;
|
|
||||||
for (ui_rem = ui_total; ui_rem > ui_total - wait; ui_rem--) {
|
for (ui_rem = ui_total; ui_rem > ui_total - wait; ui_rem--) {
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
if (ui_callback && ui_message) {
|
if (sectrue == ui_progress(i * 100)) {
|
||||||
if (ui_total > 1000000) { // precise enough
|
|
||||||
progress = (ui_total - ui_rem) / (ui_total / 1000);
|
|
||||||
} else {
|
|
||||||
progress = ((ui_total - ui_rem) * 10 + i) * 100 / ui_total;
|
|
||||||
}
|
|
||||||
if (sectrue == ui_callback(ui_rem, progress, ui_message)) {
|
|
||||||
memzero(&legacy_pin, sizeof(legacy_pin));
|
memzero(&legacy_pin, sizeof(legacy_pin));
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
hal_delay(100);
|
hal_delay(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1058,7 +1044,7 @@ static secbool unlock(const uint8_t *pin, size_t pin_len,
|
|||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
if (sectrue != initialized ||
|
if (sectrue != initialized ||
|
||||||
sectrue != norcow_get(EDEK_PVC_KEY, &rand_salt, &len) ||
|
sectrue != norcow_get(EDEK_PVC_KEY, &rand_salt, &len) ||
|
||||||
len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
|
len != STORAGE_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
|
||||||
memzero(&legacy_pin, sizeof(legacy_pin));
|
memzero(&legacy_pin, sizeof(legacy_pin));
|
||||||
handle_fault("no EDEK");
|
handle_fault("no EDEK");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
@ -1118,7 +1104,7 @@ secbool storage_unlock(const uint8_t *pin, size_t pin_len,
|
|||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_total = DERIVE_SECS;
|
ui_total = PIN_DERIVE_SECS;
|
||||||
ui_rem = ui_total;
|
ui_rem = ui_total;
|
||||||
if (pin_len == 0) {
|
if (pin_len == 0) {
|
||||||
if (ui_message == NULL) {
|
if (ui_message == NULL) {
|
||||||
@ -1412,7 +1398,7 @@ secbool storage_change_pin(const uint8_t *oldpin, size_t oldpin_len,
|
|||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_total = 2 * DERIVE_SECS;
|
ui_total = 2 * PIN_DERIVE_SECS;
|
||||||
ui_rem = ui_total;
|
ui_rem = ui_total;
|
||||||
ui_message =
|
ui_message =
|
||||||
(oldpin_len != 0 && newpin_len == 0) ? VERIFYING_PIN_MSG : PROCESSING_MSG;
|
(oldpin_len != 0 && newpin_len == 0) ? VERIFYING_PIN_MSG : PROCESSING_MSG;
|
||||||
@ -1461,7 +1447,7 @@ secbool storage_change_wipe_code(const uint8_t *pin, size_t pin_len,
|
|||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_total = DERIVE_SECS;
|
ui_total = PIN_DERIVE_SECS;
|
||||||
ui_rem = ui_total;
|
ui_rem = ui_total;
|
||||||
ui_message =
|
ui_message =
|
||||||
(pin_len != 0 && wipe_code_len == 0) ? VERIFYING_PIN_MSG : PROCESSING_MSG;
|
(pin_len != 0 && wipe_code_len == 0) ? VERIFYING_PIN_MSG : PROCESSING_MSG;
|
||||||
@ -1619,7 +1605,7 @@ static secbool storage_upgrade(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set EDEK_PVC_KEY and PIN_NOT_SET_KEY.
|
// Set EDEK_PVC_KEY and PIN_NOT_SET_KEY.
|
||||||
ui_total = DERIVE_SECS;
|
ui_total = PIN_DERIVE_SECS;
|
||||||
ui_rem = ui_total;
|
ui_rem = ui_total;
|
||||||
ui_message = PROCESSING_MSG;
|
ui_message = PROCESSING_MSG;
|
||||||
secbool found = norcow_get(V0_PIN_KEY, &val, &len);
|
secbool found = norcow_get(V0_PIN_KEY, &val, &len);
|
||||||
|
@ -41,6 +41,21 @@
|
|||||||
extern const uint8_t *PIN_EMPTY;
|
extern const uint8_t *PIN_EMPTY;
|
||||||
#define PIN_EMPTY_LEN 0
|
#define PIN_EMPTY_LEN 0
|
||||||
|
|
||||||
|
// Maximum number of failed unlock attempts.
|
||||||
|
// NOTE: The PIN counter logic relies on this constant being less than or equal
|
||||||
|
// to 16.
|
||||||
|
#define PIN_MAX_TRIES 16
|
||||||
|
|
||||||
|
// The length of the random salt in bytes.
|
||||||
|
#define STORAGE_SALT_SIZE 4
|
||||||
|
|
||||||
|
// The number of seconds required to derive the KEK and KEIV.
|
||||||
|
#if USE_OPTIGA
|
||||||
|
#define PIN_DERIVE_SECS 3
|
||||||
|
#else
|
||||||
|
#define PIN_DERIVE_SECS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef secbool (*PIN_UI_WAIT_CALLBACK)(uint32_t wait, uint32_t progress,
|
typedef secbool (*PIN_UI_WAIT_CALLBACK)(uint32_t wait, uint32_t progress,
|
||||||
const char *message);
|
const char *message);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user