1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-04 22:02:34 +00:00

feat(core): support quad-word only flash

[no changelog]
This commit is contained in:
tychovrahe 2023-07-04 12:14:34 +02:00
parent 238e3fd7c1
commit 43d132acfa
3 changed files with 243 additions and 53 deletions

View File

@ -28,8 +28,6 @@
// NRCW = 4e524357 // NRCW = 4e524357
#define NORCOW_MAGIC_V0 ((uint32_t)0x5743524e) #define NORCOW_MAGIC_V0 ((uint32_t)0x5743524e)
#define NORCOW_WORD_SIZE (sizeof(uint32_t))
#define NORCOW_PREFIX_LEN NORCOW_WORD_SIZE
#define NORCOW_MAGIC_LEN NORCOW_WORD_SIZE #define NORCOW_MAGIC_LEN NORCOW_WORD_SIZE
#define NORCOW_VERSION_LEN NORCOW_WORD_SIZE #define NORCOW_VERSION_LEN NORCOW_WORD_SIZE
@ -39,10 +37,26 @@
// The key value which is used to indicate that the entry has been deleted. // The key value which is used to indicate that the entry has been deleted.
#define NORCOW_KEY_DELETED (0x0000) #define NORCOW_KEY_DELETED (0x0000)
#ifdef FLASH_BYTE_ACCESS
#define NORCOW_WORD_SIZE (sizeof(uint32_t))
#define NORCOW_PREFIX_LEN (NORCOW_WORD_SIZE)
#define NORCOW_KEY_LEN 2
#define NORCOW_LEN_LEN 2
#define ALIGN(X) ((X) = ((X) + 3) & ~3)
// The offset from the beginning of the sector where stored items start. // The offset from the beginning of the sector where stored items start.
#define NORCOW_STORAGE_START \ #define NORCOW_STORAGE_START \
(NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN) (NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN)
#else
#define NORCOW_WORD_SIZE (4 * sizeof(uint32_t))
#define NORCOW_PREFIX_LEN (2 * NORCOW_WORD_SIZE)
#define NORCOW_KEY_LEN 16
#define NORCOW_LEN_LEN 16
#define ALIGN(X) ((X) = ((X) + 0xF) & ~0xF)
// The offset from the beginning of the sector where stored items start.
#define NORCOW_STORAGE_START (NORCOW_HEADER_LEN + NORCOW_WORD_SIZE)
#endif
// The index of the active reading sector and writing sector. These should be // The index of the active reading sector and writing sector. These should be
// equal except when storage version upgrade or compaction is in progress. // equal except when storage version upgrade or compaction is in progress.
static uint8_t norcow_active_sector = 0; static uint8_t norcow_active_sector = 0;
@ -66,7 +80,8 @@ static const void *norcow_ptr(uint8_t sector, uint32_t offset, uint32_t size) {
/* /*
* Writes data to given sector, starting from offset * Writes data to given sector, starting from offset
*/ */
static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix, #ifdef FLASH_BYTE_ACCESS
static secbool norcow_write(uint8_t sector, uint32_t offset, uint16_t key,
const uint8_t *data, uint16_t len) { const uint8_t *data, uint16_t len) {
if (sector >= NORCOW_SECTOR_COUNT) { if (sector >= NORCOW_SECTOR_COUNT) {
return secfalse; return secfalse;
@ -76,6 +91,8 @@ static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix,
return secfalse; return secfalse;
} }
uint32_t prefix = ((uint32_t)len << 16) | key;
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
// write prefix // write prefix
@ -100,6 +117,62 @@ static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix,
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
return sectrue; return sectrue;
} }
#else
static secbool norcow_write(uint8_t sector, uint32_t offset, uint16_t key,
const uint8_t *data, uint16_t len) {
if (sector >= NORCOW_SECTOR_COUNT) {
return secfalse;
}
uint16_t len_adjusted = ((len) + 0xF) & ~0xF;
if (offset + NORCOW_PREFIX_LEN + len_adjusted > NORCOW_SECTOR_SIZE) {
return secfalse;
}
ensure(flash_unlock_write(), NULL);
uint32_t d[4];
d[0] = key;
d[1] = 0xFFFFFFFF;
d[2] = 0xFFFFFFFF;
d[3] = 0xFFFFFFFF;
// write key
ensure(flash_area_write_quadword(&STORAGE_AREAS[sector], offset, d), NULL);
offset += NORCOW_WORD_SIZE;
d[0] = len;
// write len
ensure(flash_area_write_quadword(&STORAGE_AREAS[sector], offset, d), NULL);
offset += NORCOW_WORD_SIZE;
if (data != NULL) {
// write data
for (uint16_t i = 0; i < len / NORCOW_WORD_SIZE;
i++, offset += NORCOW_WORD_SIZE) {
memcpy(d, data + i * NORCOW_WORD_SIZE, NORCOW_WORD_SIZE);
ensure(flash_area_write_quadword(&STORAGE_AREAS[sector], offset, d),
NULL);
}
memset(d, 0, sizeof(d));
// pad with zeroes
for (uint16_t i = 0; i < len % NORCOW_WORD_SIZE; i++) {
((uint8_t *)d)[i] = data[i + len - len % NORCOW_WORD_SIZE];
}
if (len % NORCOW_WORD_SIZE != 0) {
ensure(flash_area_write_quadword(&STORAGE_AREAS[sector], offset, d),
NULL);
}
} else {
offset += len;
}
ensure(flash_lock_write(), NULL);
return sectrue;
}
#endif
/* /*
* Erases sector (and sets a magic) * Erases sector (and sets a magic)
@ -126,15 +199,35 @@ static void erase_sector(uint8_t sector, secbool set_magic) {
#endif #endif
if (sectrue == set_magic) { if (sectrue == set_magic) {
ensure(norcow_write(sector, NORCOW_HEADER_LEN, NORCOW_MAGIC, NULL, 0), #ifdef FLASH_BYTE_ACCESS
"set magic failed"); ensure(flash_unlock_write(), NULL);
ensure(norcow_write(sector, NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN,
~NORCOW_VERSION, NULL, 0),
"set version failed");
}
}
#define ALIGN4(X) (X) = ((X) + 3) & ~3 ensure(flash_area_write_word(&STORAGE_AREAS[sector], NORCOW_HEADER_LEN,
NORCOW_MAGIC),
NULL);
ensure(flash_area_write_word(&STORAGE_AREAS[sector],
NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN,
~NORCOW_VERSION),
"set version failed");
ensure(flash_lock_write(), NULL);
#else
uint32_t d[4];
d[0] = NORCOW_MAGIC;
d[1] = ~NORCOW_VERSION;
d[2] = 0xFFFFFFFF;
d[3] = 0xFFFFFFFF;
ensure(flash_unlock_write(), NULL);
ensure(
flash_area_write_quadword(&STORAGE_AREAS[sector], NORCOW_HEADER_LEN, d),
"set magic and version failed");
ensure(flash_lock_write(), NULL);
#endif
}
}
/* /*
* Reads one item starting from offset * Reads one item starting from offset
@ -145,7 +238,7 @@ static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key,
const void *k = norcow_ptr(sector, *pos, 2); const void *k = norcow_ptr(sector, *pos, 2);
if (k == NULL) return secfalse; if (k == NULL) return secfalse;
*pos += 2; *pos += NORCOW_KEY_LEN;
memcpy(key, k, sizeof(uint16_t)); memcpy(key, k, sizeof(uint16_t));
if (*key == NORCOW_KEY_FREE) { if (*key == NORCOW_KEY_FREE) {
return secfalse; return secfalse;
@ -153,13 +246,13 @@ static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key,
const void *l = norcow_ptr(sector, *pos, 2); const void *l = norcow_ptr(sector, *pos, 2);
if (l == NULL) return secfalse; if (l == NULL) return secfalse;
*pos += 2; *pos += NORCOW_LEN_LEN;
memcpy(len, l, sizeof(uint16_t)); memcpy(len, l, sizeof(uint16_t));
*val = norcow_ptr(sector, *pos, *len); *val = norcow_ptr(sector, *pos, *len);
if (*val == NULL) return secfalse; if (*val == NULL) return secfalse;
*pos += *len; *pos += *len;
ALIGN4(*pos); ALIGN(*pos);
return sectrue; return sectrue;
} }
@ -168,10 +261,9 @@ static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key,
*/ */
static secbool write_item(uint8_t sector, uint32_t offset, uint16_t key, static secbool write_item(uint8_t sector, uint32_t offset, uint16_t key,
const void *val, uint16_t len, uint32_t *pos) { const void *val, uint16_t len, uint32_t *pos) {
uint32_t prefix = ((uint32_t)len << 16) | key;
*pos = offset + NORCOW_PREFIX_LEN + len; *pos = offset + NORCOW_PREFIX_LEN + len;
ALIGN4(*pos); ALIGN(*pos);
return norcow_write(sector, offset, prefix, val, len); return norcow_write(sector, offset, key, val, len);
} }
/* /*
@ -417,6 +509,7 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len,
return secfalse; return secfalse;
} }
const flash_area_t *area = &STORAGE_AREAS[norcow_write_sector];
secbool ret = secfalse; secbool ret = secfalse;
const void *ptr = NULL; const void *ptr = NULL;
uint16_t len_old = 0; uint16_t len_old = 0;
@ -428,19 +521,20 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len,
offset = offset =
(const uint8_t *)ptr - (const uint8_t *)ptr -
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE); (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE);
#ifdef FLASH_BYTE_ACCESS
if (val != NULL && len_old == len) { if (val != NULL && len_old == len) {
ret = sectrue; ret = sectrue;
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
for (uint16_t i = 0; i < len; i++) { for (uint16_t i = 0; i < len; i++) {
if (sectrue != if (sectrue != flash_area_write_byte(area, offset + i,
flash_area_write_byte(&STORAGE_AREAS[norcow_write_sector], ((const uint8_t *)val)[i])) {
offset + i, ((const uint8_t *)val)[i])) {
ret = secfalse; ret = secfalse;
break; break;
} }
} }
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
} }
#endif
} }
// If the update was not possible then write the entry as a new item. // If the update was not possible then write the entry as a new item.
@ -449,18 +543,26 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len,
if (sectrue == *found) { if (sectrue == *found) {
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
#ifdef FLASH_BYTE_ACCESS
// Update the prefix to indicate that the old item has been deleted. // Update the prefix to indicate that the old item has been deleted.
uint32_t prefix = (uint32_t)len_old << 16; uint32_t prefix = (uint32_t)len_old << 16;
ensure(flash_area_write_word(&STORAGE_AREAS[norcow_write_sector], ensure(flash_area_write_word(area, offset - NORCOW_PREFIX_LEN, prefix),
offset - NORCOW_PREFIX_LEN, prefix),
NULL); NULL);
#else
// Update the key to indicate that the old item has been deleted.
uint32_t d[4] = {0};
ensure(flash_area_write_quadword(area, offset - NORCOW_PREFIX_LEN, d),
NULL);
#endif
// Delete the old item data. // Delete the old item data.
uint32_t end = offset + len_old; uint32_t end = offset + len_old;
while (offset < end) { while (offset < end) {
ensure(flash_area_write_word(&STORAGE_AREAS[norcow_write_sector], #ifdef FLASH_BYTE_ACCESS
offset, 0x00000000), ensure(flash_area_write_word(area, offset, 0x00000000), NULL);
NULL); #else
ensure(flash_area_write_quadword(area, offset, d), NULL);
#endif
offset += NORCOW_WORD_SIZE; offset += NORCOW_WORD_SIZE;
} }
@ -490,6 +592,7 @@ secbool norcow_delete(uint16_t key) {
return secfalse; return secfalse;
} }
const flash_area_t *area = &STORAGE_AREAS[norcow_write_sector];
const void *ptr = NULL; const void *ptr = NULL;
uint16_t len = 0; uint16_t len = 0;
if (sectrue != find_item(norcow_write_sector, key, &ptr, &len)) { if (sectrue != find_item(norcow_write_sector, key, &ptr, &len)) {
@ -502,18 +605,24 @@ secbool norcow_delete(uint16_t key) {
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
#ifdef FLASH_BYTE_ACCESS
// Update the prefix to indicate that the item has been deleted. // Update the prefix to indicate that the item has been deleted.
uint32_t prefix = (uint32_t)len << 16; uint32_t prefix = (uint32_t)len << 16;
ensure(flash_area_write_word(&STORAGE_AREAS[norcow_write_sector], ensure(flash_area_write_word(area, offset - NORCOW_PREFIX_LEN, prefix), NULL);
offset - NORCOW_PREFIX_LEN, prefix), #else
NULL); // Update the key to indicate that the old item has been deleted.
uint32_t d[4] = {0};
ensure(flash_area_write_quadword(area, offset - NORCOW_PREFIX_LEN, d), NULL);
#endif
// Delete the item data. // Delete the item data.
uint32_t end = offset + len; uint32_t end = offset + len;
while (offset < end) { while (offset < end) {
ensure(flash_area_write_word(&STORAGE_AREAS[norcow_write_sector], offset, #ifdef FLASH_BYTE_ACCESS
0x00000000), ensure(flash_area_write_word(area, offset, 0x00000000), NULL);
NULL); #else
ensure(flash_area_write_quadword(area, offset, d), NULL);
#endif
offset += NORCOW_WORD_SIZE; offset += NORCOW_WORD_SIZE;
} }
@ -522,6 +631,7 @@ secbool norcow_delete(uint16_t key) {
return sectrue; return sectrue;
} }
#ifdef FLASH_BYTE_ACCESS
/* /*
* Update a word in flash at the given pointer. The pointer must point * Update a word in flash at the given pointer. The pointer must point
* into the NORCOW area. * into the NORCOW area.
@ -546,6 +656,7 @@ secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value) {
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
return sectrue; return sectrue;
} }
#endif
/* /*
* Update the value of the given key starting at the given offset. * Update the value of the given key starting at the given offset.
@ -564,12 +675,28 @@ secbool norcow_update_bytes(const uint16_t key, const uint16_t offset,
(const uint8_t *)ptr - (const uint8_t *)ptr -
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) + (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) +
offset; offset;
const flash_area_t *area = &STORAGE_AREAS[norcow_write_sector];
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
#ifdef FLASH_BYTE_ACCESS
for (uint16_t i = 0; i < len; i++, sector_offset++) { for (uint16_t i = 0; i < len; i++, sector_offset++) {
ensure(flash_area_write_byte(&STORAGE_AREAS[norcow_write_sector], ensure(flash_area_write_byte(area, sector_offset, data[i]), NULL);
sector_offset, data[i]),
NULL);
} }
#else
uint32_t d[4];
for (uint16_t i = 0; i < len / 16; i++) {
memcpy(d, data + i * 16, 16);
ensure(flash_area_write_quadword(area, sector_offset, d), NULL);
sector_offset += 16;
}
memset(d, 0, 16);
// pad with zeroes
for (uint16_t i = 0; i < len % 16; i++) {
((uint8_t *)d)[i] = data[i + len - len % 16];
}
if (len % 16 != 0) {
ensure(flash_area_write_quadword(area, sector_offset, d), NULL);
}
#endif
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
return sectrue; return sectrue;
} }

View File

@ -65,11 +65,13 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len,
*/ */
secbool norcow_delete(uint16_t key); secbool norcow_delete(uint16_t key);
#ifdef FLASH_BYTE_ACCESS
/* /*
* Update a word in flash in the given key at the given offset. * Update a word in flash in the given key at the given offset.
* Note that you can only change bits from 1 to 0. * Note that you can only change bits from 1 to 0.
*/ */
secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value); secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value);
#endif
/* /*
* Update the value of the given key starting at the given offset. * Update the value of the given key starting at the given offset.

View File

@ -126,6 +126,12 @@ const uint32_t V0_PIN_EMPTY = 1;
// The length of the ChaCha20 IV (aka nonce) in bytes as per RFC 7539. // The length of the ChaCha20 IV (aka nonce) in bytes as per RFC 7539.
#define CHACHA20_IV_SIZE 12 #define CHACHA20_IV_SIZE 12
#ifdef FLASH_BYTE_ACCESS
#define CHACHA20_IV_PADDING 0
#else
#define CHACHA20_IV_PADDING 4
#endif
// The length of the ChaCha20 block in bytes. // The length of the ChaCha20 block in bytes.
#define CHACHA20_BLOCK_SIZE 64 #define CHACHA20_BLOCK_SIZE 64
@ -145,7 +151,11 @@ const uint8_t WIPE_CODE_EMPTY[] = {0, 0, 0, 0};
#define V2_WIPE_CODE_EMPTY 0 #define V2_WIPE_CODE_EMPTY 0
// The length of the counter tail in words. // The length of the counter tail in words.
#ifdef FLASH_BYTE_ACCESS
#define COUNTER_TAIL_WORDS 2 #define COUNTER_TAIL_WORDS 2
#else
#define COUNTER_TAIL_WORDS 0
#endif
// Values used in the guard key integrity check. // Values used in the guard key integrity check.
#define GUARD_KEY_MODULUS 6311 #define GUARD_KEY_MODULUS 6311
@ -404,19 +414,22 @@ static secbool set_wipe_code(const uint8_t *wipe_code, size_t wipe_code_len) {
return secfalse; return secfalse;
} }
uint32_t data[(MAX_WIPE_CODE_LEN + WIPE_CODE_SALT_SIZE + WIPE_CODE_TAG_SIZE) /
sizeof(uint32_t)] = {0};
memcpy((uint8_t *)data, wipe_code, wipe_code_len);
memcpy((uint8_t *)data + wipe_code_len, salt_and_tag,
WIPE_CODE_SALT_SIZE + WIPE_CODE_TAG_SIZE);
// Write wipe code into the preallocated entry. // Write wipe code into the preallocated entry.
if (sectrue != if (sectrue != norcow_update_bytes(WIPE_CODE_DATA_KEY, 0, (uint8_t *)data,
norcow_update_bytes(WIPE_CODE_DATA_KEY, 0, wipe_code, wipe_code_len)) { wipe_code_len + WIPE_CODE_SALT_SIZE +
return secfalse; WIPE_CODE_TAG_SIZE)) {
} memzero(data, sizeof(data));
// Write salt and tag into the preallocated entry.
if (sectrue !=
norcow_update_bytes(WIPE_CODE_DATA_KEY, wipe_code_len, salt_and_tag,
WIPE_CODE_SALT_SIZE + WIPE_CODE_TAG_SIZE)) {
return secfalse; return secfalse;
} }
memzero(data, sizeof(data));
return sectrue; return sectrue;
} }
@ -710,6 +723,12 @@ static secbool pin_fails_reset(void) {
return secfalse; return secfalse;
} }
#ifndef FLASH_BYTE_ACCESS
uint32_t new_logs[GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS];
secbool edited = secfalse;
memcpy(new_logs, logs, len);
#endif
uint32_t guard_mask = 0; uint32_t guard_mask = 0;
uint32_t guard = 0; uint32_t guard = 0;
wait_random(); wait_random();
@ -723,16 +742,35 @@ static secbool pin_fails_reset(void) {
const uint32_t *entry_log = success_log + PIN_LOG_WORDS; const uint32_t *entry_log = success_log + PIN_LOG_WORDS;
for (size_t i = 0; i < PIN_LOG_WORDS; ++i) { for (size_t i = 0; i < PIN_LOG_WORDS; ++i) {
if (entry_log[i] == unused) { if (entry_log[i] == unused) {
#ifndef FLASH_BYTE_ACCESS
if (edited == sectrue) {
return norcow_set(PIN_LOGS_KEY, new_logs, sizeof(new_logs));
}
#endif
return sectrue; return sectrue;
} }
if (success_log[i] != guard) { if (success_log[i] != guard) {
#ifdef FLASH_BYTE_ACCESS
if (sectrue != norcow_update_word( if (sectrue != norcow_update_word(
PIN_LOGS_KEY, sizeof(uint32_t) * (i + GUARD_KEY_WORDS), PIN_LOGS_KEY, sizeof(uint32_t) * (i + GUARD_KEY_WORDS),
entry_log[i])) { entry_log[i])) {
return secfalse; return secfalse;
} }
#else
if (new_logs[(i + GUARD_KEY_WORDS)] != entry_log[i]) {
edited = sectrue;
new_logs[(i + GUARD_KEY_WORDS)] = entry_log[i];
}
#endif
} }
} }
#ifndef FLASH_BYTE_ACCESS
if (edited == sectrue) {
if (sectrue != norcow_set(PIN_LOGS_KEY, new_logs, sizeof(new_logs))) {
return secfalse;
}
}
#endif
return pin_logs_init(0); return pin_logs_init(0);
} }
@ -751,6 +789,11 @@ secbool storage_pin_fails_increase(void) {
return secfalse; return secfalse;
} }
#ifndef FLASH_BYTE_ACCESS
uint32_t new_logs[GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS];
memcpy(new_logs, logs, len);
#endif
uint32_t guard_mask = 0; uint32_t guard_mask = 0;
uint32_t guard = 0; uint32_t guard = 0;
wait_random(); wait_random();
@ -775,6 +818,7 @@ secbool storage_pin_fails_increase(void) {
word = (word >> 2) | (word >> 1); word = (word >> 2) | (word >> 1);
wait_random(); wait_random();
#ifdef FLASH_BYTE_ACCESS
if (sectrue != if (sectrue !=
norcow_update_word( norcow_update_word(
PIN_LOGS_KEY, PIN_LOGS_KEY,
@ -783,6 +827,14 @@ secbool storage_pin_fails_increase(void) {
handle_fault("PIN logs update"); handle_fault("PIN logs update");
return secfalse; return secfalse;
} }
#else
new_logs[(i + GUARD_KEY_WORDS + PIN_LOG_WORDS)] =
(word & ~guard_mask) | guard;
if (sectrue != norcow_set(PIN_LOGS_KEY, new_logs, sizeof(new_logs))) {
handle_fault("PIN logs update");
return secfalse;
}
#endif
return sectrue; return sectrue;
} }
} }
@ -1145,11 +1197,11 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest,
return secfalse; return secfalse;
} }
if (*len < CHACHA20_IV_SIZE + POLY1305_TAG_SIZE) { if (*len < CHACHA20_IV_SIZE + CHACHA20_IV_PADDING + POLY1305_TAG_SIZE) {
handle_fault("ciphertext length check"); handle_fault("ciphertext length check");
return secfalse; return secfalse;
} }
*len -= CHACHA20_IV_SIZE + POLY1305_TAG_SIZE; *len -= CHACHA20_IV_SIZE + CHACHA20_IV_PADDING + POLY1305_TAG_SIZE;
if (val_dest == NULL) { if (val_dest == NULL) {
return sectrue; return sectrue;
@ -1160,9 +1212,10 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest,
} }
const uint8_t *iv = (const uint8_t *)val_stored; 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 *tag_stored =
const uint8_t *ciphertext = (const uint8_t *)val_stored + CHACHA20_IV_SIZE + CHACHA20_IV_PADDING;
(const uint8_t *)val_stored + CHACHA20_IV_SIZE + POLY1305_TAG_SIZE; const uint8_t *ciphertext = (const uint8_t *)val_stored + CHACHA20_IV_SIZE +
CHACHA20_IV_PADDING + POLY1305_TAG_SIZE;
uint8_t tag_computed[POLY1305_TAG_SIZE] = {0}; uint8_t tag_computed[POLY1305_TAG_SIZE] = {0};
chacha20poly1305_ctx ctx = {0}; chacha20poly1305_ctx ctx = {0};
rfc7539_init(&ctx, cached_dek, iv); rfc7539_init(&ctx, cached_dek, iv);
@ -1229,24 +1282,27 @@ secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len,
*/ */
static secbool storage_set_encrypted(const uint16_t key, const void *val, static secbool storage_set_encrypted(const uint16_t key, const void *val,
const uint16_t len) { const uint16_t len) {
if (len > UINT16_MAX - CHACHA20_IV_SIZE - POLY1305_TAG_SIZE) { if (len >
UINT16_MAX - CHACHA20_IV_SIZE - CHACHA20_IV_PADDING - POLY1305_TAG_SIZE) {
return secfalse; return secfalse;
} }
// Preallocate space on the flash storage. // Preallocate space on the flash storage.
if (sectrue != if (sectrue != auth_set(key, NULL,
auth_set(key, NULL, CHACHA20_IV_SIZE + POLY1305_TAG_SIZE + len)) { CHACHA20_IV_SIZE + CHACHA20_IV_PADDING +
POLY1305_TAG_SIZE + len)) {
return secfalse; return secfalse;
} }
// Write the IV to the flash. // Write the IV to the flash.
uint8_t buffer[CHACHA20_BLOCK_SIZE] = {0}; uint8_t buffer[CHACHA20_BLOCK_SIZE + CHACHA20_IV_PADDING] = {0};
random_buffer(buffer, CHACHA20_IV_SIZE); random_buffer(buffer, CHACHA20_IV_SIZE);
uint16_t offset = 0; uint16_t offset = 0;
if (sectrue != norcow_update_bytes(key, offset, buffer, CHACHA20_IV_SIZE)) { if (sectrue != norcow_update_bytes(key, offset, buffer,
CHACHA20_IV_SIZE + CHACHA20_IV_PADDING)) {
return secfalse; return secfalse;
} }
offset += CHACHA20_IV_SIZE + POLY1305_TAG_SIZE; offset += CHACHA20_IV_SIZE + CHACHA20_IV_PADDING + POLY1305_TAG_SIZE;
// Encrypt all blocks except for the last one. // Encrypt all blocks except for the last one.
chacha20poly1305_ctx ctx = {0}; chacha20poly1305_ctx ctx = {0};
@ -1270,7 +1326,8 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val,
secbool ret = norcow_update_bytes(key, offset, buffer, len - i); secbool ret = norcow_update_bytes(key, offset, buffer, len - i);
if (sectrue == ret) { if (sectrue == ret) {
rfc7539_finish(&ctx, sizeof(key), len, buffer); rfc7539_finish(&ctx, sizeof(key), len, buffer);
ret = norcow_update_bytes(key, CHACHA20_IV_SIZE, buffer, POLY1305_TAG_SIZE); ret = norcow_update_bytes(key, CHACHA20_IV_SIZE + CHACHA20_IV_PADDING,
buffer, POLY1305_TAG_SIZE);
} }
memzero(&ctx, sizeof(ctx)); memzero(&ctx, sizeof(ctx));
memzero(buffer, sizeof(buffer)); memzero(buffer, sizeof(buffer));
@ -1372,7 +1429,11 @@ secbool storage_next_counter(const uint16_t key, uint32_t *count) {
// Value overflow. // Value overflow.
return secfalse; return secfalse;
} }
#ifdef FLASH_BYTE_ACCESS
return norcow_update_word(key, sizeof(uint32_t) * i, val_stored[i] >> 1); return norcow_update_word(key, sizeof(uint32_t) * i, val_stored[i] >> 1);
#else
return storage_set_counter(key, *count);
#endif
} else { } else {
return storage_set_counter(key, *count); return storage_set_counter(key, *count);
} }