forked from trezor/trezor-firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pinlogs_blockwise.h
87 lines (65 loc) · 1.92 KB
/
pinlogs_blockwise.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#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);
}