1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-20 21:38:26 +00:00
trezor-firmware/core/embed/firmware/bootloader_hashes.py
2024-08-29 12:47:24 +02:00

113 lines
3.1 KiB
Python
Executable File

#!/usr/bin/env python3
from pathlib import Path
from hashlib import blake2s
from trezorlib.firmware.core import FirmwareImage
ALIGNED_SIZE = 128 * 1024
HERE = Path(__file__).parent
BOOTLOADERS = HERE / ".." / "models"
BL_CHECK = HERE / "bl_check.c"
BL_CHECK_AUTO_BEGIN = "// --- BEGIN GENERATED BOOTLOADER SECTION ---\n"
BL_CHECK_AUTO_END = "// --- END GENERATED BOOTLOADER SECTION ---\n"
PATTERN = """\
// {name} version {version}
#define BOOTLOADER_{suffix}_00 {{{bytes_00}}}
#define BOOTLOADER_{suffix}_FF {{{bytes_ff}}}
"""
def aligned_digest(data: bytes, padding: bytes) -> bytes:
"""Calculate digest of data, aligned to ALIGNED_SIZE with
the specified padding.
Firmware needs to check the bootloader against a digest padded either by 0xff
(unwritten NOR-flash byte) or 0x00 (explicitly cleared byte).
"""
if len(data) > ALIGNED_SIZE:
raise ValueError(fn, "too big")
assert len(padding) == 1
digest_data = data + padding * (ALIGNED_SIZE - len(data))
assert len(digest_data) == ALIGNED_SIZE
return blake2s(digest_data).digest()
def to_uint_array(data: bytes) -> str:
"""Convert bytes to C array of uint8_t, like so:
>>> to_uint_array(b"\\x00\\x01\\x02")
"{0x00, 0x01, 0x02}"
"""
return ", ".join([f"0x{i:02x}" for i in data])
def bootloader_str(file: Path) -> str:
"""From a given file, generate the relevant C definition strings from PATTERN.
Calculates the two padded hashes, one with 0x00 and the other 0xFF, and returns
a string suitable for writing into bl_check.c.
"""
data = file.read_bytes()
suffix = file.stem[len("bootloader_") :].upper()
bytes_00 = to_uint_array(aligned_digest(data, b"\x00"))
bytes_ff = to_uint_array(aligned_digest(data, b"\xff"))
try:
bl = FirmwareImage.parse(data)
version_str = ".".join(str(x) for x in bl.header.version)
except Exception:
version_str = "<unknown>"
return PATTERN.format(
name=file.name,
version=version_str,
suffix=suffix,
bytes_00=bytes_00,
bytes_ff=bytes_ff,
)
def main():
models = list(BOOTLOADERS.iterdir())
models = [model for model in models if model.is_dir()]
for model in models:
path = model / "bootloaders"
if path.is_dir():
header_file = path / "bootloader_hashes.h"
content = []
content.append("#ifndef BOOTLOADER_HASHES_H\n")
content.append("#define BOOTLOADER_HASHES_H\n")
content.append("\n")
content.append("// Auto-generated file, do not edit.\n")
content.append("\n")
content.append("// clang-format off\n")
bootloaders = sorted(path.glob("bootloader*.bin"))
for bootloader in bootloaders:
if bootloader.is_file():
print(f"Processing {bootloader}")
content.append(bootloader_str(bootloader))
content.append("// clang-format on\n")
content.append("\n")
content.append("#endif\n")
header_file.write_text("".join(content))
if __name__ == "__main__":
main()