1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 15:38:11 +00:00

tools: run black and flake8 on tools/

This commit is contained in:
Pavol Rusnak 2018-07-31 11:35:09 +02:00
parent 481bb4ccab
commit 10396777b8
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
18 changed files with 533 additions and 449 deletions

View File

@ -12,107 +12,101 @@ from trezorlib import cosi
def format_sigmask(sigmask): def format_sigmask(sigmask):
bits = [str(b + 1) if sigmask & (1 << b) else '.' for b in range(8)] bits = [str(b + 1) if sigmask & (1 << b) else "." for b in range(8)]
return '0x%02x = [%s]' % (sigmask, ' '.join(bits)) return "0x%02x = [%s]" % (sigmask, " ".join(bits))
def format_vtrust(vtrust): def format_vtrust(vtrust):
bits = [str(b) if vtrust & (1 << b) == 0 else '.' for b in range(16)] bits = [str(b) if vtrust & (1 << b) == 0 else "." for b in range(16)]
# see docs/bootloader.md for vtrust constants # see docs/bootloader.md for vtrust constants
desc = '' desc = ""
wait = (vtrust & 0x000F) ^ 0x000F wait = (vtrust & 0x000F) ^ 0x000F
if wait > 0: if wait > 0:
desc = 'WAIT_%d' % wait desc = "WAIT_%d" % wait
if vtrust & 0x0010 == 0: if vtrust & 0x0010 == 0:
desc += ' RED' desc += " RED"
if vtrust & 0x0020 == 0: if vtrust & 0x0020 == 0:
desc += ' CLICK' desc += " CLICK"
if vtrust & 0x0040 == 0: if vtrust & 0x0040 == 0:
desc += ' STRING' desc += " STRING"
return '%d = [%s] = [%s]' % (vtrust, ' '.join(bits), desc) return "%d = [%s] = [%s]" % (vtrust, " ".join(bits), desc)
# bootloader/firmware headers specification: https://github.com/trezor/trezor-core/blob/master/docs/bootloader.md # bootloader/firmware headers specification: https://github.com/trezor/trezor-core/blob/master/docs/bootloader.md
IMAGE_HEADER_SIZE = 1024 IMAGE_HEADER_SIZE = 1024
IMAGE_SIG_SIZE = 65 IMAGE_SIG_SIZE = 65
IMAGE_CHUNK_SIZE = 128 * 1024 IMAGE_CHUNK_SIZE = 128 * 1024
BOOTLOADER_SECTORS_COUNT = 1 BOOTLOADER_SECTORS_COUNT = 1
FIRMWARE_SECTORS_COUNT = 6 + 7 FIRMWARE_SECTORS_COUNT = 6 + 7
class BinImage(object): class BinImage(object):
def __init__(self, data, magic, max_size): def __init__(self, data, magic, max_size):
header = struct.unpack('<4sIIIBBBBBBBB8s512s415sB64s', data[:IMAGE_HEADER_SIZE]) header = struct.unpack("<4sIIIBBBBBBBB8s512s415sB64s", data[:IMAGE_HEADER_SIZE])
self.magic, \ self.magic, self.hdrlen, self.expiry, self.codelen, self.vmajor, self.vminor, self.vpatch, self.vbuild, self.fix_vmajor, self.fix_vminor, self.fix_vpatch, self.fix_vbuild, self.reserved1, self.hashes, self.reserved2, self.sigmask, self.sig = (
self.hdrlen, \ header
self.expiry, \ )
self.codelen, \
self.vmajor, \
self.vminor, \
self.vpatch, \
self.vbuild, \
self.fix_vmajor, \
self.fix_vminor, \
self.fix_vpatch, \
self.fix_vbuild, \
self.reserved1, \
self.hashes, \
self.reserved2, \
self.sigmask, \
self.sig = header
assert self.magic == magic assert self.magic == magic
assert self.hdrlen == IMAGE_HEADER_SIZE assert self.hdrlen == IMAGE_HEADER_SIZE
total_len = self.hdrlen + self.codelen total_len = self.hdrlen + self.codelen
assert total_len % 512 == 0 assert total_len % 512 == 0
assert total_len >= 4 * 1024 assert total_len >= 4 * 1024
assert total_len <= max_size assert total_len <= max_size
assert self.reserved1 == 8 * b'\x00' assert self.reserved1 == 8 * b"\x00"
assert self.reserved2 == 415 * b'\x00' assert self.reserved2 == 415 * b"\x00"
self.code = data[self.hdrlen:] self.code = data[self.hdrlen :]
assert len(self.code) == self.codelen assert len(self.code) == self.codelen
def print(self): def print(self):
if self.magic == b'TRZF': if self.magic == b"TRZF":
print('TREZOR Firmware Image') print("TREZOR Firmware Image")
total_len = self.vhdrlen + self.hdrlen + self.codelen total_len = self.vhdrlen + self.hdrlen + self.codelen
elif self.magic == b'TRZB': elif self.magic == b"TRZB":
print('TREZOR Bootloader Image') print("TREZOR Bootloader Image")
total_len = self.hdrlen + self.codelen total_len = self.hdrlen + self.codelen
else: else:
print('TREZOR Unknown Image') print("TREZOR Unknown Image")
print(' * magic :', self.magic.decode()) print(" * magic :", self.magic.decode())
print(' * hdrlen :', self.hdrlen) print(" * hdrlen :", self.hdrlen)
print(' * expiry :', self.expiry) print(" * expiry :", self.expiry)
print(' * codelen :', self.codelen) print(" * codelen :", self.codelen)
print(' * version : %d.%d.%d.%d' % (self.vmajor, self.vminor, self.vpatch, self.vbuild)) print(
print(' * fixver : %d.%d.%d.%d' % (self.fix_vmajor, self.fix_vminor, self.fix_vpatch, self.fix_vbuild)) " * version : %d.%d.%d.%d"
print(' * hashes: %s' % ('OK' if self.check_hashes() else 'INCORRECT')) % (self.vmajor, self.vminor, self.vpatch, self.vbuild)
)
print(
" * fixver : %d.%d.%d.%d"
% (self.fix_vmajor, self.fix_vminor, self.fix_vpatch, self.fix_vbuild)
)
print(" * hashes: %s" % ("OK" if self.check_hashes() else "INCORRECT"))
for i in range(16): for i in range(16):
print(' - %02d : %s' % (i, binascii.hexlify(self.hashes[i * 32:i * 32 + 32]).decode())) print(
print(' * sigmask :', format_sigmask(self.sigmask)) " - %02d : %s"
print(' * sig :', binascii.hexlify(self.sig).decode()) % (i, binascii.hexlify(self.hashes[i * 32 : i * 32 + 32]).decode())
print(' * total : %d bytes' % total_len) )
print(' * fngprnt :', self.fingerprint()) print(" * sigmask :", format_sigmask(self.sigmask))
print(" * sig :", binascii.hexlify(self.sig).decode())
print(" * total : %d bytes" % total_len)
print(" * fngprnt :", self.fingerprint())
print() print()
def compute_hashes(self): def compute_hashes(self):
if self.magic == b'TRZF': if self.magic == b"TRZF":
hdrlen = self.vhdrlen + self.hdrlen hdrlen = self.vhdrlen + self.hdrlen
else: else:
hdrlen = self.hdrlen hdrlen = self.hdrlen
hashes = b'' hashes = b""
for i in range(16): for i in range(16):
if i == 0: if i == 0:
d = self.code[:IMAGE_CHUNK_SIZE - hdrlen] d = self.code[: IMAGE_CHUNK_SIZE - hdrlen]
else: else:
s = IMAGE_CHUNK_SIZE - hdrlen + (i - 1) * IMAGE_CHUNK_SIZE s = IMAGE_CHUNK_SIZE - hdrlen + (i - 1) * IMAGE_CHUNK_SIZE
d = self.code[s:s + IMAGE_CHUNK_SIZE] d = self.code[s : s + IMAGE_CHUNK_SIZE]
if len(d) > 0: if len(d) > 0:
h = pyblake2.blake2s(d).digest() h = pyblake2.blake2s(d).digest()
else: else:
h = 32 * b'\x00' h = 32 * b"\x00"
hashes += h hashes += h
return hashes return hashes
@ -123,15 +117,28 @@ class BinImage(object):
self.hashes = self.compute_hashes() self.hashes = self.compute_hashes()
def serialize_header(self, sig=True): def serialize_header(self, sig=True):
header = struct.pack('<4sIIIBBBBBBBB8s512s415s', header = struct.pack(
self.magic, self.hdrlen, self.expiry, self.codelen, "<4sIIIBBBBBBBB8s512s415s",
self.vmajor, self.vminor, self.vpatch, self.vbuild, self.magic,
self.fix_vmajor, self.fix_vminor, self.fix_vpatch, self.fix_vbuild, self.hdrlen,
self.reserved1, self.hashes, self.reserved2) self.expiry,
self.codelen,
self.vmajor,
self.vminor,
self.vpatch,
self.vbuild,
self.fix_vmajor,
self.fix_vminor,
self.fix_vpatch,
self.fix_vbuild,
self.reserved1,
self.hashes,
self.reserved2,
)
if sig: if sig:
header += struct.pack('<B64s', self.sigmask, self.sig) header += struct.pack("<B64s", self.sigmask, self.sig)
else: else:
header += IMAGE_SIG_SIZE * b'\x00' header += IMAGE_SIG_SIZE * b"\x00"
assert len(header) == self.hdrlen assert len(header) == self.hdrlen
return header return header
@ -146,104 +153,122 @@ class BinImage(object):
self.sig = signature self.sig = signature
def write(self, filename): def write(self, filename):
with open(filename, 'wb') as f: with open(filename, "wb") as f:
f.write(self.serialize_header()) f.write(self.serialize_header())
f.write(self.code) f.write(self.code)
class FirmwareImage(BinImage): class FirmwareImage(BinImage):
def __init__(self, data, vhdrlen): def __init__(self, data, vhdrlen):
super(FirmwareImage, self).__init__(data[vhdrlen:], magic=b'TRZF', max_size=FIRMWARE_SECTORS_COUNT * IMAGE_CHUNK_SIZE) super(FirmwareImage, self).__init__(
data[vhdrlen:],
magic=b"TRZF",
max_size=FIRMWARE_SECTORS_COUNT * IMAGE_CHUNK_SIZE,
)
self.vhdrlen = vhdrlen self.vhdrlen = vhdrlen
self.vheader = data[:vhdrlen] self.vheader = data[:vhdrlen]
def write(self, filename): def write(self, filename):
with open(filename, 'wb') as f: with open(filename, "wb") as f:
f.write(self.vheader) f.write(self.vheader)
f.write(self.serialize_header()) f.write(self.serialize_header())
f.write(self.code) f.write(self.code)
class BootloaderImage(BinImage): class BootloaderImage(BinImage):
def __init__(self, data): def __init__(self, data):
super(BootloaderImage, self).__init__(data, magic=b'TRZB', max_size=BOOTLOADER_SECTORS_COUNT * IMAGE_CHUNK_SIZE) super(BootloaderImage, self).__init__(
data, magic=b"TRZB", max_size=BOOTLOADER_SECTORS_COUNT * IMAGE_CHUNK_SIZE
)
class VendorHeader(object): class VendorHeader(object):
def __init__(self, data): def __init__(self, data):
header = struct.unpack('<4sIIBBBBH', data[:18]) header = struct.unpack("<4sIIBBBBH", data[:18])
self.magic, \ self.magic, self.hdrlen, self.expiry, self.vmajor, self.vminor, self.vsig_m, self.vsig_n, self.vtrust = (
self.hdrlen, \ header
self.expiry, \ )
self.vmajor, \ assert self.magic == b"TRZV"
self.vminor, \ data = data[: self.hdrlen] # strip remaining data (firmware)
self.vsig_m, \
self.vsig_n, \
self.vtrust = header
assert self.magic == b'TRZV'
data = data[:self.hdrlen] # strip remaining data (firmware)
assert self.vsig_m > 0 and self.vsig_m <= self.vsig_n assert self.vsig_m > 0 and self.vsig_m <= self.vsig_n
assert self.vsig_n > 0 and self.vsig_n <= 8 assert self.vsig_n > 0 and self.vsig_n <= 8
p = 32 p = 32
self.vpub = [] self.vpub = []
for _ in range(self.vsig_n): for _ in range(self.vsig_n):
self.vpub.append(data[p:p + 32]) self.vpub.append(data[p : p + 32])
p += 32 p += 32
self.vstr_len = data[p] self.vstr_len = data[p]
p += 1 p += 1
self.vstr = data[p:p + self.vstr_len] self.vstr = data[p : p + self.vstr_len]
p += self.vstr_len p += self.vstr_len
vstr_pad = -p & 3 vstr_pad = -p & 3
p += vstr_pad p += vstr_pad
self.vimg_len = len(data) - IMAGE_SIG_SIZE - p self.vimg_len = len(data) - IMAGE_SIG_SIZE - p
self.vimg = data[p:p + self.vimg_len] self.vimg = data[p : p + self.vimg_len]
p += self.vimg_len p += self.vimg_len
self.sigmask = data[p] self.sigmask = data[p]
p += 1 p += 1
self.sig = data[p:p + 64] self.sig = data[p : p + 64]
assert len(data) == 4 + 4 + 4 + 1 + 1 + 1 + 1 + 1 + 15 + \ assert (
32 * len(self.vpub) + \ len(data)
1 + self.vstr_len + vstr_pad + \ == 4
self.vimg_len + \ + 4
IMAGE_SIG_SIZE + 4
+ 1
+ 1
+ 1
+ 1
+ 1
+ 15
+ 32 * len(self.vpub)
+ 1
+ self.vstr_len
+ vstr_pad
+ self.vimg_len
+ IMAGE_SIG_SIZE
)
assert len(data) % 512 == 0 assert len(data) % 512 == 0
def print(self): def print(self):
print('TREZOR Vendor Header') print("TREZOR Vendor Header")
print(' * magic :', self.magic.decode()) print(" * magic :", self.magic.decode())
print(' * hdrlen :', self.hdrlen) print(" * hdrlen :", self.hdrlen)
print(' * expiry :', self.expiry) print(" * expiry :", self.expiry)
print(' * version : %d.%d' % (self.vmajor, self.vminor)) print(" * version : %d.%d" % (self.vmajor, self.vminor))
print(' * scheme : %d out of %d' % (self.vsig_m, self.vsig_n)) print(" * scheme : %d out of %d" % (self.vsig_m, self.vsig_n))
print(' * trust :', format_vtrust(self.vtrust)) print(" * trust :", format_vtrust(self.vtrust))
for i in range(self.vsig_n): for i in range(self.vsig_n):
print(' * vpub #%d :' % (i + 1), binascii.hexlify(self.vpub[i]).decode()) print(" * vpub #%d :" % (i + 1), binascii.hexlify(self.vpub[i]).decode())
print(' * vstr :', self.vstr.decode()) print(" * vstr :", self.vstr.decode())
print(' * vhash :', binascii.hexlify(self.vhash()).decode()) print(" * vhash :", binascii.hexlify(self.vhash()).decode())
print(' * vimg : (%d bytes)' % len(self.vimg)) print(" * vimg : (%d bytes)" % len(self.vimg))
print(' * sigmask :', format_sigmask(self.sigmask)) print(" * sigmask :", format_sigmask(self.sigmask))
print(' * sig :', binascii.hexlify(self.sig).decode()) print(" * sig :", binascii.hexlify(self.sig).decode())
print(' * fngprnt :', self.fingerprint()) print(" * fngprnt :", self.fingerprint())
print() print()
def serialize_header(self, sig=True): def serialize_header(self, sig=True):
header = struct.pack('<4sIIBBBBH', header = struct.pack(
self.magic, self.hdrlen, self.expiry, "<4sIIBBBBH",
self.vmajor, self.vminor, self.magic,
self.vsig_m, self.vsig_n, self.vtrust) self.hdrlen,
header += 14 * b'\x00' self.expiry,
self.vmajor,
self.vminor,
self.vsig_m,
self.vsig_n,
self.vtrust,
)
header += 14 * b"\x00"
for i in range(self.vsig_n): for i in range(self.vsig_n):
header += self.vpub[i] header += self.vpub[i]
header += struct.pack('<B', self.vstr_len) + self.vstr header += struct.pack("<B", self.vstr_len) + self.vstr
header += (-len(header) & 3) * b'\x00' # vstr_pad header += (-len(header) & 3) * b"\x00" # vstr_pad
header += self.vimg header += self.vimg
if sig: if sig:
header += struct.pack('<B64s', self.sigmask, self.sig) header += struct.pack("<B64s", self.sigmask, self.sig)
else: else:
header += IMAGE_SIG_SIZE * b'\x00' header += IMAGE_SIG_SIZE * b"\x00"
assert len(header) == self.hdrlen assert len(header) == self.hdrlen
return header return header
@ -252,12 +277,12 @@ class VendorHeader(object):
def vhash(self): def vhash(self):
h = pyblake2.blake2s() h = pyblake2.blake2s()
h.update(struct.pack('<BB', self.vsig_m, self.vsig_n)) h.update(struct.pack("<BB", self.vsig_m, self.vsig_n))
for i in range(8): for i in range(8):
if i < self.vsig_n: if i < self.vsig_n:
h.update(self.vpub[i]) h.update(self.vpub[i])
else: else:
h.update(b'\x00' * 32) h.update(b"\x00" * 32)
return h.digest() return h.digest()
def sign(self, sigmask, signature): def sign(self, sigmask, signature):
@ -267,54 +292,57 @@ class VendorHeader(object):
self.sig = signature self.sig = signature
def write(self, filename): def write(self, filename):
with open(filename, 'wb') as f: with open(filename, "wb") as f:
f.write(self.serialize_header()) f.write(self.serialize_header())
def binopen(filename): def binopen(filename):
data = open(filename, 'rb').read() data = open(filename, "rb").read()
magic = data[:4] magic = data[:4]
if magic == b'TRZB': if magic == b"TRZB":
return BootloaderImage(data) return BootloaderImage(data)
if magic == b'TRZV': if magic == b"TRZV":
vheader = VendorHeader(data) vheader = VendorHeader(data)
if len(data) == vheader.hdrlen: if len(data) == vheader.hdrlen:
return vheader return vheader
vheader.print() vheader.print()
subdata = data[vheader.hdrlen:] subdata = data[vheader.hdrlen :]
if subdata[:4] == b'TRZF': if subdata[:4] == b"TRZF":
firmware = FirmwareImage(data, vheader.hdrlen) firmware = FirmwareImage(data, vheader.hdrlen)
# check signatures against signing keys in the vendor header # check signatures against signing keys in the vendor header
if firmware.sigmask > 0: if firmware.sigmask > 0:
pk = [vheader.vpub[i] for i in range(8) if firmware.sigmask & (1 << i)] pk = [vheader.vpub[i] for i in range(8) if firmware.sigmask & (1 << i)]
global_pk = cosi.combine_keys(pk) global_pk = cosi.combine_keys(pk)
hdr = subdata[:IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE] + IMAGE_SIG_SIZE * b'\x00' hdr = (
subdata[: IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE]
+ IMAGE_SIG_SIZE * b"\x00"
)
digest = pyblake2.blake2s(hdr).digest() digest = pyblake2.blake2s(hdr).digest()
try: try:
cosi.verify(firmware.sig, digest, global_pk) cosi.verify(firmware.sig, digest, global_pk)
print('Firmware signature OK') print("Firmware signature OK")
except: except ValueError:
print('Firmware signature INCORRECT') print("Firmware signature INCORRECT")
else: else:
print('No firmware signature') print("No firmware signature")
return firmware return firmware
if magic == b'TRZF': if magic == b"TRZF":
return FirmwareImage(data, 0) return FirmwareImage(data, 0)
raise Exception('Unknown file format') raise Exception("Unknown file format")
def main(): def main():
if len(sys.argv) < 2: if len(sys.argv) < 2:
print('Usage: binctl file.bin [-s sigmask signature] [-h]') print("Usage: binctl file.bin [-s sigmask signature] [-h]")
return 1 return 1
fn = sys.argv[1] fn = sys.argv[1]
sign = len(sys.argv) > 2 and sys.argv[2] == '-s' sign = len(sys.argv) > 2 and sys.argv[2] == "-s"
rehash = len(sys.argv) == 3 and sys.argv[2] == '-h' rehash = len(sys.argv) == 3 and sys.argv[2] == "-h"
b = binopen(fn) b = binopen(fn)
if sign: if sign:
sigmask = 0 sigmask = 0
if ':' in sys.argv[3]: if ":" in sys.argv[3]:
for idx in sys.argv[3].split(':'): for idx in sys.argv[3].split(":"):
sigmask |= 1 << (int(idx) - 1) sigmask |= 1 << (int(idx) - 1)
else: else:
sigmask = 1 << (int(sys.argv[3]) - 1) sigmask = 1 << (int(sys.argv[3]) - 1)
@ -327,5 +355,5 @@ def main():
b.print() b.print()
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
COMMENT_PREFIX = '/// ' COMMENT_PREFIX = "/// "
current_indent = 0 current_indent = 0
current_class = None current_class = None
@ -14,24 +14,24 @@ def split_to_parts(line, mod_desc=None):
global current_class global current_class
global current_method global current_method
if line.startswith('class '): if line.startswith("class "):
current_class = line[6:].split('(')[0].strip(':') current_class = line[6:].split("(")[0].strip(":")
current_indent = 0 current_indent = 0
yield (current_package, "\n") yield (current_package, "\n")
yield (current_package, '# ' + mod_desc + "\n") yield (current_package, "# " + mod_desc + "\n")
elif line.startswith('def '): elif line.startswith("def "):
current_method = line[4:].split('(')[0] current_method = line[4:].split("(")[0]
yield (current_package, "\n") yield (current_package, "\n")
if current_class is None: if current_class is None:
yield (current_package, '# ' + mod_desc + "\n") yield (current_package, "# " + mod_desc + "\n")
else: else:
current_indent = 4 current_indent = 4
line = current_indent * ' ' + line line = current_indent * " " + line
yield (current_package, line) yield (current_package, line)
@ -43,16 +43,16 @@ def store_to_file(dest, parts):
if not os.path.exists(dirpath): if not os.path.exists(dirpath):
os.makedirs(dirpath) os.makedirs(dirpath)
open(os.path.join(dirpath, '__init__.py'), 'w').close() open(os.path.join(dirpath, "__init__.py"), "w").close()
open(os.path.join(dirpath, '.mock-generated'), 'w').close() open(os.path.join(dirpath, ".mock-generated"), "w").close()
filepath = os.path.join(dirpath, filename + '.py') filepath = os.path.join(dirpath, filename + ".py")
if not os.path.exists(filepath): if not os.path.exists(filepath):
with open(filepath, 'a') as f: with open(filepath, "a") as f:
f.write('from typing import *\n') f.write("from typing import *\n")
with open(filepath, 'a') as f: with open(filepath, "a") as f:
f.write(line) f.write(line)
@ -61,24 +61,23 @@ def build_module(mod_file, dest):
global current_class global current_class
global current_package global current_package
if not (mod_file.endswith('.h') or mod_file.endswith('.c')): if not (mod_file.endswith(".h") or mod_file.endswith(".c")):
return return
if not os.path.basename(mod_file).startswith('mod'): if not os.path.basename(mod_file).startswith("mod"):
return return
current_indent = 0 current_indent = 0
current_class = None current_class = None
current_package = os.path.basename(mod_file) \ current_package = (
.split('.')[0] \ os.path.basename(mod_file).split(".")[0].split("-")[0].replace("mod", "")
.split('-')[0] \ )
.replace('mod', '') mod_desc = mod_file.replace("../embed/extmod", "extmod")
mod_desc = mod_file.replace('../embed/extmod', 'extmod')
for l in open(mod_file): for l in open(mod_file):
if not l.startswith(COMMENT_PREFIX): if not l.startswith(COMMENT_PREFIX):
continue continue
l = l[len(COMMENT_PREFIX):] # .strip() l = l[len(COMMENT_PREFIX) :] # .strip()
store_to_file(dest, split_to_parts(l, mod_desc)) store_to_file(dest, split_to_parts(l, mod_desc))
@ -92,7 +91,7 @@ def build_directory(dir, dest):
def clear_directory(top_dir): def clear_directory(top_dir):
print("Clearing up directory", top_dir) print("Clearing up directory", top_dir)
for root, dirs, files in os.walk(top_dir, topdown=False): for root, dirs, files in os.walk(top_dir, topdown=False):
if '.mock-generated' not in files: if ".mock-generated" not in files:
# print("Not a mock directory", root) # print("Not a mock directory", root)
continue continue
for name in files: for name in files:
@ -108,6 +107,6 @@ def clear_directory(top_dir):
os.rmdir(root) os.rmdir(root)
if __name__ == '__main__': if __name__ == "__main__":
clear_directory('../mocks/generated') clear_directory("../mocks/generated")
build_directory('../embed/extmod', '../mocks/generated') build_directory("../embed/extmod", "../mocks/generated")

