mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-10 09:39:00 +00:00
88 lines
1.9 KiB
C
88 lines
1.9 KiB
C
|
|
||
|
#if FLASH_BLOCK_WORDS <= 1
|
||
|
#error "FLASH_BLOCK_WORDS must be at least 2 to fit the counter and header"
|
||
|
#endif
|
||
|
|
||
|
#define PIN_LOG_HALFWORDS (((FLASH_BLOCK_WORDS - 1) * sizeof(uint32_t)) / 2)
|
||
|
|
||
|
static uint16_t expand_counter(uint16_t c) {
|
||
|
c = ((c << 4) | c) & 0x0f0f;
|
||
|
c = ((c << 2) | c) & 0x3333;
|
||
|
c = ((c << 1) | c) & 0x5555;
|
||
|
c = ((c << 1) | c) ^ 0xaaaa;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
static uint16_t compress_counter(uint16_t c) {
|
||
|
if (((c ^ (c << 1)) & 0xAAAA) != 0xAAAA) {
|
||
|
handle_fault("ill-formed counter");
|
||
|
}
|
||
|
c = c & 0x5555;
|
||
|
c = ((c >> 1) | c) & 0x3333;
|
||
|
c = ((c >> 2) | c) & 0x0f0f;
|
||
|
c = ((c >> 4) | c) & 0x00ff;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
static secbool pin_get_fails(uint32_t *ctr) {
|
||
|
const void *logs = NULL;
|
||
|
uint16_t len = 0;
|
||
|
|
||
|
wait_random();
|
||
|
|
||
|
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) ||
|
||
|
len != PIN_LOG_HALFWORDS * sizeof(uint16_t)) {
|
||
|
handle_fault("no PIN logs");
|
||
|
return secfalse;
|
||
|
}
|
||
|
|
||
|
uint16_t c = compress_counter(((uint16_t *)logs)[0]);
|
||
|
|
||
|
uint16_t correct_bytes_cnt = 0;
|
||
|
|
||
|
for (uint8_t i = 0; i < PIN_LOG_HALFWORDS; i++) {
|
||
|
wait_random();
|
||
|
correct_bytes_cnt += compress_counter(((uint16_t *)logs)[i]) == c;
|
||
|
*ctr = c;
|
||
|
}
|
||
|
|
||
|
if (correct_bytes_cnt != PIN_LOG_HALFWORDS) {
|
||
|
handle_fault("PIN logs corrupted");
|
||
|
return secfalse;
|
||
|
}
|
||
|
|
||
|
return sectrue * (correct_bytes_cnt == PIN_LOG_HALFWORDS);
|
||
|
}
|
||
|
|
||
|
static secbool pin_logs_init(uint32_t fails) {
|
||
|
wait_random();
|
||
|
|
||
|
uint16_t logs[PIN_LOG_HALFWORDS];
|
||
|
uint16_t ctr = expand_counter(fails);
|
||
|
|
||
|
for (uint8_t i = 0; i < PIN_LOG_HALFWORDS; i++) {
|
||
|
logs[i] = ctr;
|
||
|
}
|
||
|
|
||
|
if (fails != compress_counter(ctr)) {
|
||
|
handle_fault("PIN logs increase failed");
|
||
|
return secfalse;
|
||
|
}
|
||
|
|
||
|
return norcow_set(PIN_LOGS_KEY, logs, sizeof(logs));
|
||
|
}
|
||
|
|
||
|
static secbool pin_fails_reset(void) { return pin_logs_init(0); }
|
||
|
|
||
|
secbool pin_fails_increase(void) {
|
||
|
uint32_t fails;
|
||
|
|
||
|
if (sectrue != pin_get_fails(&fails)) {
|
||
|
return secfalse;
|
||
|
}
|
||
|
|
||
|
fails++;
|
||
|
|
||
|
return pin_logs_init(fails);
|
||
|
}
|