src/apps/common: rework PassphraseState behaviour

This commit is contained in:
Pavol Rusnak 2018-03-01 00:07:45 +01:00
parent 01bb1e34fa
commit 2e3dc8b29d
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
9 changed files with 55 additions and 29 deletions

View File

@ -4,28 +4,26 @@ from apps.common import storage
memory = {}
_seed = None
_passphrase = None
_state_salt = None
def get_state(salt: bytes=None, passphrase: str=None):
global _passphrase, _state_salt
if salt is None:
# generate a random salt if not provided and not already cached
if _state_salt is None:
_state_salt = random.bytes(32)
def get_state(state: bytes=None, passphrase: str=None):
if state is None:
salt = random.bytes(32) # generate a random salt if no state provided
else:
# otherwise copy provided salt to cached salt
_state_salt = salt
salt = state[:32] # use salt from provided state
if passphrase is None:
global _passphrase
if _passphrase is None:
return None
passphrase = _passphrase # use cached passphrase
# state = HMAC(passphrase, salt || device_id)
if passphrase is None:
key = _passphrase if _passphrase is not None else ''
else:
key = passphrase
msg = _state_salt + storage.get_device_id().encode()
state = hmac.new(key.encode(), msg, hashlib.sha256).digest()
msg = salt + storage.get_device_id().encode()
state = hmac.new(passphrase.encode(), msg, hashlib.sha256).digest()
return _state_salt + state
return salt + state
def get_seed():
@ -45,6 +43,4 @@ def has_passphrase():
def clear():
global _seed, _passphrase
global _state_salt
_seed, _passphrase = None, None
_state_salt = None

View File

@ -3,6 +3,7 @@ from trezor.messages import ButtonRequestType, wire_types
from trezor.messages.ButtonRequest import ButtonRequest
from trezor.messages.FailureType import ActionCancelled, ProcessError
from trezor.messages.PassphraseRequest import PassphraseRequest
from trezor.messages.PassphraseStateRequest import PassphraseStateRequest
from trezor.ui.entry_select import DEVICE, EntrySelector
from trezor.ui.passphrase import CANCELLED, PassphraseKeyboard
from trezor.ui.text import Text
@ -53,15 +54,15 @@ async def request_passphrase_ack(ctx, on_device):
raise wire.FailureError(ProcessError, 'Passphrase not provided')
passphrase = ack.passphrase
return ack.state, passphrase
req = PassphraseStateRequest(state=get_state(state=ack.state, passphrase=passphrase))
ack = await ctx.call(req, wire_types.PassphraseStateAck, wire_types.Cancel)
return passphrase
async def request_passphrase(ctx):
on_device = await request_passphrase_entry(ctx) == DEVICE
state, passphrase = await request_passphrase_ack(ctx, on_device)
if state is not None:
if state != get_state(salt=state[:32], passphrase=passphrase):
raise wire.FailureError(ProcessError, 'Passphrase mismatch')
passphrase = await request_passphrase_ack(ctx, on_device)
return passphrase

View File

@ -11,7 +11,7 @@ from apps.common import storage, coins, cache
async def respond_Features(ctx, msg):
if msg.__qualname__ == 'Initialize':
if msg.state is None or msg.state != cache.get_state(salt=msg.state[:32]):
if msg.state is None or msg.state != cache.get_state(state=msg.state):
cache.clear()
f = Features()
@ -32,7 +32,6 @@ async def respond_Features(ctx, msg):
f.needs_backup = storage.needs_backup()
f.flags = storage.get_flags()
f.model = 'T'
f.state = cache.get_state()
return f

View File

@ -31,7 +31,6 @@ class Features(p.MessageType):
24: ('fw_patch', p.UVarintType, 0),
25: ('fw_vendor', p.UnicodeType, 0),
26: ('fw_vendor_keys', p.BytesType, 0),
27: ('state', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 17
@ -63,7 +62,6 @@ class Features(p.MessageType):
fw_patch: int = None,
fw_vendor: str = None,
fw_vendor_keys: bytes = None,
state: bytes = None,
**kwargs,
):
self.vendor = vendor
@ -92,5 +90,4 @@ class Features(p.MessageType):
self.fw_patch = fw_patch
self.fw_vendor = fw_vendor
self.fw_vendor_keys = fw_vendor_keys
self.state = state
p.MessageType.__init__(self, **kwargs)

View File

@ -41,6 +41,8 @@ VerifyMessage = const(39)
MessageSignature = const(40)
PassphraseRequest = const(41)
PassphraseAck = const(42)
PassphraseStateRequest = const(77)
PassphraseStateAck = const(78)
EstimateTxSize = const(43)
TxSize = const(44)
RecoveryDevice = const(45)

View File

@ -0,0 +1,12 @@
# Automatically generated by pb2py
import protobuf as p
class PassphraseStateAck(p.MessageType):
MESSAGE_WIRE_TYPE = 78
def __init__(
self,
**kwargs,
):
p.MessageType.__init__(self, **kwargs)

View File

@ -0,0 +1,17 @@
# Automatically generated by pb2py
import protobuf as p
class PassphraseStateRequest(p.MessageType):
FIELDS = {
1: ('state', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 77
def __init__(
self,
state: bytes = None,
**kwargs,
):
self.state = state
p.MessageType.__init__(self, **kwargs)

View File

@ -63,6 +63,8 @@ NEMSignTx = const(69)
NEMSignedTx = const(70)
PassphraseAck = const(42)
PassphraseRequest = const(41)
PassphraseStateAck = const(78)
PassphraseStateRequest = const(77)
PinMatrixAck = const(19)
PinMatrixRequest = const(18)
Ping = const(1)

@ -1 +1 @@
Subproject commit d85f7ac6bbcccbc83012d85fdf25635e57c5f15b
Subproject commit 0924bd6826bb63f66010e2e511356d54ea733df3