View File

@ -3,58 +3,62 @@ import sys
import struct import struct
import binascii import binascii
# encode vendor name, add length byte and padding to multiple of 4 # encode vendor name, add length byte and padding to multiple of 4
def encode_vendor(vname): def encode_vendor(vname):
vbin = vname.encode() vbin = vname.encode()
vbin = struct.pack('<B', len(vbin)) + vbin vbin = struct.pack("<B", len(vbin)) + vbin
vbin += b'\0' * (-len(vbin) & 3) vbin += b"\0" * (-len(vbin) & 3)
return vbin return vbin
def encode_pubkey(pubkey): def encode_pubkey(pubkey):
if len(pubkey) != 64: if len(pubkey) != 64:
raise Exception('Wrong public key length') raise Exception("Wrong public key length")
return binascii.unhexlify(pubkey) return binascii.unhexlify(pubkey)
def decode_vtrust(vtrust): def decode_vtrust(vtrust):
t = 0xFFFF t = 0xFFFF
for i, b in enumerate(reversed(vtrust)): for i, b in enumerate(reversed(vtrust)):
if b != '.': if b != ".":
t &= ~(1 << i) t &= ~(1 << i)
return t return t
def main(): def main():
if len(sys.argv) < 7: if len(sys.argv) < 7:
print('Usage build_vendorheader "pubkey1hex:pubkey2hex:..." m version vendortrust vendorname vendorimage.toif vendorheader.bin') print(
'Usage build_vendorheader "pubkey1hex:pubkey2hex:..." m version vendortrust vendorname vendorimage.toif vendorheader.bin'
)
return 1 return 1
keys = [encode_pubkey(x) for x in sys.argv[1].split(':')] keys = [encode_pubkey(x) for x in sys.argv[1].split(":")]
m = int(sys.argv[2]) m = int(sys.argv[2])
(vmajor, vminor) = [int(x) for x in sys.argv[3].split('.')] (vmajor, vminor) = [int(x) for x in sys.argv[3].split(".")]
vtrust = decode_vtrust(sys.argv[4]) vtrust = decode_vtrust(sys.argv[4])
vname = sys.argv[5] vname = sys.argv[5]
ifn = sys.argv[6] ifn = sys.argv[6]
ofn = sys.argv[7] ofn = sys.argv[7]
if not ifn.endswith('.toif'): if not ifn.endswith(".toif"):
print('Must provide TOIF file') print("Must provide TOIF file")
return 2 return 2
expiry = 0 expiry = 0
vheader = b'TRZV' + \ vheader = b"TRZV" + struct.pack(
struct.pack('<IIBBBBH', 0, expiry, vmajor, vminor, m, len(keys), vtrust) "<IIBBBBH", 0, expiry, vmajor, vminor, m, len(keys), vtrust
vheader += 14 * b'\0' )
vheader += 14 * b"\0"
for k in keys: for k in keys:
vheader += k vheader += k
vheader += encode_vendor(vname) + open(ifn, 'rb').read() vheader += encode_vendor(vname) + open(ifn, "rb").read()
padding = 65 + (-len(vheader) - 65) & 511 padding = 65 + (-len(vheader) - 65) & 511
vheader += b'\0' * padding vheader += b"\0" * padding
# put in length # put in length
vheader = vheader[0:4] + struct.pack('<I', len(vheader)) + vheader[8:] vheader = vheader[0:4] + struct.pack("<I", len(vheader)) + vheader[8:]
with open(ofn, 'wb') as f: with open(ofn, "wb") as f:
f.write(vheader) f.write(vheader)

