1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-30 03:18:20 +00:00

Support for matrix recovery

See issue trezor/trezor-mcu#96
This commit is contained in:
Jochen Hoenicke 2016-06-29 22:40:37 +02:00 committed by Pavol Rusnak
parent 17435cf174
commit c935b51849
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
2 changed files with 60 additions and 5 deletions

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import print_function from __future__ import print_function
import sys
import os import os
import binascii import binascii
import argparse import argparse
@ -9,9 +10,8 @@ import tempfile
from trezorlib import types_pb2 as types from trezorlib import types_pb2 as types
from io import BytesIO from io import BytesIO
import sys
from trezorlib.client import TrezorClient, TrezorClientDebug, CallException from trezorlib.client import TrezorClient, TrezorClientDebug, CallException
import trezorlib.types_pb2 as types
ether_units = { ether_units = {
"wei": 1, "wei": 1,
@ -218,8 +218,11 @@ class Commands(object):
return self.client.wipe_device() return self.client.wipe_device()
def recovery_device(self, args): def recovery_device(self, args):
typemap = { 'scrambled': types.RecoveryDeviceType_ScrambledWords,
'matrix': types.RecoveryDeviceType_Matrix }
return self.client.recovery_device(args.words, args.passphrase_protection, return self.client.recovery_device(args.words, args.passphrase_protection,
args.pin_protection, args.label, 'english') args.pin_protection, args.label, 'english',
typemap[args.type])
def load_device(self, args): def load_device(self, args):
if not args.mnemonic and not args.xprv: if not args.mnemonic and not args.xprv:
@ -403,6 +406,7 @@ class Commands(object):
(('-p', '--pin-protection'), {'action': 'store_true', 'default': False}), (('-p', '--pin-protection'), {'action': 'store_true', 'default': False}),
(('-r', '--passphrase-protection'), {'action': 'store_true', 'default': False}), (('-r', '--passphrase-protection'), {'action': 'store_true', 'default': False}),
(('-l', '--label'), {'type': str, 'default': ''}), (('-l', '--label'), {'type': str, 'default': ''}),
(('-t', '--type'), {'type': str, 'choices': ['scrambled', 'matrix'], 'default': 'matrix'}),
) )
load_device.arguments = ( load_device.arguments = (

View File

@ -30,6 +30,29 @@ DEFAULT_CURVE = 'secp256k1'
# monkeypatching: text formatting of protobuf messages # monkeypatching: text formatting of protobuf messages
tools.monkeypatch_google_protobuf_text_format() tools.monkeypatch_google_protobuf_text_format()
def getch():
try:
import termios
except ImportError:
# Non-POSIX. Return msvcrt's (Windows') getch.
import msvcrt
return msvcrt.getch()
# POSIX system. Create and return a getch that manipulates the tty.
import sys, tty
def _getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
return _getch()
def get_buttonrequest_value(code): def get_buttonrequest_value(code):
# Converts integer code to its string representation of ButtonRequestType # Converts integer code to its string representation of ButtonRequestType
return [ k for k, v in types.ButtonRequestType.items() if v == code][0] return [ k for k, v in types.ButtonRequestType.items() if v == code][0]
@ -174,6 +197,29 @@ class TextUIMixin(object):
# log("Sending ButtonAck for %s " % get_buttonrequest_value(msg.code)) # log("Sending ButtonAck for %s " % get_buttonrequest_value(msg.code))
return proto.ButtonAck() return proto.ButtonAck()
def callback_RecoveryMatrix(self, msg):
if self.recovery_matrix_first_pass:
self.recovery_matrix_first_pass = False
log("Use the numeric keypad to describe positions. For the word list use only left and right keys. The layout is:")
log(" 7 8 9 7 | 9")
log(" 4 5 6 4 | 6")
log(" 1 2 3 1 | 3")
while True:
character = getch()
if character in ('\x03', '\x04'):
return proto.Cancel()
if character in ('\x08', '\x7f'):
return proto.WordAck(word='\x08')
# ignore middle column if only 6 keys requested.
if (msg.type == types.WordRequestType_Matrix6 and
character in ('2', '5', '8')):
continue
if (ord(character) >= ord('1') and ord(character) <= ord('9')):
return proto.WordAck(word=character)
def callback_PinMatrixRequest(self, msg): def callback_PinMatrixRequest(self, msg):
if msg.type == 1: if msg.type == 1:
desc = 'current PIN' desc = 'current PIN'
@ -204,6 +250,9 @@ class TextUIMixin(object):
exit() exit()
def callback_WordRequest(self, msg): def callback_WordRequest(self, msg):
if msg.type in (types.WordRequestType_Matrix9,
types.WordRequestType_Matrix6):
return self.callback_RecoveryMatrix(msg)
log("Enter one word of mnemonic: ") log("Enter one word of mnemonic: ")
try: try:
word = raw_input() word = raw_input()
@ -741,19 +790,21 @@ class ProtocolMixin(object):
@field('message') @field('message')
@expect(proto.Success) @expect(proto.Success)
def recovery_device(self, word_count, passphrase_protection, pin_protection, label, language): def recovery_device(self, word_count, passphrase_protection, pin_protection, label, language, type=types.RecoveryDeviceType_Matrix):
if self.features.initialized: if self.features.initialized:
raise Exception("Device is initialized already. Call wipe_device() and try again.") raise Exception("Device is initialized already. Call wipe_device() and try again.")
if word_count not in (12, 18, 24): if word_count not in (12, 18, 24):
raise Exception("Invalid word count. Use 12/18/24") raise Exception("Invalid word count. Use 12/18/24")
self.recovery_matrix_first_pass = True
res = self.call(proto.RecoveryDevice(word_count=int(word_count), res = self.call(proto.RecoveryDevice(word_count=int(word_count),
passphrase_protection=bool(passphrase_protection), passphrase_protection=bool(passphrase_protection),
pin_protection=bool(pin_protection), pin_protection=bool(pin_protection),
label=label, label=label,
language=language, language=language,
enforce_wordlist=True)) enforce_wordlist=True,
type=type))
self.init_device() self.init_device()
return res return res