1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-02 04:18:20 +00:00

tools: split computation of signatures to keyctl, remove from binctl

This commit is contained in:
Pavol Rusnak 2017-10-05 07:41:36 +02:00
parent 383b5d7c89
commit 57f2eee5bf
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
2 changed files with 116 additions and 79 deletions

View File

@ -5,73 +5,10 @@ from __future__ import print_function
import sys import sys
import struct import struct
import binascii import binascii
import pyblake2
from trezorlib import ed25519raw, ed25519cosi from trezorlib import ed25519raw, ed25519cosi
if sys.version_info.major < 3:
input = raw_input
def get_trezor(index):
from trezorlib.client import TrezorClient
from trezorlib.transport_hid import HidTransport
devices = HidTransport.enumerate()
if len(devices) > index:
return TrezorClient(devices[index])
else:
raise Exception('TREZOR with such index not found')
def sign_data(seckeys, data):
digest = pyblake2.blake2s(data).digest()
if len(seckeys) == 1:
sk = seckeys[0]
pk = ed25519raw.publickey(sk)
return ed25519raw.signature(digest, sk, pk)
else:
ctr = 0
pubkeys = []
nonces = []
commits = []
for i, sk in enumerate(seckeys):
if sk == 'trezor':
t = get_trezor(i)
# FIXME: path below should change according to what is being signed
commit = t.cosi_commit(t.expand_path("10018'/0'"), digest)
pk = commit.pubkey
r = None
R = commit.commitment
else:
pk = ed25519raw.publickey(sk)
r, R = ed25519cosi.get_nonce(sk, digest, ctr)
pubkeys.append(pk)
nonces.append(r)
commits.append(R)
global_pk = ed25519cosi.combine_keys(pubkeys)
global_R = ed25519cosi.combine_keys(commits)
sigs = []
for i, sk in enumerate(seckeys):
if sk == 'trezor':
t = get_trezor(i)
# FIXME: path below should change according to what is being signed
signature = t.cosi_sign(t.expand_path("10018'/0'"), digest, global_R, global_pk)
sig = signature.signature
else:
r = nonces[i]
R = commits[i]
h = ed25519raw.H(sk)
b = ed25519raw.b
a = 2 ** (b - 2) + sum(2 ** i * ed25519raw.bit(h, i) for i in range(3, b - 2))
S = (r + ed25519raw.Hint(global_R + global_pk + digest) * a) % ed25519raw.l
sig = ed25519raw.encodeint(S)
sigs.append(sig)
sig = ed25519cosi.combine_sig(global_R, sigs)
ed25519raw.checkvalid(sig, digest, global_pk)
return sig
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))
@ -136,12 +73,12 @@ class BinImage(object):
assert len(header) == self.hdrlen assert len(header) == self.hdrlen
return header return header
def sign(self, sigmask, seckeys): def sign(self, sigmask, signature):
header = self.serialize_header(sig=False) header = self.serialize_header(sig=False)
data = header + self.code data = header + self.code
assert len(data) == self.hdrlen + self.codelen assert len(data) == self.hdrlen + self.codelen
self.sigmask = sigmask self.sigmask = sigmask
self.sig = sign_data(seckeys, data) self.sig = signature
def write(self, filename): def write(self, filename):
with open(filename, 'wb') as f: with open(filename, 'wb') as f:
@ -240,10 +177,7 @@ class VendorHeader(object):
assert len(header) == self.hdrlen assert len(header) == self.hdrlen
return header return header
def sign(self, sigmask, seckeys): def sign(self, sigmask, signature):
# check whether provided arguments match vsig_m/vsig_n
if len(seckeys) != self.vsig_m:
raise Exception('invalid number of signatures (vsig_m expected %d, got %d)' % (self.vsig_m, len(seckeys)))
if sigmask >= (1 << self.vsig_n): if sigmask >= (1 << self.vsig_n):
raise Exception('signature index is higher than vsig_n (%d)' % self.vsig_n) raise Exception('signature index is higher than vsig_n (%d)' % self.vsig_n)
if bin(sigmask).count('1') != self.vsig_m: if bin(sigmask).count('1') != self.vsig_m:
@ -251,7 +185,7 @@ class VendorHeader(object):
# sign # sign
header = self.serialize_header(sig=False) header = self.serialize_header(sig=False)
self.sigmask = sigmask self.sigmask = sigmask
self.sig = sign_data(seckeys, header) self.sig = signature
def write(self, filename): def write(self, filename):
with open(filename, 'wb') as f: with open(filename, 'wb') as f:
@ -278,7 +212,7 @@ def binopen(filename):
def main(): def main():
if len(sys.argv) < 2: if len(sys.argv) < 2:
print('Usage: binctl file.bin [-s index seckey]') print('Usage: binctl file.bin [-s sigmask signature]')
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'
@ -290,14 +224,8 @@ def main():
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)
if ':' in sys.argv[4]: signature = binascii.unhexlify(sys.argv[4])
seckeys = sys.argv[4].split(':') b.sign(sigmask, signature)
for i in range(len(seckeys)):
if seckeys[i] != 'trezor':
seckeys[i] = binascii.unhexlify(seckeys[i])
else:
seckeys = [binascii.unhexlify(sys.argv[4])]
b.sign(sigmask, seckeys)
print() print()
b.write(fn) b.write(fn)
b.print() b.print()