View File

@ -5,16 +5,19 @@ from hashlib import sha256
import requests import requests
REPO = 'certifi/python-certifi' REPO = "certifi/python-certifi"
def fetch_certdata(): def fetch_certdata():
r = requests.get('https://api.github.com/repos/%s/git/refs/heads/master' % REPO) r = requests.get("https://api.github.com/repos/%s/git/refs/heads/master" % REPO)
assert(r.status_code == 200) assert r.status_code == 200
commithash = r.json()['object']['sha'] commithash = r.json()["object"]["sha"]
r = requests.get('https://raw.githubusercontent.com/%s/%s/certifi/cacert.pem' % (REPO, commithash)) r = requests.get(
assert(r.status_code == 200) "https://raw.githubusercontent.com/%s/%s/certifi/cacert.pem"
% (REPO, commithash)
)
assert r.status_code == 200
certdata = r.text certdata = r.text
return commithash, certdata return commithash, certdata
@ -22,21 +25,21 @@ def fetch_certdata():
def process_certdata(data): def process_certdata(data):
certs = {} certs = {}
lines = [x.strip() for x in data.split('\n')] lines = [x.strip() for x in data.split("\n")]
label = None label = None
value = None value = None
for line in lines: for line in lines:
if line.startswith('# Label: '): if line.startswith("# Label: "):
assert(label is None) assert label is None
assert(value is None) assert value is None
label = line.split('"')[1] label = line.split('"')[1]
elif line == '-----BEGIN CERTIFICATE-----': elif line == "-----BEGIN CERTIFICATE-----":
assert(label is not None) assert label is not None
assert(value is None) assert value is None
value = '' value = ""
elif line == '-----END CERTIFICATE-----': elif line == "-----END CERTIFICATE-----":
assert(label is not None) assert label is not None
assert(value is not None) assert value is not None
certs[label] = b64decode(value) certs[label] = b64decode(value)
label, value = None, None label, value = None, None
else: else:
@ -49,22 +52,25 @@ def process_certdata(data):
def main(): def main():
commithash, certdata = fetch_certdata() commithash, certdata = fetch_certdata()
print('# fetched from https://github.com/%s' % REPO) print("# fetched from https://github.com/%s" % REPO)
print('# commit %s' % commithash) print("# commit %s" % commithash)
certs = process_certdata(certdata) certs = process_certdata(certdata)
size = sum([len(x) for x in certs.values()]) size = sum([len(x) for x in certs.values()])
print('# certs: %d | digests size: %d | total size: %d' % (len(certs), len(certs) * 32, size)) print(
"# certs: %d | digests size: %d | total size: %d"
% (len(certs), len(certs) * 32, size)
)
print('cert_bundle = [') print("cert_bundle = [")
for k, v in certs.items(): for k, v in certs.items():
h = sha256(v) h = sha256(v)
print(' # %s' % k) print(" # %s" % k)
print(' # %s' % h.hexdigest()) print(" # %s" % h.hexdigest())
print(' %s,' % h.digest()) print(" %s," % h.digest())
print(']') print("]")
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View File

