#!/usr/bin/env python3 import binascii import struct import click import pyblake2 from trezorlib import cosi indexmap = {"bootloader": 0, "vendorheader": 1, "firmware": 2} def header_digest(index, filename): data = open(filename, "rb").read() z = bytes(65 * [0x00]) if index == "bootloader": header = data[:0x03BF] + z elif index == "vendorheader": header = data[:-65] + z elif index == "firmware": vhdrlen = struct.unpack("<I", data[4:8])[0] header = data[vhdrlen : vhdrlen + 0x03BF] + z else: raise ValueError('Unknown index "%s"' % index) return pyblake2.blake2s(header).digest() @click.group() def cli(): pass @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) # collect commits pks, nonces, Rs = [], [], [] for ctr, seckey in enumerate(seckeys): sk = binascii.unhexlify(seckey) pk = cosi.pubkey_from_privkey(sk) r, R = cosi.get_nonce(sk, digest, ctr) pks.append(pk) nonces.append(r) Rs.append(R) # compute global commit global_pk = cosi.combine_keys(pks) global_R = cosi.combine_keys(Rs) # collect signatures sigs = [] for seckey, nonce in zip(seckeys, nonces): sk = binascii.unhexlify(seckey) sig = cosi.sign_with_privkey(digest, sk, global_pk, nonce, global_R) sigs.append(sig) # compute global signature sig = cosi.combine_sig(global_R, sigs) cosi.verify(sig, digest, global_pk) print(binascii.hexlify(sig).decode()) if __name__ == "__main__": cli()