109
tools/keyctl Executable file
View File

@ -0,0 +1,109 @@
#!/usr/bin/env python3
import binascii
import click
import pyblake2
from trezorlib import ed25519raw, ed25519cosi
indexmap = {
'bootloader': 0,
'vendorheader': 1,
'firmware': 2,
}
def get_trezor():
from trezorlib.client import TrezorClient
from trezorlib.transport_hid import HidTransport
devices = HidTransport.enumerate()
if len(devices) > 0:
return TrezorClient(devices[0])
else:
raise Exception('No TREZOR found')
@click.group()
def cli():
pass
@cli.command(help='')
@click.argument('index', type=click.Choice(indexmap.keys()))
@click.argument('filename')
@click.argument('seckey', required=False)
def commit(index, filename, seckey):
index = indexmap[index]
data = open(filename, 'rb').read()
digest = pyblake2.blake2s(data).digest()
ctr = 0
if seckey:
sk = binascii.unhexlify(seckey)
pk = ed25519raw.publickey(sk)
_, R = ed25519cosi.get_nonce(sk, digest, ctr)
else:
t = get_trezor()
commit = t.cosi_commit(t.expand_path("10018'/%d'" % index), digest)
pk = commit.pubkey
R = commit.commitment
print('%s+%s' % (binascii.hexlify(pk).decode(), binascii.hexlify(R).decode()))
@cli.command(help='')
@click.argument('commits', nargs=-1)
def global_commit(commits):
if len(commits) < 1:
raise Exception('Need to provide at least one commit')
pk, R = [], []
for c in commits:
a, b = c.split('+')
pk.append(binascii.unhexlify(a))
R.append(binascii.unhexlify(b))
global_pk = ed25519cosi.combine_keys(pk)
global_R = ed25519cosi.combine_keys(R)
print('%s+%s' % (binascii.hexlify(global_pk).decode(), binascii.hexlify(global_R).decode()))
@cli.command(help='')
@click.argument('index', type=click.Choice(indexmap.keys()))
@click.argument('filename')
@click.argument('global_commit')
@click.argument('seckey', required=False)
def sign(index, filename, global_commit, seckey):
index = indexmap[index]
data = open(filename, 'rb').read()
digest = pyblake2.blake2s(data).digest()
global_pk, global_R = [binascii.unhexlify(x) for x in global_commit.split('+')]
ctr = 0
if seckey:
sk = binascii.unhexlify(seckey)
r, _ = ed25519cosi.get_nonce(sk, digest, ctr)
h = ed25519raw.H(sk)
b = ed25519raw.b
a = 2 ** (b - 2) + sum(2 ** i * ed25519raw.bit(h, i) for i in range(3, b - 2))
S = (r + ed25519raw.Hint(global_R + global_pk + digest) * a) % ed25519raw.l
sig = ed25519raw.encodeint(S)
else:
t = get_trezor()
signature = t.cosi_sign(t.expand_path("10018'/%d'" % index), digest, global_R, global_pk)
sig = signature.signature
print(binascii.hexlify(sig).decode())
@cli.command(help='')
@click.argument('filename')
@click.argument('global_commit')
@click.argument('signatures', nargs=-1)
def global_sign(filename, global_commit, signatures):
data = open(filename, 'rb').read()
digest = pyblake2.blake2s(data).digest()
global_pk, global_R = [binascii.unhexlify(x) for x in global_commit.split('+')]
signatures = [binascii.unhexlify(x) for x in signatures]
sig = ed25519cosi.combine_sig(global_R, signatures)
ed25519raw.checkvalid(sig, digest, global_pk)
print(binascii.hexlify(sig).decode())
if __name__ == '__main__':
cli()