@ -2,43 +2,43 @@
import json import json
fields = [ fields = [
'coin_name', "coin_name",
'coin_shortcut', "coin_shortcut",
'address_type', "address_type",
'address_type_p2sh', "address_type_p2sh",
'maxfee_kb', "maxfee_kb",
'signed_message_header', "signed_message_header",
'xpub_magic', "xpub_magic",
'bech32_prefix', "bech32_prefix",
'cashaddr_prefix', "cashaddr_prefix",
'slip44', "slip44",
'segwit', "segwit",
'fork_id', "fork_id",
'force_bip143', "force_bip143",
'version_group_id', "version_group_id",
'bip115', "bip115",
'curve_name', "curve_name",
] ]
support = json.load(open('../../vendor/trezor-common/defs/support.json', 'r')) support = json.load(open("../../vendor/trezor-common/defs/support.json", "r"))
coins = support['trezor2'].keys() coins = support["trezor2"].keys()
print('COINS = [') print("COINS = [")
for c in coins: for c in coins:
print(' CoinInfo(') print(" CoinInfo(")
name = c.replace(' ', '_').lower() name = c.replace(" ", "_").lower()
if name == 'testnet': if name == "testnet":
name = 'bitcoin_testnet' name = "bitcoin_testnet"
data = json.load(open('../../vendor/trezor-common/defs/coins/%s.json' % name, 'r')) data = json.load(open("../../vendor/trezor-common/defs/coins/%s.json" % name, "r"))
for n in fields: for n in fields:
if n in ['xpub_magic', 'version_group_id']: if n in ["xpub_magic", "version_group_id"]:
v = '0x%08x' % data[n] if data[n] is not None else 'None' v = "0x%08x" % data[n] if data[n] is not None else "None"
else: else:
v = repr(data[n]) v = repr(data[n])
if n == 'curve_name': if n == "curve_name":
v = v.replace('_', '-') v = v.replace("_", "-")
print(' %s=%s,' % (n, v)) print(" %s=%s," % (n, v))
print(' ),') print(" ),")
print(']') print("]")

View File

@ -1,14 +1,14 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import json import json
j = json.load(open('../../vendor/trezor-common/defs/ethereum/networks.json', 'r')) j = json.load(open("../../vendor/trezor-common/defs/ethereum/networks.json", "r"))
print('NETWORKS = [') print("NETWORKS = [")
for n in j: for n in j:
print(' NetworkInfo(') print(" NetworkInfo(")
for f in ['chain_id', 'slip44', 'shortcut', 'name', 'rskip60']: for f in ["chain_id", "slip44", "shortcut", "name", "rskip60"]:
print(' %s=%s,' % (f, repr(n[f]))) print(" %s=%s," % (f, repr(n[f])))
print(' ),') print(" ),")
print(']') print("]")

