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:
parent
481bb4ccab
commit
10396777b8
272
tools/binctl
272
tools/binctl
@ -12,24 +12,24 @@ from trezorlib import cosi
|
||||
|
||||
|
||||
def format_sigmask(sigmask):
|
||||
bits = [str(b + 1) if sigmask & (1 << b) else '.' for b in range(8)]
|
||||
return '0x%02x = [%s]' % (sigmask, ' '.join(bits))
|
||||
bits = [str(b + 1) if sigmask & (1 << b) else "." for b in range(8)]
|
||||
return "0x%02x = [%s]" % (sigmask, " ".join(bits))
|
||||
|
||||
|
||||
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
|
||||
desc = ''
|
||||
desc = ""
|
||||
wait = (vtrust & 0x000F) ^ 0x000F
|
||||
if wait > 0:
|
||||
desc = 'WAIT_%d' % wait
|
||||
desc = "WAIT_%d" % wait
|
||||
if vtrust & 0x0010 == 0:
|
||||
desc += ' RED'
|
||||
desc += " RED"
|
||||
if vtrust & 0x0020 == 0:
|
||||
desc += ' CLICK'
|
||||
desc += " CLICK"
|
||||
if vtrust & 0x0040 == 0:
|
||||
desc += ' STRING'
|
||||
return '%d = [%s] = [%s]' % (vtrust, ' '.join(bits), desc)
|
||||
desc += " STRING"
|
||||
return "%d = [%s] = [%s]" % (vtrust, " ".join(bits), desc)
|
||||
|
||||
|
||||
# bootloader/firmware headers specification: https://github.com/trezor/trezor-core/blob/master/docs/bootloader.md
|
||||
@ -42,67 +42,61 @@ FIRMWARE_SECTORS_COUNT = 6 + 7
|
||||
|
||||
|
||||
class BinImage(object):
|
||||
|
||||
def __init__(self, data, magic, max_size):
|
||||
header = struct.unpack('<4sIIIBBBBBBBB8s512s415sB64s', data[:IMAGE_HEADER_SIZE])
|
||||
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 = header
|
||||
header = struct.unpack("<4sIIIBBBBBBBB8s512s415sB64s", data[:IMAGE_HEADER_SIZE])
|
||||
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 = (
|
||||
header
|
||||
)
|
||||
assert self.magic == magic
|
||||
assert self.hdrlen == IMAGE_HEADER_SIZE
|
||||
total_len = self.hdrlen + self.codelen
|
||||
assert total_len % 512 == 0
|
||||
assert total_len >= 4 * 1024
|
||||
assert total_len <= max_size
|
||||
assert self.reserved1 == 8 * b'\x00'
|
||||
assert self.reserved2 == 415 * b'\x00'
|
||||
assert self.reserved1 == 8 * b"\x00"
|
||||
assert self.reserved2 == 415 * b"\x00"
|
||||
self.code = data[self.hdrlen :]
|
||||
assert len(self.code) == self.codelen
|
||||
|
||||
def print(self):
|
||||
if self.magic == b'TRZF':
|
||||
print('TREZOR Firmware Image')
|
||||
if self.magic == b"TRZF":
|
||||
print("TREZOR Firmware Image")
|
||||
total_len = self.vhdrlen + self.hdrlen + self.codelen
|
||||
elif self.magic == b'TRZB':
|
||||
print('TREZOR Bootloader Image')
|
||||
elif self.magic == b"TRZB":
|
||||
print("TREZOR Bootloader Image")
|
||||
total_len = self.hdrlen + self.codelen
|
||||
else:
|
||||
print('TREZOR Unknown Image')
|
||||
print(' * magic :', self.magic.decode())
|
||||
print(' * hdrlen :', self.hdrlen)
|
||||
print(' * expiry :', self.expiry)
|
||||
print(' * codelen :', self.codelen)
|
||||
print(' * version : %d.%d.%d.%d' % (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'))
|
||||
print("TREZOR Unknown Image")
|
||||
print(" * magic :", self.magic.decode())
|
||||
print(" * hdrlen :", self.hdrlen)
|
||||
print(" * expiry :", self.expiry)
|
||||
print(" * codelen :", self.codelen)
|
||||
print(
|
||||
" * version : %d.%d.%d.%d"
|
||||
% (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):
|
||||
print(' - %02d : %s' % (i, binascii.hexlify(self.hashes[i * 32:i * 32 + 32]).decode()))
|
||||
print(' * sigmask :', format_sigmask(self.sigmask))
|
||||
print(' * sig :', binascii.hexlify(self.sig).decode())
|
||||
print(' * total : %d bytes' % total_len)
|
||||
print(' * fngprnt :', self.fingerprint())
|
||||
print(
|
||||
" - %02d : %s"
|
||||
% (i, binascii.hexlify(self.hashes[i * 32 : i * 32 + 32]).decode())
|
||||
)
|
||||
print(" * sigmask :", format_sigmask(self.sigmask))
|
||||
print(" * sig :", binascii.hexlify(self.sig).decode())
|
||||
print(" * total : %d bytes" % total_len)
|
||||
print(" * fngprnt :", self.fingerprint())
|
||||
print()
|
||||
|
||||
def compute_hashes(self):
|
||||
if self.magic == b'TRZF':
|
||||
if self.magic == b"TRZF":
|
||||
hdrlen = self.vhdrlen + self.hdrlen
|
||||
else:
|
||||
hdrlen = self.hdrlen
|
||||
hashes = b''
|
||||
hashes = b""
|
||||
for i in range(16):
|
||||
if i == 0:
|
||||
d = self.code[: IMAGE_CHUNK_SIZE - hdrlen]
|
||||
@ -112,7 +106,7 @@ class BinImage(object):
|
||||
if len(d) > 0:
|
||||
h = pyblake2.blake2s(d).digest()
|
||||
else:
|
||||
h = 32 * b'\x00'
|
||||
h = 32 * b"\x00"
|
||||
hashes += h
|
||||
return hashes
|
||||
|
||||
@ -123,15 +117,28 @@ class BinImage(object):
|
||||
self.hashes = self.compute_hashes()
|
||||
|
||||
def serialize_header(self, sig=True):
|
||||
header = struct.pack('<4sIIIBBBBBBBB8s512s415s',
|
||||
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)
|
||||
header = struct.pack(
|
||||
"<4sIIIBBBBBBBB8s512s415s",
|
||||
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,
|
||||
)
|
||||
if sig:
|
||||
header += struct.pack('<B64s', self.sigmask, self.sig)
|
||||
header += struct.pack("<B64s", self.sigmask, self.sig)
|
||||
else:
|
||||
header += IMAGE_SIG_SIZE * b'\x00'
|
||||
header += IMAGE_SIG_SIZE * b"\x00"
|
||||
assert len(header) == self.hdrlen
|
||||
return header
|
||||
|
||||
@ -146,44 +153,42 @@ class BinImage(object):
|
||||
self.sig = signature
|
||||
|
||||
def write(self, filename):
|
||||
with open(filename, 'wb') as f:
|
||||
with open(filename, "wb") as f:
|
||||
f.write(self.serialize_header())
|
||||
f.write(self.code)
|
||||
|
||||
|
||||
class FirmwareImage(BinImage):
|
||||
|
||||
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.vheader = data[:vhdrlen]
|
||||
|
||||
def write(self, filename):
|
||||
with open(filename, 'wb') as f:
|
||||
with open(filename, "wb") as f:
|
||||
f.write(self.vheader)
|
||||
f.write(self.serialize_header())
|
||||
f.write(self.code)
|
||||
|
||||
|
||||
class BootloaderImage(BinImage):
|
||||
|
||||
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):
|
||||
|
||||
def __init__(self, data):
|
||||
header = struct.unpack('<4sIIBBBBH', data[:18])
|
||||
self.magic, \
|
||||
self.hdrlen, \
|
||||
self.expiry, \
|
||||
self.vmajor, \
|
||||
self.vminor, \
|
||||
self.vsig_m, \
|
||||
self.vsig_n, \
|
||||
self.vtrust = header
|
||||
assert self.magic == b'TRZV'
|
||||
header = struct.unpack("<4sIIBBBBH", data[:18])
|
||||
self.magic, self.hdrlen, self.expiry, self.vmajor, self.vminor, 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_n > 0 and self.vsig_n <= 8
|
||||
@ -204,46 +209,66 @@ class VendorHeader(object):
|
||||
self.sigmask = data[p]
|
||||
p += 1
|
||||
self.sig = data[p : p + 64]
|
||||
assert len(data) == 4 + 4 + 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)
|
||||
== 4
|
||||
+ 4
|
||||
+ 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
|
||||
|
||||
def print(self):
|
||||
print('TREZOR Vendor Header')
|
||||
print(' * magic :', self.magic.decode())
|
||||
print(' * hdrlen :', self.hdrlen)
|
||||
print(' * expiry :', self.expiry)
|
||||
print(' * version : %d.%d' % (self.vmajor, self.vminor))
|
||||
print(' * scheme : %d out of %d' % (self.vsig_m, self.vsig_n))
|
||||
print(' * trust :', format_vtrust(self.vtrust))
|
||||
print("TREZOR Vendor Header")
|
||||
print(" * magic :", self.magic.decode())
|
||||
print(" * hdrlen :", self.hdrlen)
|
||||
print(" * expiry :", self.expiry)
|
||||
print(" * version : %d.%d" % (self.vmajor, self.vminor))
|
||||
print(" * scheme : %d out of %d" % (self.vsig_m, self.vsig_n))
|
||||
print(" * trust :", format_vtrust(self.vtrust))
|
||||
for i in range(self.vsig_n):
|
||||
print(' * vpub #%d :' % (i + 1), binascii.hexlify(self.vpub[i]).decode())
|
||||
print(' * vstr :', self.vstr.decode())
|
||||
print(' * vhash :', binascii.hexlify(self.vhash()).decode())
|
||||
print(' * vimg : (%d bytes)' % len(self.vimg))
|
||||
print(' * sigmask :', format_sigmask(self.sigmask))
|
||||
print(' * sig :', binascii.hexlify(self.sig).decode())
|
||||
print(' * fngprnt :', self.fingerprint())
|
||||
print(" * vpub #%d :" % (i + 1), binascii.hexlify(self.vpub[i]).decode())
|
||||
print(" * vstr :", self.vstr.decode())
|
||||
print(" * vhash :", binascii.hexlify(self.vhash()).decode())
|
||||
print(" * vimg : (%d bytes)" % len(self.vimg))
|
||||
print(" * sigmask :", format_sigmask(self.sigmask))
|
||||
print(" * sig :", binascii.hexlify(self.sig).decode())
|
||||
print(" * fngprnt :", self.fingerprint())
|
||||
print()
|
||||
|
||||
def serialize_header(self, sig=True):
|
||||
header = struct.pack('<4sIIBBBBH',
|
||||
self.magic, self.hdrlen, self.expiry,
|
||||
self.vmajor, self.vminor,
|
||||
self.vsig_m, self.vsig_n, self.vtrust)
|
||||
header += 14 * b'\x00'
|
||||
header = struct.pack(
|
||||
"<4sIIBBBBH",
|
||||
self.magic,
|
||||
self.hdrlen,
|
||||
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):
|
||||
header += self.vpub[i]
|
||||
header += struct.pack('<B', self.vstr_len) + self.vstr
|
||||
header += (-len(header) & 3) * b'\x00' # vstr_pad
|
||||
header += struct.pack("<B", self.vstr_len) + self.vstr
|
||||
header += (-len(header) & 3) * b"\x00" # vstr_pad
|
||||
header += self.vimg
|
||||
if sig:
|
||||
header += struct.pack('<B64s', self.sigmask, self.sig)
|
||||
header += struct.pack("<B64s", self.sigmask, self.sig)
|
||||
else:
|
||||
header += IMAGE_SIG_SIZE * b'\x00'
|
||||
header += IMAGE_SIG_SIZE * b"\x00"
|
||||
assert len(header) == self.hdrlen
|
||||
return header
|
||||
|
||||
@ -252,12 +277,12 @@ class VendorHeader(object):
|
||||
|
||||
def vhash(self):
|
||||
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):
|
||||
if i < self.vsig_n:
|
||||
h.update(self.vpub[i])
|
||||
else:
|
||||
h.update(b'\x00' * 32)
|
||||
h.update(b"\x00" * 32)
|
||||
return h.digest()
|
||||
|
||||
def sign(self, sigmask, signature):
|
||||
@ -267,54 +292,57 @@ class VendorHeader(object):
|
||||
self.sig = signature
|
||||
|
||||
def write(self, filename):
|
||||
with open(filename, 'wb') as f:
|
||||
with open(filename, "wb") as f:
|
||||
f.write(self.serialize_header())
|
||||
|
||||
|
||||
def binopen(filename):
|
||||
data = open(filename, 'rb').read()
|
||||
data = open(filename, "rb").read()
|
||||
magic = data[:4]
|
||||
if magic == b'TRZB':
|
||||
if magic == b"TRZB":
|
||||
return BootloaderImage(data)
|
||||
if magic == b'TRZV':
|
||||
if magic == b"TRZV":
|
||||
vheader = VendorHeader(data)
|
||||
if len(data) == vheader.hdrlen:
|
||||
return vheader
|
||||
vheader.print()
|
||||
subdata = data[vheader.hdrlen :]
|
||||
if subdata[:4] == b'TRZF':
|
||||
if subdata[:4] == b"TRZF":
|
||||
firmware = FirmwareImage(data, vheader.hdrlen)
|
||||
# check signatures against signing keys in the vendor header
|
||||
if firmware.sigmask > 0:
|
||||
pk = [vheader.vpub[i] for i in range(8) if firmware.sigmask & (1 << i)]
|
||||
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()
|
||||
try:
|
||||
cosi.verify(firmware.sig, digest, global_pk)
|
||||
print('Firmware signature OK')
|
||||
except:
|
||||
print('Firmware signature INCORRECT')
|
||||
print("Firmware signature OK")
|
||||
except ValueError:
|
||||
print("Firmware signature INCORRECT")
|
||||
else:
|
||||
print('No firmware signature')
|
||||
print("No firmware signature")
|
||||
return firmware
|
||||
if magic == b'TRZF':
|
||||
if magic == b"TRZF":
|
||||
return FirmwareImage(data, 0)
|
||||
raise Exception('Unknown file format')
|
||||
raise Exception("Unknown file format")
|
||||
|
||||
|
||||
def main():
|
||||
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
|
||||
fn = sys.argv[1]
|
||||
sign = len(sys.argv) > 2 and sys.argv[2] == '-s'
|
||||
rehash = len(sys.argv) == 3 and sys.argv[2] == '-h'
|
||||
sign = len(sys.argv) > 2 and sys.argv[2] == "-s"
|
||||
rehash = len(sys.argv) == 3 and sys.argv[2] == "-h"
|
||||
b = binopen(fn)
|
||||
if sign:
|
||||
sigmask = 0
|
||||
if ':' in sys.argv[3]:
|
||||
for idx in sys.argv[3].split(':'):
|
||||
if ":" in sys.argv[3]:
|
||||
for idx in sys.argv[3].split(":"):
|
||||
sigmask |= 1 << (int(idx) - 1)
|
||||
else:
|
||||
sigmask = 1 << (int(sys.argv[3]) - 1)
|
||||
@ -327,5 +355,5 @@ def main():
|
||||
b.print()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
|
||||
COMMENT_PREFIX = '/// '
|
||||
COMMENT_PREFIX = "/// "
|
||||
|
||||
current_indent = 0
|
||||
current_class = None
|
||||
@ -14,24 +14,24 @@ def split_to_parts(line, mod_desc=None):
|
||||
global current_class
|
||||
global current_method
|
||||
|
||||
if line.startswith('class '):
|
||||
current_class = line[6:].split('(')[0].strip(':')
|
||||
if line.startswith("class "):
|
||||
current_class = line[6:].split("(")[0].strip(":")
|
||||
current_indent = 0
|
||||
|
||||
yield (current_package, "\n")
|
||||
yield (current_package, '# ' + mod_desc + "\n")
|
||||
yield (current_package, "# " + mod_desc + "\n")
|
||||
|
||||
elif line.startswith('def '):
|
||||
current_method = line[4:].split('(')[0]
|
||||
elif line.startswith("def "):
|
||||
current_method = line[4:].split("(")[0]
|
||||
|
||||
yield (current_package, "\n")
|
||||
|
||||
if current_class is None:
|
||||
yield (current_package, '# ' + mod_desc + "\n")
|
||||
yield (current_package, "# " + mod_desc + "\n")
|
||||
else:
|
||||
current_indent = 4
|
||||
|
||||
line = current_indent * ' ' + line
|
||||
line = current_indent * " " + line
|
||||
|
||||
yield (current_package, line)
|
||||
|
||||
@ -43,16 +43,16 @@ def store_to_file(dest, parts):
|
||||
|
||||
if not os.path.exists(dirpath):
|
||||
os.makedirs(dirpath)
|
||||
open(os.path.join(dirpath, '__init__.py'), 'w').close()
|
||||
open(os.path.join(dirpath, '.mock-generated'), 'w').close()
|
||||
open(os.path.join(dirpath, "__init__.py"), "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):
|
||||
with open(filepath, 'a') as f:
|
||||
f.write('from typing import *\n')
|
||||
with open(filepath, "a") as f:
|
||||
f.write("from typing import *\n")
|
||||
|
||||
with open(filepath, 'a') as f:
|
||||
with open(filepath, "a") as f:
|
||||
f.write(line)
|
||||
|
||||
|
||||
@ -61,18 +61,17 @@ def build_module(mod_file, dest):
|
||||
global current_class
|
||||
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
|
||||
if not os.path.basename(mod_file).startswith('mod'):
|
||||
if not os.path.basename(mod_file).startswith("mod"):
|
||||
return
|
||||
|
||||
current_indent = 0
|
||||
current_class = None
|
||||
current_package = os.path.basename(mod_file) \
|
||||
.split('.')[0] \
|
||||
.split('-')[0] \
|
||||
.replace('mod', '')
|
||||
mod_desc = mod_file.replace('../embed/extmod', 'extmod')
|
||||
current_package = (
|
||||
os.path.basename(mod_file).split(".")[0].split("-")[0].replace("mod", "")
|
||||
)
|
||||
mod_desc = mod_file.replace("../embed/extmod", "extmod")
|
||||
|
||||
for l in open(mod_file):
|
||||
if not l.startswith(COMMENT_PREFIX):
|
||||
@ -92,7 +91,7 @@ def build_directory(dir, dest):
|
||||
def clear_directory(top_dir):
|
||||
print("Clearing up directory", top_dir)
|
||||
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)
|
||||
continue
|
||||
for name in files:
|
||||
@ -108,6 +107,6 @@ def clear_directory(top_dir):
|
||||
os.rmdir(root)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
clear_directory('../mocks/generated')
|
||||
build_directory('../embed/extmod', '../mocks/generated')
|
||||
if __name__ == "__main__":
|
||||
clear_directory("../mocks/generated")
|
||||
build_directory("../embed/extmod", "../mocks/generated")
|
||||
|
@ -3,58 +3,62 @@ import sys
|
||||
import struct
|
||||
import binascii
|
||||
|
||||
|
||||
# encode vendor name, add length byte and padding to multiple of 4
|
||||
def encode_vendor(vname):
|
||||
vbin = vname.encode()
|
||||
vbin = struct.pack('<B', len(vbin)) + vbin
|
||||
vbin += b'\0' * (-len(vbin) & 3)
|
||||
vbin = struct.pack("<B", len(vbin)) + vbin
|
||||
vbin += b"\0" * (-len(vbin) & 3)
|
||||
return vbin
|
||||
|
||||
|
||||
def encode_pubkey(pubkey):
|
||||
if len(pubkey) != 64:
|
||||
raise Exception('Wrong public key length')
|
||||
raise Exception("Wrong public key length")
|
||||
return binascii.unhexlify(pubkey)
|
||||
|
||||
|
||||
def decode_vtrust(vtrust):
|
||||
t = 0xFFFF
|
||||
for i, b in enumerate(reversed(vtrust)):
|
||||
if b != '.':
|
||||
if b != ".":
|
||||
t &= ~(1 << i)
|
||||
return t
|
||||
|
||||
|
||||
def main():
|
||||
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
|
||||
|
||||
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])
|
||||
(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])
|
||||
vname = sys.argv[5]
|
||||
ifn = sys.argv[6]
|
||||
ofn = sys.argv[7]
|
||||
if not ifn.endswith('.toif'):
|
||||
print('Must provide TOIF file')
|
||||
if not ifn.endswith(".toif"):
|
||||
print("Must provide TOIF file")
|
||||
return 2
|
||||
|
||||
expiry = 0
|
||||
vheader = b'TRZV' + \
|
||||
struct.pack('<IIBBBBH', 0, expiry, vmajor, vminor, m, len(keys), vtrust)
|
||||
vheader += 14 * b'\0'
|
||||
vheader = b"TRZV" + struct.pack(
|
||||
"<IIBBBBH", 0, expiry, vmajor, vminor, m, len(keys), vtrust
|
||||
)
|
||||
vheader += 14 * b"\0"
|
||||
for k in keys:
|
||||
vheader += k
|
||||
vheader += encode_vendor(vname) + open(ifn, 'rb').read()
|
||||
vheader += encode_vendor(vname) + open(ifn, "rb").read()
|
||||
padding = 65 + (-len(vheader) - 65) & 511
|
||||
vheader += b'\0' * padding
|
||||
vheader += b"\0" * padding
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
|
@ -5,16 +5,19 @@ from hashlib import sha256
|
||||
import requests
|
||||
|
||||
|
||||
REPO = 'certifi/python-certifi'
|
||||
REPO = "certifi/python-certifi"
|
||||
|
||||
|
||||
def fetch_certdata():
|
||||
r = requests.get('https://api.github.com/repos/%s/git/refs/heads/master' % REPO)
|
||||
assert(r.status_code == 200)
|
||||
commithash = r.json()['object']['sha']
|
||||
r = requests.get("https://api.github.com/repos/%s/git/refs/heads/master" % REPO)
|
||||
assert r.status_code == 200
|
||||
commithash = r.json()["object"]["sha"]
|
||||
|
||||
r = requests.get('https://raw.githubusercontent.com/%s/%s/certifi/cacert.pem' % (REPO, commithash))
|
||||
assert(r.status_code == 200)
|
||||
r = requests.get(
|
||||
"https://raw.githubusercontent.com/%s/%s/certifi/cacert.pem"
|
||||
% (REPO, commithash)
|
||||
)
|
||||
assert r.status_code == 200
|
||||
certdata = r.text
|
||||
|
||||
return commithash, certdata
|
||||
@ -22,21 +25,21 @@ def fetch_certdata():
|
||||
|
||||
def process_certdata(data):
|
||||
certs = {}
|
||||
lines = [x.strip() for x in data.split('\n')]
|
||||
lines = [x.strip() for x in data.split("\n")]
|
||||
label = None
|
||||
value = None
|
||||
for line in lines:
|
||||
if line.startswith('# Label: '):
|
||||
assert(label is None)
|
||||
assert(value is None)
|
||||
if line.startswith("# Label: "):
|
||||
assert label is None
|
||||
assert value is None
|
||||
label = line.split('"')[1]
|
||||
elif line == '-----BEGIN CERTIFICATE-----':
|
||||
assert(label is not None)
|
||||
assert(value is None)
|
||||
value = ''
|
||||
elif line == '-----END CERTIFICATE-----':
|
||||
assert(label is not None)
|
||||
assert(value is not None)
|
||||
elif line == "-----BEGIN CERTIFICATE-----":
|
||||
assert label is not None
|
||||
assert value is None
|
||||
value = ""
|
||||
elif line == "-----END CERTIFICATE-----":
|
||||
assert label is not None
|
||||
assert value is not None
|
||||
certs[label] = b64decode(value)
|
||||
label, value = None, None
|
||||
else:
|
||||
@ -49,22 +52,25 @@ def process_certdata(data):
|
||||
def main():
|
||||
commithash, certdata = fetch_certdata()
|
||||
|
||||
print('# fetched from https://github.com/%s' % REPO)
|
||||
print('# commit %s' % commithash)
|
||||
print("# fetched from https://github.com/%s" % REPO)
|
||||
print("# commit %s" % commithash)
|
||||
|
||||
certs = process_certdata(certdata)
|
||||
|
||||
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():
|
||||
h = sha256(v)
|
||||
print(' # %s' % k)
|
||||
print(' # %s' % h.hexdigest())
|
||||
print(' %s,' % h.digest())
|
||||
print(']')
|
||||
print(" # %s" % k)
|
||||
print(" # %s" % h.hexdigest())
|
||||
print(" %s," % h.digest())
|
||||
print("]")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -2,43 +2,43 @@
|
||||
import json
|
||||
|
||||
fields = [
|
||||
'coin_name',
|
||||
'coin_shortcut',
|
||||
'address_type',
|
||||
'address_type_p2sh',
|
||||
'maxfee_kb',
|
||||
'signed_message_header',
|
||||
'xpub_magic',
|
||||
'bech32_prefix',
|
||||
'cashaddr_prefix',
|
||||
'slip44',
|
||||
'segwit',
|
||||
'fork_id',
|
||||
'force_bip143',
|
||||
'version_group_id',
|
||||
'bip115',
|
||||
'curve_name',
|
||||
"coin_name",
|
||||
"coin_shortcut",
|
||||
"address_type",
|
||||
"address_type_p2sh",
|
||||
"maxfee_kb",
|
||||
"signed_message_header",
|
||||
"xpub_magic",
|
||||
"bech32_prefix",
|
||||
"cashaddr_prefix",
|
||||
"slip44",
|
||||
"segwit",
|
||||
"fork_id",
|
||||
"force_bip143",
|
||||
"version_group_id",
|
||||
"bip115",
|
||||
"curve_name",
|
||||
]
|
||||
|
||||
support = json.load(open('../../vendor/trezor-common/defs/support.json', 'r'))
|
||||
coins = support['trezor2'].keys()
|
||||
support = json.load(open("../../vendor/trezor-common/defs/support.json", "r"))
|
||||
coins = support["trezor2"].keys()
|
||||
|
||||
print('COINS = [')
|
||||
print("COINS = [")
|
||||
|
||||
for c in coins:
|
||||
print(' CoinInfo(')
|
||||
name = c.replace(' ', '_').lower()
|
||||
if name == 'testnet':
|
||||
name = 'bitcoin_testnet'
|
||||
data = json.load(open('../../vendor/trezor-common/defs/coins/%s.json' % name, 'r'))
|
||||
print(" CoinInfo(")
|
||||
name = c.replace(" ", "_").lower()
|
||||
if name == "testnet":
|
||||
name = "bitcoin_testnet"
|
||||
data = json.load(open("../../vendor/trezor-common/defs/coins/%s.json" % name, "r"))
|
||||
for n in fields:
|
||||
if n in ['xpub_magic', 'version_group_id']:
|
||||
v = '0x%08x' % data[n] if data[n] is not None else 'None'
|
||||
if n in ["xpub_magic", "version_group_id"]:
|
||||
v = "0x%08x" % data[n] if data[n] is not None else "None"
|
||||
else:
|
||||
v = repr(data[n])
|
||||
if n == 'curve_name':
|
||||
v = v.replace('_', '-')
|
||||
print(' %s=%s,' % (n, v))
|
||||
print(' ),')
|
||||
if n == "curve_name":
|
||||
v = v.replace("_", "-")
|
||||
print(" %s=%s," % (n, v))
|
||||
print(" ),")
|
||||
|
||||
print(']')
|
||||
print("]")
|
||||
|
@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
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:
|
||||
print(' NetworkInfo(')
|
||||
for f in ['chain_id', 'slip44', 'shortcut', 'name', 'rskip60']:
|
||||
print(' %s=%s,' % (f, repr(n[f])))
|
||||
print(' ),')
|
||||
print(" NetworkInfo(")
|
||||
for f in ["chain_id", "slip44", "shortcut", "name", "rskip60"]:
|
||||
print(" %s=%s," % (f, repr(n[f])))
|
||||
print(" ),")
|
||||
|
||||
print(']')
|
||||
print("]")
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
import freetype
|
||||
|
||||
MIN_GLYPH = ord(' ')
|
||||
MAX_GLYPH = ord('~')
|
||||
MIN_GLYPH = ord(" ")
|
||||
MAX_GLYPH = ord("~")
|
||||
|
||||
FONT_BPP = 4
|
||||
|
||||
@ -14,20 +14,23 @@ FONT_BPP = 4
|
||||
|
||||
|
||||
def process_face(name, style, size):
|
||||
print('Processing ... %s %s %s' % (name, style, size))
|
||||
face = freetype.Face('/usr/share/fonts/truetype/%s-%s.ttf' % (name, style))
|
||||
print("Processing ... %s %s %s" % (name, style, size))
|
||||
face = freetype.Face("/usr/share/fonts/truetype/%s-%s.ttf" % (name, style))
|
||||
face.set_pixel_sizes(0, size)
|
||||
fontname = '%s_%s_%d' % (name.lower(), style.lower(), size)
|
||||
with open('font_%s.h' % fontname, 'wt') as f:
|
||||
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))
|
||||
with open('font_%s.c' % fontname, 'wt') as f:
|
||||
fontname = "%s_%s_%d" % (name.lower(), style.lower(), size)
|
||||
with open("font_%s.h" % fontname, "wt") as f:
|
||||
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)
|
||||
)
|
||||
with open("font_%s.c" % fontname, "wt") as f:
|
||||
f.write('#include "font_%s.h"\n\n' % fontname)
|
||||
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('// bearingX and bearingY of the horizontal metrics of the glyph\n')
|
||||
f.write('// rest is packed 4-bit glyph data\n\n')
|
||||
f.write('// clang-format off\n\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("// bearingX and bearingY of the horizontal metrics of the glyph\n")
|
||||
f.write("// rest is packed 4-bit glyph data\n\n")
|
||||
f.write("// clang-format off\n\n")
|
||||
for i in range(MIN_GLYPH, MAX_GLYPH + 1):
|
||||
c = chr(i)
|
||||
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
|
||||
# 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
|
||||
if c in 'jy}),/' and bearingX < 0:
|
||||
if c in "jy}),/" and bearingX < 0:
|
||||
advance += -bearingX
|
||||
bearingX = 0
|
||||
bearingY = metrics.horiBearingY // 64
|
||||
assert advance >= 0 and advance <= 255
|
||||
assert bearingX >= 0 and bearingX <= 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))
|
||||
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))
|
||||
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,
|
||||
)
|
||||
)
|
||||
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)
|
||||
if len(buf) > 0:
|
||||
if FONT_BPP == 2:
|
||||
for _ in range(4 - len(buf) % 4):
|
||||
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:
|
||||
if len(buf) % 2 > 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)]]
|
||||
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))
|
||||
buf = [
|
||||
((a & 0xF0) | (b >> 4))
|
||||
for a, b in [buf[i : i + 2] for i in range(0, len(buf), 2)]
|
||||
]
|
||||
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):
|
||||
f.write(' Font_%s_%s_%d_glyph_%d,\n' % (name, style, size, i))
|
||||
f.write('};\n')
|
||||
f.write(" Font_%s_%s_%d_glyph_%d,\n" % (name, style, size, i))
|
||||
f.write("};\n")
|
||||
|
||||
|
||||
process_face('Roboto', 'Regular', 20)
|
||||
process_face('Roboto', 'Bold', 20)
|
||||
process_face('RobotoMono', 'Regular', 20)
|
||||
process_face("Roboto", "Regular", 20)
|
||||
process_face("Roboto", "Bold", 20)
|
||||
process_face("RobotoMono", "Regular", 20)
|
||||
|
@ -5,16 +5,16 @@ from trezorlib import ed25519raw
|
||||
|
||||
|
||||
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()
|
||||
seckey = c.encode() * 32
|
||||
seckey_hex = binascii.hexlify(seckey).decode()
|
||||
print('seckey', seckey_hex)
|
||||
print(' ', hex_to_c(seckey_hex))
|
||||
print("seckey", seckey_hex)
|
||||
print(" ", hex_to_c(seckey_hex))
|
||||
pubkey = ed25519raw.publickey(seckey)
|
||||
pubkey_hex = binascii.hexlify(pubkey).decode()
|
||||
print('pubkey', pubkey_hex)
|
||||
print(' ', hex_to_c(pubkey_hex))
|
||||
print("pubkey", pubkey_hex)
|
||||
print(" ", hex_to_c(pubkey_hex))
|
||||
|
@ -3,16 +3,15 @@
|
||||
# script used to generate /embed/extmod/modtrezorui/loader.h
|
||||
|
||||
import math
|
||||
import sys
|
||||
|
||||
outer = 60
|
||||
inner = 42
|
||||
|
||||
with open('loader.h', 'wt') as f:
|
||||
f.write('static const int img_loader_size = %d;\n' % outer)
|
||||
f.write('static const uint16_t img_loader[%d][%d] = {\n' % (outer, outer))
|
||||
with open("loader.h", "wt") as f:
|
||||
f.write("static const int img_loader_size = %d;\n" % outer)
|
||||
f.write("static const uint16_t img_loader[%d][%d] = {\n" % (outer, outer))
|
||||
for y in range(outer):
|
||||
f.write(' {')
|
||||
f.write(" {")
|
||||
for x in range(outer):
|
||||
d = math.sqrt((outer - 1 - x) ** 2 + (outer - 1 - y) ** 2)
|
||||
c = {}
|
||||
@ -33,6 +32,6 @@ with open('loader.h', 'wt') as f:
|
||||
c[i] = max(0, min(int(c[i]), 15))
|
||||
a = int(math.atan2((outer - 1 - x), (outer - 1 - y)) * 2 * 249 / math.pi)
|
||||
v = (a << 8) | (c[15] << 4) | c[5]
|
||||
f.write('%d,' % v)
|
||||
f.write('},\n')
|
||||
f.write('};\n')
|
||||
f.write("%d," % v)
|
||||
f.write("},\n")
|
||||
f.write("};\n")
|
||||
|
@ -18,29 +18,31 @@ def format_primitive(value):
|
||||
|
||||
|
||||
fields = [
|
||||
'name',
|
||||
'ticker',
|
||||
'namespace',
|
||||
'mosaic',
|
||||
'divisibility',
|
||||
'levy',
|
||||
'fee',
|
||||
'levy_namespace',
|
||||
'levy_mosaic',
|
||||
'networks',
|
||||
"name",
|
||||
"ticker",
|
||||
"namespace",
|
||||
"mosaic",
|
||||
"divisibility",
|
||||
"levy",
|
||||
"fee",
|
||||
"levy_namespace",
|
||||
"levy_mosaic",
|
||||
"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('mosaics = [')
|
||||
print(
|
||||
"# generated using gen_nem_mosaics.py from trezor-common nem_mosaics.json - do not edit directly!"
|
||||
)
|
||||
print("")
|
||||
print("mosaics = [")
|
||||
for m in mosaics:
|
||||
print(' {')
|
||||
print(" {")
|
||||
for name in fields:
|
||||
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:
|
||||
# print(' %s: None,' % format_str(name))
|
||||
print(' },')
|
||||
print(']')
|
||||
print(" },")
|
||||
print("]")
|
||||
|
@ -8,9 +8,11 @@ devices = HidTransport.enumerate()
|
||||
if len(devices) > 0:
|
||||
t = TrezorClient(devices[0])
|
||||
else:
|
||||
raise Exception('No TREZOR found')
|
||||
raise Exception("No TREZOR found")
|
||||
|
||||
for i in [0, 1, 2]:
|
||||
path = "m/10018'/%d'" % i
|
||||
pk = t.get_public_node(t.expand_path(path), ecdsa_curve_name='ed25519', show_display=True)
|
||||
print(path, '=>', binascii.hexlify(pk.node.public_key).decode())
|
||||
pk = t.get_public_node(
|
||||
t.expand_path(path), ecdsa_curve_name="ed25519", show_display=True
|
||||
)
|
||||
print(path, "=>", binascii.hexlify(pk.node.public_key).decode())
|
||||
|
@ -16,11 +16,11 @@ out = bytearray()
|
||||
|
||||
for addr, fn in files:
|
||||
addr = int(addr, 16) - offset
|
||||
data = open(fn, 'rb').read()
|
||||
data = open(fn, "rb").read()
|
||||
if len(out) < addr:
|
||||
out += b'\x00' * (addr - len(out))
|
||||
out += b"\x00" * (addr - len(out))
|
||||
if len(out) != addr:
|
||||
raise Exception('Alignment failed')
|
||||
raise Exception("Alignment failed")
|
||||
out += data
|
||||
|
||||
sys.stdout.buffer.write(out)
|
||||
|
26
tools/keyctl
26
tools/keyctl
@ -5,22 +5,18 @@ import click
|
||||
import pyblake2
|
||||
from trezorlib import cosi
|
||||
|
||||
indexmap = {
|
||||
'bootloader': 0,
|
||||
'vendorheader': 1,
|
||||
'firmware': 2,
|
||||
}
|
||||
indexmap = {"bootloader": 0, "vendorheader": 1, "firmware": 2}
|
||||
|
||||
|
||||
def header_digest(index, filename):
|
||||
data = open(filename, 'rb').read()
|
||||
data = open(filename, "rb").read()
|
||||
z = bytes(65 * [0x00])
|
||||
if index == 'bootloader':
|
||||
if index == "bootloader":
|
||||
header = data[:0x03BF] + z
|
||||
elif index == 'vendorheader':
|
||||
elif index == "vendorheader":
|
||||
header = data[:-65] + z
|
||||
elif index == 'firmware':
|
||||
vhdrlen = struct.unpack('<I', data[4:8])[0]
|
||||
elif index == "firmware":
|
||||
vhdrlen = struct.unpack("<I", data[4:8])[0]
|
||||
header = data[vhdrlen : vhdrlen + 0x03BF] + z
|
||||
else:
|
||||
raise ValueError('Unknown index "%s"' % index)
|
||||
@ -32,10 +28,10 @@ def cli():
|
||||
pass
|
||||
|
||||
|
||||
@cli.command(help='')
|
||||
@click.argument('index', type=click.Choice(indexmap.keys()))
|
||||
@click.argument('filename')
|
||||
@click.argument('seckeys', nargs=-1)
|
||||
@cli.command(help="")
|
||||
@click.argument("index", type=click.Choice(indexmap.keys()))
|
||||
@click.argument("filename")
|
||||
@click.argument("seckeys", nargs=-1)
|
||||
def sign(index, filename, seckeys):
|
||||
# compute header digest
|
||||
digest = header_digest(index, filename)
|
||||
@ -63,5 +59,5 @@ def sign(index, filename, seckeys):
|
||||
print(binascii.hexlify(sig).decode())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
|
@ -8,22 +8,18 @@ import serpent
|
||||
from trezorlib import cosi
|
||||
|
||||
PORT = 5001
|
||||
indexmap = {
|
||||
'bootloader': 0,
|
||||
'vendorheader': 1,
|
||||
'firmware': 2,
|
||||
}
|
||||
indexmap = {"bootloader": 0, "vendorheader": 1, "firmware": 2}
|
||||
|
||||
|
||||
def header_digest(index, filename):
|
||||
data = open(filename, 'rb').read()
|
||||
data = open(filename, "rb").read()
|
||||
z = bytes(65 * [0x00])
|
||||
if index == 'bootloader':
|
||||
if index == "bootloader":
|
||||
header = data[:0x03BF] + z
|
||||
elif index == 'vendorheader':
|
||||
elif index == "vendorheader":
|
||||
header = data[:-65] + z
|
||||
elif index == 'firmware':
|
||||
vhdrlen = struct.unpack('<I', data[4:8])[0]
|
||||
elif index == "firmware":
|
||||
vhdrlen = struct.unpack("<I", data[4:8])[0]
|
||||
header = data[vhdrlen : vhdrlen + 0x03BF] + z
|
||||
else:
|
||||
raise ValueError('Unknown index "%s"' % index)
|
||||
@ -35,20 +31,20 @@ def cli():
|
||||
pass
|
||||
|
||||
|
||||
@cli.command(help='')
|
||||
@click.argument('index', type=click.Choice(indexmap.keys()))
|
||||
@click.argument('filename')
|
||||
@click.argument('participants', nargs=-1)
|
||||
@cli.command(help="")
|
||||
@click.argument("index", type=click.Choice(indexmap.keys()))
|
||||
@click.argument("filename")
|
||||
@click.argument("participants", nargs=-1)
|
||||
def sign(index, filename, participants):
|
||||
# compute header digest
|
||||
digest = header_digest(index, filename)
|
||||
# create participant proxies
|
||||
if len(participants) < 1:
|
||||
raise ValueError('Not enough participants')
|
||||
print('connecting to %d participants:' % len(participants))
|
||||
raise ValueError("Not enough participants")
|
||||
print("connecting to %d participants:" % len(participants))
|
||||
proxy = []
|
||||
for p in participants:
|
||||
uri = 'PYRO:keyctl@%s:%d' % (p, PORT)
|
||||
uri = "PYRO:keyctl@%s:%d" % (p, PORT)
|
||||
proxy.append(Pyro4.Proxy(uri))
|
||||
# collect commits
|
||||
pks, Rs = [], []
|
||||
@ -57,7 +53,7 @@ def sign(index, filename, participants):
|
||||
pk, R = serpent.tobytes(pk), serpent.tobytes(R)
|
||||
pks.append(pk)
|
||||
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
|
||||
global_pk = cosi.combine_keys(pks)
|
||||
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 = serpent.tobytes(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
|
||||
sig = cosi.combine_sig(global_R, sigs)
|
||||
cosi.verify(sig, digest, global_pk)
|
||||
print('global signature:')
|
||||
print("global signature:")
|
||||
print(binascii.hexlify(sig).decode())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
|
@ -5,16 +5,13 @@ import Pyro4
|
||||
import serpent
|
||||
|
||||
PORT = 5001
|
||||
indexmap = {
|
||||
'bootloader': 0,
|
||||
'vendorheader': 1,
|
||||
'firmware': 2,
|
||||
}
|
||||
indexmap = {"bootloader": 0, "vendorheader": 1, "firmware": 2}
|
||||
|
||||
|
||||
def get_trezor():
|
||||
from trezorlib.client import TrezorClient
|
||||
from trezorlib.transport import get_transport
|
||||
|
||||
return TrezorClient(get_transport())
|
||||
|
||||
|
||||
@ -24,7 +21,6 @@ def get_path(index):
|
||||
|
||||
@Pyro4.expose
|
||||
class KeyctlProxy(object):
|
||||
|
||||
def get_commit(self, index, digest):
|
||||
digest = serpent.tobytes(digest)
|
||||
path = get_path(index)
|
||||
@ -32,41 +28,53 @@ class KeyctlProxy(object):
|
||||
while commit is None:
|
||||
try:
|
||||
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)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print('Trying again ...')
|
||||
print("Trying again ...")
|
||||
pk = commit.pubkey
|
||||
R = commit.commitment
|
||||
print('Commitment sent!')
|
||||
print("Commitment sent!")
|
||||
return (pk, R)
|
||||
|
||||
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)
|
||||
signature = None
|
||||
while signature is None:
|
||||
try:
|
||||
t = get_trezor()
|
||||
print('\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)
|
||||
print(
|
||||
"\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:
|
||||
print(e)
|
||||
print('Trying again ...')
|
||||
print("Trying again ...")
|
||||
sig = signature.signature
|
||||
print('Signature sent!')
|
||||
print("Signature sent!")
|
||||
return sig
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
ipaddr = sys.argv[1]
|
||||
else:
|
||||
print('Usage: keyctl-proxy ipaddress')
|
||||
print("Usage: keyctl-proxy ipaddress")
|
||||
sys.exit(1)
|
||||
daemon = Pyro4.Daemon(host=ipaddr, port=PORT)
|
||||
proxy = KeyctlProxy()
|
||||
uri = daemon.register(proxy, 'keyctl')
|
||||
uri = daemon.register(proxy, "keyctl")
|
||||
print('keyctl-proxy running at URI: "%s"' % uri)
|
||||
daemon.requestLoop()
|
||||
|
@ -12,7 +12,7 @@ def process_rgb(w, h, pix):
|
||||
for i in range(w):
|
||||
r, g, b = pix[i, j]
|
||||
c = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)
|
||||
data += struct.pack('>H', c)
|
||||
data += struct.pack(">H", c)
|
||||
return data
|
||||
|
||||
|
||||
@ -22,89 +22,95 @@ def process_grayscale(w, h, pix):
|
||||
for i in range(w // 2):
|
||||
l1, l2 = pix[i * 2, j], pix[i * 2 + 1, j]
|
||||
c = (l1 & 0xF0) | (l2 >> 4)
|
||||
data += struct.pack('>B', c)
|
||||
data += struct.pack(">B", c)
|
||||
return data
|
||||
|
||||
|
||||
def process_image(ifn, savefiles=False):
|
||||
im = Image.open(ifn)
|
||||
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':
|
||||
print('Detected RGB mode')
|
||||
elif im.mode == 'L':
|
||||
if im.mode == "RGB":
|
||||
print("Detected RGB mode")
|
||||
elif im.mode == "L":
|
||||
if w % 2 > 0:
|
||||
print('PNG file must have width divisible by 2')
|
||||
print("PNG file must have width divisible by 2")
|
||||
return 3
|
||||
print('Detected GRAYSCALE mode')
|
||||
print("Detected GRAYSCALE mode")
|
||||
else:
|
||||
print('Unknown mode:', im.mode)
|
||||
print("Unknown mode:", im.mode)
|
||||
return 4
|
||||
|
||||
pix = im.load()
|
||||
|
||||
bname = basename(ifn[:-4])
|
||||
ofn_h = '%s.h' % bname
|
||||
ofn_py = '%s.py' % bname
|
||||
ofn_h = "%s.h" % bname
|
||||
ofn_py = "%s.py" % bname
|
||||
|
||||
if im.mode == 'RGB':
|
||||
ofn = '%s.toif' % bname
|
||||
if im.mode == "RGB":
|
||||
ofn = "%s.toif" % bname
|
||||
pixeldata = process_rgb(w, h, pix)
|
||||
else:
|
||||
ofn = '%s.toig' % bname
|
||||
ofn = "%s.toig" % bname
|
||||
pixeldata = process_grayscale(w, h, pix)
|
||||
z = zlib.compressobj(level=9, wbits=10)
|
||||
zdata = z.compress(pixeldata) + z.flush()
|
||||
zdata = zdata[2:-4] # strip header and checksum
|
||||
|
||||
data = b''
|
||||
if im.mode == 'RGB':
|
||||
data += b'TOIf'
|
||||
data = b""
|
||||
if im.mode == "RGB":
|
||||
data += b"TOIf"
|
||||
else:
|
||||
data += b'TOIg'
|
||||
data += struct.pack('<HH', w, h)
|
||||
data += struct.pack('<I', len(zdata))
|
||||
data += b"TOIg"
|
||||
data += struct.pack("<HH", w, h)
|
||||
data += struct.pack("<I", len(zdata))
|
||||
data += zdata
|
||||
|
||||
if savefiles:
|
||||
with open(ofn, 'wb') as f:
|
||||
with open(ofn, "wb") as f:
|
||||
f.write(data)
|
||||
print('Written %s ... %d bytes' % (ofn, len(data)))
|
||||
with open(ofn_py, 'wb') as f:
|
||||
f.write(('%s = %s\n' % (bname, data)).encode())
|
||||
print('Written %s ... %d bytes' % (ofn_py, len(data)))
|
||||
with open(ofn_h, 'wt') as f:
|
||||
f.write('// clang-format off\n')
|
||||
f.write('static const uint8_t toi_%s[] = {\n' % bname)
|
||||
f.write(' // magic\n')
|
||||
if im.mode == 'RGB':
|
||||
print("Written %s ... %d bytes" % (ofn, len(data)))
|
||||
with open(ofn_py, "wb") as f:
|
||||
f.write(("%s = %s\n" % (bname, data)).encode())
|
||||
print("Written %s ... %d bytes" % (ofn_py, len(data)))
|
||||
with open(ofn_h, "wt") as f:
|
||||
f.write("// clang-format off\n")
|
||||
f.write("static const uint8_t toi_%s[] = {\n" % bname)
|
||||
f.write(" // magic\n")
|
||||
if im.mode == "RGB":
|
||||
f.write(" 'T', 'O', 'I', 'f',\n")
|
||||
else:
|
||||
f.write(" 'T', 'O', 'I', 'g',\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(" // 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)
|
||||
)
|
||||
l = len(zdata)
|
||||
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(' // compressed data\n')
|
||||
f.write(' ')
|
||||
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(" // compressed data\n")
|
||||
f.write(" ")
|
||||
for b in zdata:
|
||||
f.write(' 0x%02x,' % b)
|
||||
f.write('\n};\n')
|
||||
print('Written %s ... done' % ofn_py)
|
||||
f.write(" 0x%02x," % b)
|
||||
f.write("\n};\n")
|
||||
print("Written %s ... done" % ofn_py)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print('Usage png2toi image.png')
|
||||
print("Usage png2toi image.png")
|
||||
return 1
|
||||
|
||||
ifn = sys.argv[1]
|
||||
if not ifn.endswith('.png'):
|
||||
print('Must provide PNG file')
|
||||
if not ifn.endswith(".png"):
|
||||
print("Must provide PNG file")
|
||||
return 2
|
||||
|
||||
process_image(ifn, savefiles=True)
|
||||
|
@ -6,20 +6,20 @@ resources = {}
|
||||
resources_size = 0
|
||||
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
os.chdir('../src/')
|
||||
os.chdir("../src/")
|
||||
|
||||
|
||||
def process_file(name):
|
||||
if name.endswith('.gitignore'):
|
||||
if name.endswith(".gitignore"):
|
||||
return
|
||||
if name.endswith('.py'):
|
||||
if name.endswith(".py"):
|
||||
return
|
||||
if os.path.basename(name).startswith('.'):
|
||||
if os.path.basename(name).startswith("."):
|
||||
return
|
||||
with open(name, 'rb') as f:
|
||||
with open(name, "rb") as f:
|
||||
data = f.read()
|
||||
resources[name] = data
|
||||
print('processing file %s (%d bytes)' % (name, len(data)))
|
||||
print("processing file %s (%d bytes)" % (name, len(data)))
|
||||
global resources_size
|
||||
resources_size += len(data)
|
||||
|
||||
@ -33,33 +33,35 @@ def process_dir_rec(dir):
|
||||
process_dir_rec(path)
|
||||
|
||||
|
||||
process_dir_rec('trezor/res/')
|
||||
for name in os.listdir('apps/'):
|
||||
path = os.path.join('apps/', name, 'res/')
|
||||
process_dir_rec("trezor/res/")
|
||||
for name in os.listdir("apps/"):
|
||||
path = os.path.join("apps/", name, "res/")
|
||||
if os.path.isdir(path):
|
||||
process_dir_rec(path)
|
||||
|
||||
resfile = 'trezor/res/resources.py'
|
||||
resfile = "trezor/res/resources.py"
|
||||
|
||||
bio = io.StringIO()
|
||||
bio.write('# fmt: off\n')
|
||||
bio.write('resdata = {\n')
|
||||
bio.write("# fmt: off\n")
|
||||
bio.write("resdata = {\n")
|
||||
for k in sorted(resources.keys()):
|
||||
bio.write(" '%s': %s,\n" % (k, resources[k]))
|
||||
bio.write('}\n')
|
||||
bio.write("}\n")
|
||||
|
||||
try:
|
||||
with open(resfile, 'r') as f:
|
||||
with open(resfile, "r") as f:
|
||||
stale = f.read()
|
||||
except:
|
||||
except FileNotFoundError:
|
||||
stale = None
|
||||
|
||||
fresh = bio.getvalue()
|
||||
|
||||
if stale != fresh:
|
||||
with open(resfile, 'wt') as f:
|
||||
with open(resfile, "wt") as f:
|
||||
f.write(fresh)
|
||||
print('written %s with %d entries (total %d bytes)' %
|
||||
(resfile, len(resources), resources_size))
|
||||
print(
|
||||
"written %s with %d entries (total %d bytes)"
|
||||
% (resfile, len(resources), resources_size)
|
||||
)
|
||||
else:
|
||||
print('continuing with %s, no changes detected' % (resfile))
|
||||
print("continuing with %s, no changes detected" % (resfile))
|
||||
|
@ -25,62 +25,64 @@ def process_grayscale(w, h, data):
|
||||
|
||||
def process_image(ifn, ofn):
|
||||
|
||||
data = open(ifn, 'rb').read()
|
||||
data = open(ifn, "rb").read()
|
||||
|
||||
if ifn.endswith('.toif'):
|
||||
if data[:4] != b'TOIf':
|
||||
print('Unknown TOIF header')
|
||||
if ifn.endswith(".toif"):
|
||||
if data[:4] != b"TOIf":
|
||||
print("Unknown TOIF header")
|
||||
return 1
|
||||
elif ifn.endswith('.toig'):
|
||||
if data[:4] != b'TOIg':
|
||||
print('Unknown TOIG header')
|
||||
elif ifn.endswith(".toig"):
|
||||
if data[:4] != b"TOIg":
|
||||
print("Unknown TOIG header")
|
||||
return 2
|
||||
else:
|
||||
print('Unsupported format')
|
||||
print("Unsupported format")
|
||||
return 3
|
||||
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:]
|
||||
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
|
||||
data = zlib.decompress(data, -10)
|
||||
|
||||
if ifn.endswith('.toif'):
|
||||
if ifn.endswith(".toif"):
|
||||
if len(data) != w * h * 2:
|
||||
print('Uncompressed data length mismatch (%d vs %d)' %
|
||||
(len(data), w * h * 2))
|
||||
print(
|
||||
"Uncompressed data length mismatch (%d vs %d)" % (len(data), w * h * 2)
|
||||
)
|
||||
return 5
|
||||
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)
|
||||
print('Written %s ...' % ofn)
|
||||
print("Written %s ..." % ofn)
|
||||
|
||||
if ifn.endswith('.toig'):
|
||||
if ifn.endswith(".toig"):
|
||||
if len(data) != w * h // 2:
|
||||
print('Uncompressed data length mismatch (%d vs %d)' %
|
||||
(len(data), w * h // 2))
|
||||
print(
|
||||
"Uncompressed data length mismatch (%d vs %d)" % (len(data), w * h // 2)
|
||||
)
|
||||
return 6
|
||||
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)
|
||||
print('Written %s ...' % ofn)
|
||||
print("Written %s ..." % ofn)
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print('Usage: toi2png image.toi[fg] [output]')
|
||||
print("Usage: toi2png image.toi[fg] [output]")
|
||||
return 1
|
||||
|
||||
ifn = sys.argv[1]
|
||||
if not ifn.endswith('.toif') and not ifn.endswith('.toig'):
|
||||
print('Must provide TOIF/TOIG file')
|
||||
if not ifn.endswith(".toif") and not ifn.endswith(".toig"):
|
||||
print("Must provide TOIF/TOIG file")
|
||||
return 2
|
||||
|
||||
ofn = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
|
Loading…
Reference in New Issue
Block a user