You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/storage/tests/python/src/pin_log_blockwise.py

60 lines
1.4 KiB

from . import consts
PIN_LOG_HALFWORDS = int(3 * (consts.WORD_SIZE / 2))
def expand_counter(c: int) -> int:
c = ((c << 4) | c) & 0x0F0F
c = ((c << 2) | c) & 0x3333
c = ((c << 1) | c) & 0x5555
c = ((c << 1) | c) ^ 0xAAAA
return c
def compress_counter(c: int) -> int:
c = c & 0x5555
c = ((c >> 1) | c) & 0x3333
c = ((c >> 2) | c) & 0x0F0F
c = ((c >> 4) | c) & 0x00FF
return c
class PinLogBlockwise:
def __init__(self, norcow):
self.norcow = norcow
def init(self):
self._write_log(0)
def write_attempt(self):
self._write_log(self.get_failures_count() + 1)
def write_success(self):
self._write_log(0)
def get_failures_count(self) -> int:
return self._get_logs()
def _get_logs(self) -> int:
logs = self.norcow.get(consts.PIN_LOG_KEY)
if logs is None:
raise ValueError("No PIN logs")
ctr = int.from_bytes(logs[:2], "little")
fails = compress_counter(ctr)
for i in range(2, PIN_LOG_HALFWORDS, 2):
if fails != compress_counter(int.from_bytes(logs[i : i + 2], "little")):
raise ValueError("PIN logs corrupted")
return fails
def _write_log(self, fails: int):
ctr = expand_counter(fails)
data = ctr.to_bytes(2, "little")
for _ in range(1, PIN_LOG_HALFWORDS):
data += ctr.to_bytes(2, "little")
self.norcow.set(consts.PIN_LOG_KEY, data)