View File

@ -5,8 +5,8 @@
import freetype import freetype
MIN_GLYPH = ord(' ') MIN_GLYPH = ord(" ")
MAX_GLYPH = ord('~') MAX_GLYPH = ord("~")
FONT_BPP = 4 FONT_BPP = 4
@ -14,20 +14,23 @@ FONT_BPP = 4
def process_face(name, style, size): def process_face(name, style, size):
print('Processing ... %s %s %s' % (name, style, size)) print("Processing ... %s %s %s" % (name, style, size))
face = freetype.Face('/usr/share/fonts/truetype/%s-%s.ttf' % (name, style)) face = freetype.Face("/usr/share/fonts/truetype/%s-%s.ttf" % (name, style))
face.set_pixel_sizes(0, size) face.set_pixel_sizes(0, size)
fontname = '%s_%s_%d' % (name.lower(), style.lower(), size) fontname = "%s_%s_%d" % (name.lower(), style.lower(), size)
with open('font_%s.h' % fontname, 'wt') as f: with open("font_%s.h" % fontname, "wt") as f:
f.write('#include <stdint.h>\n\n') f.write("#include <stdint.h>\n\n")
f.write('extern const uint8_t* const Font_%s_%s_%d[%d + 1 - %d];\n' % (name, style, size, MAX_GLYPH, MIN_GLYPH)) f.write(
with open('font_%s.c' % fontname, 'wt') as f: "extern const uint8_t* const Font_%s_%s_%d[%d + 1 - %d];\n"
% (name, style, size, MAX_GLYPH, MIN_GLYPH)
)
with open("font_%s.c" % fontname, "wt") as f:
f.write('#include "font_%s.h"\n\n' % fontname) f.write('#include "font_%s.h"\n\n' % fontname)
f.write('// first two bytes are width and height of the glyph\n') f.write("// first two bytes are width and height of the glyph\n")
f.write('// third, fourth and fifth bytes are advance\n') f.write("// third, fourth and fifth bytes are advance\n")
f.write('// bearingX and bearingY of the horizontal metrics of the glyph\n') f.write("// bearingX and bearingY of the horizontal metrics of the glyph\n")
f.write('// rest is packed 4-bit glyph data\n\n') f.write("// rest is packed 4-bit glyph data\n\n")
f.write('// clang-format off\n\n') f.write("// clang-format off\n\n")
for i in range(MIN_GLYPH, MAX_GLYPH + 1): for i in range(MIN_GLYPH, MAX_GLYPH + 1):
c = chr(i) c = chr(i)
face.load_char(c, freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_NORMAL) face.load_char(c, freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_NORMAL)
@ -48,33 +51,64 @@ def process_face(name, style, size):
bearingX = metrics.horiBearingX // 64 bearingX = metrics.horiBearingX // 64
# the following code is here just for some letters (listed below) # the following code is here just for some letters (listed below)
# not using negative bearingX makes life so much easier; add it to advance instead # not using negative bearingX makes life so much easier; add it to advance instead
if c in 'jy}),/' and bearingX < 0: if c in "jy}),/" and bearingX < 0:
advance += -bearingX advance += -bearingX
bearingX = 0 bearingX = 0
bearingY = metrics.horiBearingY // 64 bearingY = metrics.horiBearingY // 64
assert advance >= 0 and advance <= 255 assert advance >= 0 and advance <= 255
assert bearingX >= 0 and bearingX <= 255 assert bearingX >= 0 and bearingX <= 255
assert bearingY >= 0 and bearingY <= 255 assert bearingY >= 0 and bearingY <= 255
print('Loaded glyph "%c" ... %d x %d @ %d grays (%d bytes, metrics: %d, %d, %d)' % (c, bitmap.width, bitmap.rows, bitmap.num_grays, len(bitmap.buffer), advance, bearingX, bearingY)) print(
f.write('/* %c */ static const uint8_t Font_%s_%s_%d_glyph_%d[] = { %d, %d, %d, %d, %d' % (c, name, style, size, i, width, rows, advance, bearingX, bearingY)) 'Loaded glyph "%c" ... %d x %d @ %d grays (%d bytes, metrics: %d, %d, %d)'
% (
c,
bitmap.width,
bitmap.rows,
bitmap.num_grays,
len(bitmap.buffer),
advance,
bearingX,
bearingY,
)
)
f.write(
"/* %c */ static const uint8_t Font_%s_%s_%d_glyph_%d[] = { %d, %d, %d, %d, %d"
% (c, name, style, size, i, width, rows, advance, bearingX, bearingY)
)
buf = list(bitmap.buffer) buf = list(bitmap.buffer)
if len(buf) > 0: if len(buf) > 0:
if FONT_BPP == 2: if FONT_BPP == 2:
for _ in range(4 - len(buf) % 4): for _ in range(4 - len(buf) % 4):
buf.append(0) buf.append(0)
buf = [((a & 0xC0) | ((b & 0xC0) >> 2) | ((c & 0xC0) >> 4) | ((d & 0xC0) >> 6)) for a, b, c, d in [buf[i:i + 4] for i in range(0, len(buf), 4)]] buf = [
(
(a & 0xC0)
| ((b & 0xC0) >> 2)
| ((c & 0xC0) >> 4)
| ((d & 0xC0) >> 6)
)
for a, b, c, d in [
buf[i : i + 4] for i in range(0, len(buf), 4)
]
]
elif FONT_BPP == 4: elif FONT_BPP == 4:
if len(buf) % 2 > 0: if len(buf) % 2 > 0:
buf.append(0) buf.append(0)
buf = [((a & 0xF0) | (b >> 4)) for a, b in [buf[i:i + 2] for i in range(0, len(buf), 2)]] buf = [
f.write(', ' + ', '.join(['%d' % x for x in buf])) ((a & 0xF0) | (b >> 4))
f.write(' };\n') for a, b in [buf[i : i + 2] for i in range(0, len(buf), 2)]
f.write('\nconst uint8_t * const Font_%s_%s_%d[%d + 1 - %d] = {\n' % (name, style, size, MAX_GLYPH, MIN_GLYPH)) ]
f.write(", " + ", ".join(["%d" % x for x in buf]))
f.write(" };\n")
f.write(
"\nconst uint8_t * const Font_%s_%s_%d[%d + 1 - %d] = {\n"
% (name, style, size, MAX_GLYPH, MIN_GLYPH)
)
for i in range(MIN_GLYPH, MAX_GLYPH + 1): for i in range(MIN_GLYPH, MAX_GLYPH + 1):
f.write(' Font_%s_%s_%d_glyph_%d,\n' % (name, style, size, i)) f.write(" Font_%s_%s_%d_glyph_%d,\n" % (name, style, size, i))
f.write('};\n') f.write("};\n")
process_face('Roboto', 'Regular', 20) process_face("Roboto", "Regular", 20)
process_face('Roboto', 'Bold', 20) process_face("Roboto", "Bold", 20)
process_face('RobotoMono', 'Regular', 20) process_face("RobotoMono", "Regular", 20)

View File

@ -5,16 +5,16 @@ from trezorlib import ed25519raw
def hex_to_c(s): def hex_to_c(s):
return '"\\x' + '\\x'.join([s[i:i + 2] for i in range(0, len(s), 2)]) + '"' return '"\\x' + "\\x".join([s[i : i + 2] for i in range(0, len(s), 2)]) + '"'
for c in 'ABCDEFGHI': for c in "ABCDEFGHI":
print() print()
seckey = c.encode() * 32 seckey = c.encode() * 32
seckey_hex = binascii.hexlify(seckey).decode() seckey_hex = binascii.hexlify(seckey).decode()
print('seckey', seckey_hex) print("seckey", seckey_hex)
print(' ', hex_to_c(seckey_hex)) print(" ", hex_to_c(seckey_hex))
pubkey = ed25519raw.publickey(seckey) pubkey = ed25519raw.publickey(seckey)
pubkey_hex = binascii.hexlify(pubkey).decode() pubkey_hex = binascii.hexlify(pubkey).decode()
print('pubkey', pubkey_hex) print("pubkey", pubkey_hex)
print(' ', hex_to_c(pubkey_hex)) print(" ", hex_to_c(pubkey_hex))

View File

