mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-29 19:08:12 +00:00
tools: split computation of signatures to keyctl, remove from binctl
This commit is contained in:
parent
383b5d7c89
commit
57f2eee5bf
86
tools/binctl
86
tools/binctl
@ -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
109
tools/keyctl
Executable 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()
|
Loading…
Reference in New Issue
Block a user