#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); }