@ -3,16 +3,15 @@
# script used to generate /embed/extmod/modtrezorui/loader.h # script used to generate /embed/extmod/modtrezorui/loader.h
import math import math
import sys
outer = 60 outer = 60
inner = 42 inner = 42
with open('loader.h', 'wt') as f: with open("loader.h", "wt") as f:
f.write('static const int img_loader_size = %d;\n' % outer) f.write("static const int img_loader_size = %d;\n" % outer)
f.write('static const uint16_t img_loader[%d][%d] = {\n' % (outer, outer)) f.write("static const uint16_t img_loader[%d][%d] = {\n" % (outer, outer))
for y in range(outer): for y in range(outer):
f.write(' {') f.write(" {")
for x in range(outer): for x in range(outer):
d = math.sqrt((outer - 1 - x) ** 2 + (outer - 1 - y) ** 2) d = math.sqrt((outer - 1 - x) ** 2 + (outer - 1 - y) ** 2)
c = {} c = {}
@ -33,6 +32,6 @@ with open('loader.h', 'wt') as f:
c[i] = max(0, min(int(c[i]), 15)) c[i] = max(0, min(int(c[i]), 15))
a = int(math.atan2((outer - 1 - x), (outer - 1 - y)) * 2 * 249 / math.pi) a = int(math.atan2((outer - 1 - x), (outer - 1 - y)) * 2 * 249 / math.pi)
v = (a << 8) | (c[15] << 4) | c[5] v = (a << 8) | (c[15] << 4) | c[5]
f.write('%d,' % v) f.write("%d," % v)
f.write('},\n') f.write("},\n")
f.write('};\n') f.write("};\n")

View File

@ -18,29 +18,31 @@ def format_primitive(value):
fields = [ fields = [
'name', "name",
'ticker', "ticker",
'namespace', "namespace",
'mosaic', "mosaic",
'divisibility', "divisibility",
'levy', "levy",
'fee', "fee",
'levy_namespace', "levy_namespace",
'levy_mosaic', "levy_mosaic",
'networks', "networks",
] ]
mosaics = json.load(open('../../vendor/trezor-common/defs/nem/nem_mosaics.json', 'r')) mosaics = json.load(open("../../vendor/trezor-common/defs/nem/nem_mosaics.json", "r"))
print('# generated using gen_nem_mosaics.py from trezor-common nem_mosaics.json - do not edit directly!') print(
print('') "# generated using gen_nem_mosaics.py from trezor-common nem_mosaics.json - do not edit directly!"
print('mosaics = [') )
print("")
print("mosaics = [")
for m in mosaics: for m in mosaics:
print(' {') print(" {")
for name in fields: for name in fields:
if name in m: if name in m:
print(' %s: %s,' % (format_str(name), format_primitive(m[name]))) print(" %s: %s," % (format_str(name), format_primitive(m[name])))
# else: # else:
# print(' %s: None,' % format_str(name)) # print(' %s: None,' % format_str(name))
print(' },') print(" },")
print(']') print("]")

View File

@ -8,9 +8,11 @@ devices = HidTransport.enumerate()
if len(devices) > 0: if len(devices) > 0:
t = TrezorClient(devices[0]) t = TrezorClient(devices[0])
else: else:
raise Exception('No TREZOR found') raise Exception("No TREZOR found")
for i in [0, 1, 2]: for i in [0, 1, 2]:
path = "m/10018'/%d'" % i path = "m/10018'/%d'" % i
pk = t.get_public_node(t.expand_path(path), ecdsa_curve_name='ed25519', show_display=True) pk = t.get_public_node(
print(path, '=>', binascii.hexlify(pk.node.public_key).decode()) t.expand_path(path), ecdsa_curve_name="ed25519", show_display=True
)
print(path, "=>", binascii.hexlify(pk.node.public_key).decode())

View File

@ -16,11 +16,11 @@ out = bytearray()
for addr, fn in files: for addr, fn in files:
addr = int(addr, 16) - offset addr = int(addr, 16) - offset
data = open(fn, 'rb').read() data = open(fn, "rb").read()
if len(out) < addr: if len(out) < addr:
out += b'\x00' * (addr - len(out)) out += b"\x00" * (addr - len(out))
if len(out) != addr: if len(out) != addr:
raise Exception('Alignment failed') raise Exception("Alignment failed")
out += data out += data
sys.stdout.buffer.write(out) sys.stdout.buffer.write(out)

View File

@ -5,23 +5,19 @@ import click
import pyblake2 import pyblake2
from trezorlib import cosi from trezorlib import cosi
indexmap = { indexmap = {"bootloader": 0, "vendorheader": 1, "firmware": 2}
'bootloader': 0,
'vendorheader': 1,
'firmware': 2,
}
def header_digest(index, filename): def header_digest(index, filename):
data = open(filename, 'rb').read() data = open(filename, "rb").read()
z = bytes(65 * [0x00]) z = bytes(65 * [0x00])
if index == 'bootloader': if index == "bootloader":
header = data[:0x03BF] + z header = data[:0x03BF] + z
elif index == 'vendorheader': elif index == "vendorheader":
header = data[:-65] + z header = data[:-65] + z
elif index == 'firmware': elif index == "firmware":
vhdrlen = struct.unpack('<I', data[4:8])[0] vhdrlen = struct.unpack("<I", data[4:8])[0]
header = data[vhdrlen:vhdrlen + 0x03BF] + z header = data[vhdrlen : vhdrlen + 0x03BF] + z
else: else:
raise ValueError('Unknown index "%s"' % index) raise ValueError('Unknown index "%s"' % index)
return pyblake2.blake2s(header).digest() return pyblake2.blake2s(header).digest()
@ -32,10 +28,10 @@ def cli():
pass pass
@cli.command(help='') @cli.command(help="")
@click.argument('index', type=click.Choice(indexmap.keys())) @click.argument("index", type=click.Choice(indexmap.keys()))
@click.argument('filename') @click.argument("filename")
@click.argument('seckeys', nargs=-1) @click.argument("seckeys", nargs=-1)
def sign(index, filename, seckeys): def sign(index, filename, seckeys):
# compute header digest # compute header digest
digest = header_digest(index, filename) digest = header_digest(index, filename)
@ -63,5 +59,5 @@ def sign(index, filename, seckeys):
print(binascii.hexlify(sig).decode()) print(binascii.hexlify(sig).decode())
if __name__ == '__main__': if __name__ == "__main__":
cli() cli()

View File

@ -8,23 +8,19 @@ import serpent
from trezorlib import cosi from trezorlib import cosi
PORT = 5001 PORT = 5001
indexmap = { indexmap = {"bootloader": 0, "vendorheader": 1, "firmware": 2}
'bootloader': 0,
'vendorheader': 1,
'firmware': 2,
}
def header_digest(index, filename): def header_digest(index, filename):
data = open(filename, 'rb').read() data = open(filename, "rb").read()
z = bytes(65 * [0x00]) z = bytes(65 * [0x00])
if index == 'bootloader': if index == "bootloader":
header = data[:0x03BF] + z header = data[:0x03BF] + z
elif index == 'vendorheader': elif index == "vendorheader":
header = data[:-65] + z header = data[:-65] + z
elif index == 'firmware': elif index == "firmware":
vhdrlen = struct.unpack('<I', data[4:8])[0] vhdrlen = struct.unpack("<I", data[4:8])[0]
header = data[vhdrlen:vhdrlen + 0x03BF] + z header = data[vhdrlen : vhdrlen + 0x03BF] + z
else: else:
raise ValueError('Unknown index "%s"' % index) raise ValueError('Unknown index "%s"' % index)
return pyblake2.blake2s(header).digest() return pyblake2.blake2s(header).digest()
@ -35,20 +31,20 @@ def cli():
pass pass
@cli.command(help='') @cli.command(help="")
@click.argument('index', type=click.Choice(indexmap.keys())) @click.argument("index", type=click.Choice(indexmap.keys()))
@click.argument('filename') @click.argument("filename")
@click.argument('participants', nargs=-1) @click.argument("participants", nargs=-1)
def sign(index, filename, participants): def sign(index, filename, participants):
# compute header digest # compute header digest
digest = header_digest(index, filename) digest = header_digest(index, filename)
# create participant proxies # create participant proxies
if len(participants) < 1: if len(participants) < 1:
raise ValueError('Not enough participants') raise ValueError("Not enough participants")
print('connecting to %d participants:' % len(participants)) print("connecting to %d participants:" % len(participants))
proxy = [] proxy = []
for p in participants: for p in participants:
uri = 'PYRO:keyctl@%s:%d' % (p, PORT) uri = "PYRO:keyctl@%s:%d" % (p, PORT)
proxy.append(Pyro4.Proxy(uri)) proxy.append(Pyro4.Proxy(uri))
# collect commits # collect commits
pks, Rs = [], [] pks, Rs = [], []
@ -57,7 +53,7 @@ def sign(index, filename, participants):
pk, R = serpent.tobytes(pk), serpent.tobytes(R) pk, R = serpent.tobytes(pk), serpent.tobytes(R)
pks.append(pk) pks.append(pk)
Rs.append(R) Rs.append(R)
print('collected commit #%d from %s' % (i, p._pyroUri.host)) print("collected commit #%d from %s" % (i, p._pyroUri.host))
# compute global commit # compute global commit
global_pk = cosi.combine_keys(pks) global_pk = cosi.combine_keys(pks)
global_R = cosi.combine_keys(Rs) global_R = cosi.combine_keys(Rs)
@ -67,13 +63,13 @@ def sign(index, filename, participants):
sig = p.get_signature(index, digest, global_R, global_pk) sig = p.get_signature(index, digest, global_R, global_pk)
sig = serpent.tobytes(sig) sig = serpent.tobytes(sig)
sigs.append(sig) sigs.append(sig)
print('collected signature #%d from %s' % (i, p._pyroUri.host)) print("collected signature #%d from %s" % (i, p._pyroUri.host))
# compute global signature # compute global signature
sig = cosi.combine_sig(global_R, sigs) sig = cosi.combine_sig(global_R, sigs)
cosi.verify(sig, digest, global_pk) cosi.verify(sig, digest, global_pk)
print('global signature:') print("global signature:")
print(binascii.hexlify(sig).decode()) print(binascii.hexlify(sig).decode())
if __name__ == '__main__': if __name__ == "__main__":
cli() cli()

