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 = {} memory = {}
_seed = None _seed = None
_passphrase = None _passphrase = None
_state_salt = None
def get_state(salt: bytes=None, passphrase: str=None): def get_state(state: bytes=None, passphrase: str=None):
global _passphrase, _state_salt
if salt is None: if state is None:
# generate a random salt if not provided and not already cached salt = random.bytes(32) # generate a random salt if no state provided
if _state_salt is None:
_state_salt = random.bytes(32)
else: else:
# otherwise copy provided salt to cached salt salt = state[:32] # use salt from provided state
_state_salt = salt
if passphrase is None:
global _passphrase
if _passphrase is None:
return None
passphrase = _passphrase # use cached passphrase
# state = HMAC(passphrase, salt || device_id) # state = HMAC(passphrase, salt || device_id)
if passphrase is None: msg = salt + storage.get_device_id().encode()
key = _passphrase if _passphrase is not None else '' state = hmac.new(passphrase.encode(), msg, hashlib.sha256).digest()
else:
key = passphrase
msg = _state_salt + storage.get_device_id().encode()
state = hmac.new(key.encode(), msg, hashlib.sha256).digest()
return _state_salt + state return salt + state
def get_seed(): def get_seed():
@ -45,6 +43,4 @@ def has_passphrase():
def clear(): def clear():
global _seed, _passphrase global _seed, _passphrase
global _state_salt
_seed, _passphrase = None, None _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.ButtonRequest import ButtonRequest
from trezor.messages.FailureType import ActionCancelled, ProcessError from trezor.messages.FailureType import ActionCancelled, ProcessError
from trezor.messages.PassphraseRequest import PassphraseRequest from trezor.messages.PassphraseRequest import PassphraseRequest
from trezor.messages.PassphraseStateRequest import PassphraseStateRequest
from trezor.ui.entry_select import DEVICE, EntrySelector from trezor.ui.entry_select import DEVICE, EntrySelector
from trezor.ui.passphrase import CANCELLED, PassphraseKeyboard from trezor.ui.passphrase import CANCELLED, PassphraseKeyboard
from trezor.ui.text import Text 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') raise wire.FailureError(ProcessError, 'Passphrase not provided')
passphrase = ack.passphrase 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): async def request_passphrase(ctx):
on_device = await request_passphrase_entry(ctx) == DEVICE on_device = await request_passphrase_entry(ctx) == DEVICE
state, passphrase = await request_passphrase_ack(ctx, on_device) 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')
return passphrase return passphrase

View File

@ -11,7 +11,7 @@ from apps.common import storage, coins, cache
async def respond_Features(ctx, msg): async def respond_Features(ctx, msg):
if msg.__qualname__ == 'Initialize': 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() cache.clear()
f = Features() f = Features()
@ -32,7 +32,6 @@ async def respond_Features(ctx, msg):
f.needs_backup = storage.needs_backup() f.needs_backup = storage.needs_backup()
f.flags = storage.get_flags() f.flags = storage.get_flags()
f.model = 'T' f.model = 'T'
f.state = cache.get_state()
return f return f

View File

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

View File

@ -41,6 +41,8 @@ VerifyMessage = const(39)
MessageSignature = const(40) MessageSignature = const(40)
PassphraseRequest = const(41) PassphraseRequest = const(41)
PassphraseAck = const(42) PassphraseAck = const(42)
PassphraseStateRequest = const(77)
PassphraseStateAck = const(78)
EstimateTxSize = const(43) EstimateTxSize = const(43)
TxSize = const(44) TxSize = const(44)
RecoveryDevice = const(45) 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) NEMSignedTx = const(70)
PassphraseAck = const(42) PassphraseAck = const(42)
PassphraseRequest = const(41) PassphraseRequest = const(41)
PassphraseStateAck = const(78)
PassphraseStateRequest = const(77)
PinMatrixAck = const(19) PinMatrixAck = const(19)
PinMatrixRequest = const(18) PinMatrixRequest = const(18)
Ping = const(1) Ping = const(1)

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