View File

@ -5,16 +5,13 @@ import Pyro4
import serpent import serpent
PORT = 5001 PORT = 5001
indexmap = { indexmap = {"bootloader": 0, "vendorheader": 1, "firmware": 2}
'bootloader': 0,
'vendorheader': 1,
'firmware': 2,
}
def get_trezor(): def get_trezor():
from trezorlib.client import TrezorClient from trezorlib.client import TrezorClient
from trezorlib.transport import get_transport from trezorlib.transport import get_transport
return TrezorClient(get_transport()) return TrezorClient(get_transport())
@ -24,7 +21,6 @@ def get_path(index):
@Pyro4.expose @Pyro4.expose
class KeyctlProxy(object): class KeyctlProxy(object):
def get_commit(self, index, digest): def get_commit(self, index, digest):
digest = serpent.tobytes(digest) digest = serpent.tobytes(digest)
path = get_path(index) path = get_path(index)
@ -32,41 +28,53 @@ class KeyctlProxy(object):
while commit is None: while commit is None:
try: try:
t = get_trezor() t = get_trezor()
print('\n\n\nCommiting to hash %s with path %s:' % (binascii.hexlify(digest).decode(), path)) print(
"\n\n\nCommiting to hash %s with path %s:"
% (binascii.hexlify(digest).decode(), path)
)
commit = t.cosi_commit(t.expand_path(path), digest) commit = t.cosi_commit(t.expand_path(path), digest)
except Exception as e: except Exception as e:
print(e) print(e)
print('Trying again ...') print("Trying again ...")
pk = commit.pubkey pk = commit.pubkey
R = commit.commitment R = commit.commitment
print('Commitment sent!') print("Commitment sent!")
return (pk, R) return (pk, R)
def get_signature(self, index, digest, global_R, global_pk): def get_signature(self, index, digest, global_R, global_pk):
digest, global_R, global_pk = serpent.tobytes(digest), serpent.tobytes(global_R), serpent.tobytes(global_pk) digest, global_R, global_pk = (
serpent.tobytes(digest),
serpent.tobytes(global_R),
serpent.tobytes(global_pk),
)
path = get_path(index) path = get_path(index)
signature = None signature = None
while signature is None: while signature is None:
try: try:
t = get_trezor() t = get_trezor()
print('\n\n\nSigning hash %s with path %s:' % (binascii.hexlify(digest).decode(), path)) print(
signature = t.cosi_sign(t.expand_path(path), digest, global_R, global_pk) "\n\n\nSigning hash %s with path %s:"
% (binascii.hexlify(digest).decode(), path)
)
signature = t.cosi_sign(
t.expand_path(path), digest, global_R, global_pk
)
except Exception as e: except Exception as e:
print(e) print(e)
print('Trying again ...') print("Trying again ...")
sig = signature.signature sig = signature.signature
print('Signature sent!') print("Signature sent!")
return sig return sig
if __name__ == '__main__': if __name__ == "__main__":
if len(sys.argv) > 1: if len(sys.argv) > 1:
ipaddr = sys.argv[1] ipaddr = sys.argv[1]
else: else:
print('Usage: keyctl-proxy ipaddress') print("Usage: keyctl-proxy ipaddress")
sys.exit(1) sys.exit(1)
daemon = Pyro4.Daemon(host=ipaddr, port=PORT) daemon = Pyro4.Daemon(host=ipaddr, port=PORT)
proxy = KeyctlProxy() proxy = KeyctlProxy()
uri = daemon.register(proxy, 'keyctl') uri = daemon.register(proxy, "keyctl")
print('keyctl-proxy running at URI: "%s"' % uri) print('keyctl-proxy running at URI: "%s"' % uri)
daemon.requestLoop() daemon.requestLoop()

View File

@ -12,7 +12,7 @@ def process_rgb(w, h, pix):
for i in range(w): for i in range(w):
r, g, b = pix[i, j] r, g, b = pix[i, j]
c = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3) c = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)
data += struct.pack('>H', c) data += struct.pack(">H", c)
return data return data
@ -22,89 +22,95 @@ def process_grayscale(w, h, pix):
for i in range(w // 2): for i in range(w // 2):
l1, l2 = pix[i * 2, j], pix[i * 2 + 1, j] l1, l2 = pix[i * 2, j], pix[i * 2 + 1, j]
c = (l1 & 0xF0) | (l2 >> 4) c = (l1 & 0xF0) | (l2 >> 4)
data += struct.pack('>B', c) data += struct.pack(">B", c)
return data return data
def process_image(ifn, savefiles=False): def process_image(ifn, savefiles=False):
im = Image.open(ifn) im = Image.open(ifn)
w, h = im.size w, h = im.size
print('Opened %s ... %d x %d @ %s' % (ifn, w, h, im.mode)) print("Opened %s ... %d x %d @ %s" % (ifn, w, h, im.mode))
if im.mode == 'RGB': if im.mode == "RGB":
print('Detected RGB mode') print("Detected RGB mode")
elif im.mode == 'L': elif im.mode == "L":
if w % 2 > 0: if w % 2 > 0:
print('PNG file must have width divisible by 2') print("PNG file must have width divisible by 2")
return 3 return 3
print('Detected GRAYSCALE mode') print("Detected GRAYSCALE mode")
else: else:
print('Unknown mode:', im.mode) print("Unknown mode:", im.mode)
return 4 return 4
pix = im.load() pix = im.load()
bname = basename(ifn[:-4]) bname = basename(ifn[:-4])
ofn_h = '%s.h' % bname ofn_h = "%s.h" % bname
ofn_py = '%s.py' % bname ofn_py = "%s.py" % bname
if im.mode == 'RGB': if im.mode == "RGB":
ofn = '%s.toif' % bname ofn = "%s.toif" % bname
pixeldata = process_rgb(w, h, pix) pixeldata = process_rgb(w, h, pix)
else: else:
ofn = '%s.toig' % bname ofn = "%s.toig" % bname
pixeldata = process_grayscale(w, h, pix) pixeldata = process_grayscale(w, h, pix)
z = zlib.compressobj(level=9, wbits=10) z = zlib.compressobj(level=9, wbits=10)
zdata = z.compress(pixeldata) + z.flush() zdata = z.compress(pixeldata) + z.flush()
zdata = zdata[2:-4] # strip header and checksum zdata = zdata[2:-4] # strip header and checksum
data = b'' data = b""
if im.mode == 'RGB': if im.mode == "RGB":
data += b'TOIf' data += b"TOIf"
else: else:
data += b'TOIg' data += b"TOIg"
data += struct.pack('<HH', w, h) data += struct.pack("<HH", w, h)
data += struct.pack('<I', len(zdata)) data += struct.pack("<I", len(zdata))
data += zdata data += zdata
if savefiles: if savefiles:
with open(ofn, 'wb') as f: with open(ofn, "wb") as f:
f.write(data) f.write(data)
print('Written %s ... %d bytes' % (ofn, len(data))) print("Written %s ... %d bytes" % (ofn, len(data)))
with open(ofn_py, 'wb') as f: with open(ofn_py, "wb") as f:
f.write(('%s = %s\n' % (bname, data)).encode()) f.write(("%s = %s\n" % (bname, data)).encode())
print('Written %s ... %d bytes' % (ofn_py, len(data))) print("Written %s ... %d bytes" % (ofn_py, len(data)))
with open(ofn_h, 'wt') as f: with open(ofn_h, "wt") as f:
f.write('// clang-format off\n') f.write("// clang-format off\n")
f.write('static const uint8_t toi_%s[] = {\n' % bname) f.write("static const uint8_t toi_%s[] = {\n" % bname)
f.write(' // magic\n') f.write(" // magic\n")
if im.mode == 'RGB': if im.mode == "RGB":
f.write(" 'T', 'O', 'I', 'f',\n") f.write(" 'T', 'O', 'I', 'f',\n")
else: else:
f.write(" 'T', 'O', 'I', 'g',\n") f.write(" 'T', 'O', 'I', 'g',\n")
f.write(' // width (16-bit), height (16-bit)\n') f.write(" // width (16-bit), height (16-bit)\n")
f.write(' 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n' % (w & 0xFF, w >> 8, h & 0xFF, h >> 8)) f.write(
" 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n"
% (w & 0xFF, w >> 8, h & 0xFF, h >> 8)
)
l = len(zdata) l = len(zdata)
f.write(' // compressed data length (32-bit)\n') f.write(" // compressed data length (32-bit)\n")
f.write(' 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n' % (l & 0xFF, (l >> 8) & 0xFF, (l >> 16) & 0xFF, l >> 24)) f.write(
f.write(' // compressed data\n') " 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n"
f.write(' ') % (l & 0xFF, (l >> 8) & 0xFF, (l >> 16) & 0xFF, l >> 24)
)
f.write(" // compressed data\n")
f.write(" ")
for b in zdata: for b in zdata:
f.write(' 0x%02x,' % b) f.write(" 0x%02x," % b)
f.write('\n};\n') f.write("\n};\n")
print('Written %s ... done' % ofn_py) print("Written %s ... done" % ofn_py)
return data return data
def main(): def main():
if len(sys.argv) < 2: if len(sys.argv) < 2:
print('Usage png2toi image.png') print("Usage png2toi image.png")
return 1 return 1
ifn = sys.argv[1] ifn = sys.argv[1]
if not ifn.endswith('.png'): if not ifn.endswith(".png"):
print('Must provide PNG file') print("Must provide PNG file")
return 2 return 2
process_image(ifn, savefiles=True) process_image(ifn, savefiles=True)

View File

@ -6,20 +6,20 @@ resources = {}
resources_size = 0 resources_size = 0
os.chdir(os.path.dirname(__file__)) os.chdir(os.path.dirname(__file__))
os.chdir('../src/') os.chdir("../src/")
def process_file(name): def process_file(name):
if name.endswith('.gitignore'): if name.endswith(".gitignore"):
return return
if name.endswith('.py'): if name.endswith(".py"):
return return
if os.path.basename(name).startswith('.'): if os.path.basename(name).startswith("."):
return return
with open(name, 'rb') as f: with open(name, "rb") as f:
data = f.read() data = f.read()
resources[name] = data resources[name] = data
print('processing file %s (%d bytes)' % (name, len(data))) print("processing file %s (%d bytes)" % (name, len(data)))
global resources_size global resources_size
resources_size += len(data) resources_size += len(data)
@ -33,33 +33,35 @@ def process_dir_rec(dir):
process_dir_rec(path) process_dir_rec(path)
process_dir_rec('trezor/res/') process_dir_rec("trezor/res/")
for name in os.listdir('apps/'): for name in os.listdir("apps/"):
path = os.path.join('apps/', name, 'res/') path = os.path.join("apps/", name, "res/")
if os.path.isdir(path): if os.path.isdir(path):
process_dir_rec(path) process_dir_rec(path)
resfile = 'trezor/res/resources.py' resfile = "trezor/res/resources.py"
bio = io.StringIO() bio = io.StringIO()
bio.write('# fmt: off\n') bio.write("# fmt: off\n")
bio.write('resdata = {\n') bio.write("resdata = {\n")
for k in sorted(resources.keys()): for k in sorted(resources.keys()):
bio.write(" '%s': %s,\n" % (k, resources[k])) bio.write(" '%s': %s,\n" % (k, resources[k]))
bio.write('}\n') bio.write("}\n")
try: try:
with open(resfile, 'r') as f: with open(resfile, "r") as f:
stale = f.read() stale = f.read()
except: except FileNotFoundError:
stale = None stale = None
fresh = bio.getvalue() fresh = bio.getvalue()
if stale != fresh: if stale != fresh:
with open(resfile, 'wt') as f: with open(resfile, "wt") as f:
f.write(fresh) f.write(fresh)
print('written %s with %d entries (total %d bytes)' % print(
(resfile, len(resources), resources_size)) "written %s with %d entries (total %d bytes)"
% (resfile, len(resources), resources_size)
)
else: else:
print('continuing with %s, no changes detected' % (resfile)) print("continuing with %s, no changes detected" % (resfile))

View File

@ -25,62 +25,64 @@ def process_grayscale(w, h, data):
def process_image(ifn, ofn): def process_image(ifn, ofn):
data = open(ifn, 'rb').read() data = open(ifn, "rb").read()
if ifn.endswith('.toif'): if ifn.endswith(".toif"):
if data[:4] != b'TOIf': if data[:4] != b"TOIf":
print('Unknown TOIF header') print("Unknown TOIF header")
return 1 return 1
elif ifn.endswith('.toig'): elif ifn.endswith(".toig"):
if data[:4] != b'TOIg': if data[:4] != b"TOIg":
print('Unknown TOIG header') print("Unknown TOIG header")
return 2 return 2
else: else:
print('Unsupported format') print("Unsupported format")
return 3 return 3
if ofn is None: if ofn is None:
ofn = '%s.png' % ifn[:-5] ofn = "%s.png" % ifn[:-5]
w, h = struct.unpack('<HH', data[4:8]) w, h = struct.unpack("<HH", data[4:8])
print('Opened %s ... %d x %d' % (ifn, w, h)) print("Opened %s ... %d x %d" % (ifn, w, h))
l = struct.unpack('<I', data[8:12])[0] l = struct.unpack("<I", data[8:12])[0]
data = data[12:] data = data[12:]
if len(data) != l: if len(data) != l:
print('Compressed data length mismatch (%d vs %d)' % (len(data), l)) print("Compressed data length mismatch (%d vs %d)" % (len(data), l))
return 4 return 4
data = zlib.decompress(data, -10) data = zlib.decompress(data, -10)
if ifn.endswith('.toif'): if ifn.endswith(".toif"):
if len(data) != w * h * 2: if len(data) != w * h * 2:
print('Uncompressed data length mismatch (%d vs %d)' % print(
(len(data), w * h * 2)) "Uncompressed data length mismatch (%d vs %d)" % (len(data), w * h * 2)
)
return 5 return 5
pix = process_rgb(w, h, data) pix = process_rgb(w, h, data)
img = Image.frombuffer('RGB', (w, h), pix, 'raw', 'RGB', 0, 1) img = Image.frombuffer("RGB", (w, h), pix, "raw", "RGB", 0, 1)
img.save(ofn) img.save(ofn)
print('Written %s ...' % ofn) print("Written %s ..." % ofn)
if ifn.endswith('.toig'): if ifn.endswith(".toig"):
if len(data) != w * h // 2: if len(data) != w * h // 2:
print('Uncompressed data length mismatch (%d vs %d)' % print(
(len(data), w * h // 2)) "Uncompressed data length mismatch (%d vs %d)" % (len(data), w * h // 2)
)
return 6 return 6
pix = process_grayscale(w, h, data) pix = process_grayscale(w, h, data)
img = Image.frombuffer('L', (w, h), pix, 'raw', 'L', 0, 1) img = Image.frombuffer("L", (w, h), pix, "raw", "L", 0, 1)
img.save(ofn) img.save(ofn)
print('Written %s ...' % ofn) print("Written %s ..." % ofn)
def main(): def main():
if len(sys.argv) < 2: if len(sys.argv) < 2:
print('Usage: toi2png image.toi[fg] [output]') print("Usage: toi2png image.toi[fg] [output]")
return 1 return 1
ifn = sys.argv[1] ifn = sys.argv[1]
if not ifn.endswith('.toif') and not ifn.endswith('.toig'): if not ifn.endswith(".toif") and not ifn.endswith(".toig"):
print('Must provide TOIF/TOIG file') print("Must provide TOIF/TOIG file")
return 2 return 2
ofn = sys.argv[2] if len(sys.argv) > 2 else None ofn = sys.argv[2] if len(sys.argv) > 2 else None