def recovery_loop(self, mnemonic, result): ret = self.client.call_raw( proto.RecoveryDevice( word_count=12, passphrase_protection=False, pin_protection=False, label="label", language="english", enforce_wordlist=True, dry_run=True, )) # Reminder UI assert isinstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) fakes = 0 for _ in range(int(12 * 2)): assert isinstance(ret, proto.WordRequest) (word, pos) = self.client.debug.read_recovery_word() if pos != 0: ret = self.client.call_raw( proto.WordAck(word=mnemonic[pos - 1])) mnemonic[pos - 1] = None else: ret = self.client.call_raw(proto.WordAck(word=word)) fakes += 1 assert isinstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) assert isinstance(ret, result)
def test_reset_device(self): # No PIN, no passphrase external_entropy = b'zlutoucky kun upel divoke ody' * 2 strength = 128 ret = self.client.call_raw( proto.ResetDevice(display_random=False, strength=strength, passphrase_protection=False, pin_protection=False, language='english', label='test')) # Provide entropy self.assertIsInstance(ret, proto.EntropyRequest) internal_entropy = self.client.debug.read_reset_entropy() resp = self.client.call_raw(proto.EntropyAck(entropy=external_entropy)) # Generate mnemonic locally entropy = generate_entropy(strength, internal_entropy, external_entropy) expected_mnemonic = Mnemonic('english').to_mnemonic(entropy) # Explainer Dialog self.assertIsInstance(resp, proto.ButtonRequest) self.client.debug.press_yes() resp = self.client.call_raw(proto.ButtonAck()) mnemonic = [] while isinstance(resp, proto.ButtonRequest): mnemonic.append(self.client.debug.read_reset_word()) self.client.debug.press_yes() resp = self.client.call_raw(proto.ButtonAck()) mnemonic = ' '.join(mnemonic) # Compare that device generated proper mnemonic for given entropies self.assertEqual(mnemonic, expected_mnemonic) self.assertIsInstance(resp, proto.Success) # Compare that second pass printed out the same mnemonic once again self.assertEqual(mnemonic, expected_mnemonic) # Check if device is properly initialized resp = self.client.call_raw(proto.Initialize()) self.assertFalse(resp.pin_protection) self.assertFalse(resp.passphrase_protection) # Do passphrase-protected action, PassphraseRequest should NOT be raised resp = self.client.call_raw(proto.Ping(passphrase_protection=True)) self.assertIsInstance(resp, proto.Success) # Do PIN-protected action, PinRequest should NOT be raised resp = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(resp, proto.Success)
def test_failed_pin(self): external_entropy = 'zlutoucky kun upel divoke ody' * 2 strength = 128 ret = self.client.call_raw(proto.ResetDevice(display_random=True, strength=strength, passphrase_protection=True, pin_protection=True, language='english', label='test')) self.assertIsInstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) self.assertIsInstance(ret, proto.PinMatrixRequest) # Enter PIN for first time pin_encoded = self.client.debug.encode_pin(self.pin4) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) self.assertIsInstance(ret, proto.PinMatrixRequest) # Enter PIN for second time pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) self.assertIsInstance(ret, proto.Failure)
def test_set_failed_2(self): self.setup_mnemonic_pin_passphrase() features = self.client.call_raw(proto.Initialize()) self.assertTrue(features.pin_protection) # Let's set new PIN ret = self.client.call_raw(proto.ChangePin()) self.assertIsInstance(ret, proto.ButtonRequest) # Press button self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) # Send current PIN self.assertIsInstance(ret, proto.PinMatrixRequest) pin_encoded = self.client.debug.read_pin_encoded() ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Send the PIN for first time self.assertIsInstance(ret, proto.PinMatrixRequest) pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Send the PIN for second time, but with typo self.assertIsInstance(ret, proto.PinMatrixRequest) pin_encoded = self.client.debug.encode_pin(self.pin6 + '3') ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Now it should fail, because pins are different self.assertIsInstance(ret, proto.Failure) # Check that there's still old PIN protection features = self.client.call_raw(proto.Initialize()) self.assertTrue(features.pin_protection) self.assertEqual(self.client.debug.read_pin()[0], self.pin4)
def test_set_failed(self): self.setup_mnemonic_nopin_nopassphrase() features = self.client.call_raw(proto.Initialize()) self.assertFalse(features.pin_protection) # Check that there's no PIN protection ret = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(ret, proto.Success) # Let's set new PIN ret = self.client.call_raw(proto.ChangePin()) self.assertIsInstance(ret, proto.ButtonRequest) # Press button self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) # Send the PIN for first time self.assertIsInstance(ret, proto.PinMatrixRequest) pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Send the PIN for second time, but with typo self.assertIsInstance(ret, proto.PinMatrixRequest) pin_encoded = self.client.debug.encode_pin(self.pin4) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Now it should fail, because pins are different self.assertIsInstance(ret, proto.Failure) # Check that there's still no PIN protection now features = self.client.call_raw(proto.Initialize()) self.assertFalse(features.pin_protection) ret = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(ret, proto.Success)
def test_remove_pin(self): self.setup_mnemonic_pin_passphrase() features = self.client.call_raw(proto.Initialize()) self.assertTrue(features.pin_protection) self.client.clear_session() # Check that there's PIN protection ret = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(ret, proto.PinMatrixRequest) self.client.call_raw(proto.Cancel()) # Let's remove PIN ret = self.client.call_raw(proto.ChangePin(remove=True)) self.assertIsInstance(ret, proto.ButtonRequest) # Press button self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) # Send current PIN self.assertIsInstance(ret, proto.PinMatrixRequest) pin_encoded = self.client.debug.read_pin_encoded() ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Now we're done self.assertIsInstance(ret, proto.Success) # Check that there's no PIN protection now features = self.client.call_raw(proto.Initialize()) self.assertFalse(features.pin_protection) ret = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(ret, proto.Success)
def test_nopin_nopassphrase(self): mnemonic = self.mnemonic12 ret = self.client.call_raw( proto.RecoveryDevice(word_count=12, passphrase_protection=False, pin_protection=False, label='label', language='english', enforce_wordlist=True, use_character_cipher=True)) # Reminder UI assert isinstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) mnemonic_words = mnemonic.split(' ') for index, word in enumerate(mnemonic_words): for character in word: self.assertIsInstance(ret, proto.CharacterRequest) cipher = self.client.debug.read_recovery_cipher() encoded_character = cipher[ord(character) - 97] ret = self.client.call_raw( proto.CharacterAck(character=encoded_character)) auto_completed = self.client.debug.read_recovery_auto_completed_word( ) if word == auto_completed: if len(mnemonic_words) != index + 1: ret = self.client.call_raw( proto.CharacterAck(character=' ')) break # Send final ack self.assertIsInstance(ret, proto.CharacterRequest) ret = self.client.call_raw(proto.CharacterAck(done=True)) # Workflow succesfully ended self.assertIsInstance(ret, proto.Success) # Mnemonic is the same self.client.init_device() self.assertEqual(self.client.debug.read_mnemonic(), self.mnemonic12) self.assertFalse(self.client.features.pin_protection) self.assertFalse(self.client.features.passphrase_protection) # Do passphrase-protected action, PassphraseRequest should NOT be raised resp = self.client.call_raw(proto.Ping(passphrase_protection=True)) self.assertIsInstance(resp, proto.Success) # Do PIN-protected action, PinRequest should NOT be raised resp = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(resp, proto.Success)
def test_change_pin(self): self.setup_mnemonic_pin_passphrase() features = self.client.call_raw(proto.Initialize()) self.assertTrue(features.pin_protection) self.client.clear_session() # Check that there's PIN protection ret = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(ret, proto.PinMatrixRequest) self.client.call_raw(proto.Cancel()) # Check current PIN value self.assertEqual(self.client.debug.read_pin()[0], self.pin4) # Let's change PIN ret = self.client.call_raw(proto.ChangePin()) self.assertIsInstance(ret, proto.ButtonRequest) # Press button self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) # Send current PIN self.assertIsInstance(ret, proto.PinMatrixRequest) pin_encoded = self.client.debug.read_pin_encoded() ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Send new PIN for first time self.assertIsInstance(ret, proto.PinMatrixRequest) pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Send the PIN for second time self.assertIsInstance(ret, proto.PinMatrixRequest) pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Now we're done self.assertIsInstance(ret, proto.Success) self.client.clear_session() # Check that there's still PIN protection now features = self.client.call_raw(proto.Initialize()) self.assertTrue(features.pin_protection) ret = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(ret, proto.PinMatrixRequest) self.client.call_raw(proto.Cancel()) # Check that the PIN is correct self.assertEqual(self.client.debug.read_pin()[0], self.pin6)
def check_n_words(n): ret = self.client.call_raw( proto.RecoveryDevice(word_count=12, passphrase_protection=False, pin_protection=False, label='label', language='english', enforce_wordlist=True, use_character_cipher=True)) # Reminder UI assert isinstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) mnemonic_words = ['all'] * n for index, word in enumerate(mnemonic_words): if index >= 12: self.assertIsInstance(ret, proto.Success) self.assertEndsWith(ret.message, "Device recovered") return for character in word: self.assertIsInstance(ret, proto.CharacterRequest) cipher = self.client.debug.read_recovery_cipher() encoded_character = cipher[ord(character) - 97] ret = self.client.call_raw( proto.CharacterAck(character=encoded_character)) auto_completed = self.client.debug.read_recovery_auto_completed_word( ) if word == auto_completed: if len(mnemonic_words) != index + 1: ret = self.client.call_raw( proto.CharacterAck(character=' ')) break # Send final ack self.assertIsInstance(ret, proto.CharacterRequest) ret = self.client.call_raw(proto.CharacterAck(done=True)) if n == 12: self.assertIsInstance(ret, proto.Success) self.assertEndsWith(ret.message, "Device recovered") else: self.assertIsInstance(ret, proto.Failure) self.assertEndsWith(ret.message, "words entered")
def test_nopin_nopassphrase(self): mnemonic = self.mnemonic12.split(' ') ret = self.client.call_raw( proto.RecoveryDevice(word_count=12, passphrase_protection=False, pin_protection=False, label='label', language='english', enforce_wordlist=True)) # Reminder UI assert isinstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) fakes = 0 for _ in range(int(12 * 2)): self.assertIsInstance(ret, proto.WordRequest) (word, pos) = self.client.debug.read_recovery_word() if pos != 0: ret = self.client.call_raw( proto.WordAck(word=mnemonic[pos - 1])) mnemonic[pos - 1] = None else: ret = self.client.call_raw(proto.WordAck(word=word)) fakes += 1 # Workflow succesfully ended self.assertIsInstance(ret, proto.Success) # 12 expected fake words and all words of mnemonic are used self.assertEqual(fakes, 12) self.assertEqual(mnemonic, [None] * 12) # Mnemonic is the same self.client.init_device() self.assertEqual(self.client.debug.read_mnemonic(), self.mnemonic12) self.assertFalse(self.client.features.pin_protection) self.assertFalse(self.client.features.passphrase_protection) # Do passphrase-protected action, PassphraseRequest should NOT be raised resp = self.client.call_raw(proto.Ping(passphrase_protection=True)) self.assertIsInstance(resp, proto.Success) # Do PIN-protected action, PinRequest should NOT be raised resp = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(resp, proto.Success)
def test_character_fail(self): ret = self.client.call_raw( proto.RecoveryDevice(word_count=12, passphrase_protection=False, pin_protection=False, label='label', language='english', enforce_wordlist=True, use_character_cipher=True)) # Reminder UI assert isinstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) self.assertIsInstance(ret, proto.CharacterRequest) ret = self.client.call_raw(proto.CharacterAck(character='1')) self.assertIsInstance(ret, proto.Failure)
def test_too_many_characters(self): ret = self.client.call_raw( proto.RecoveryDevice(word_count=12, passphrase_protection=False, pin_protection=False, label='label', language='english', enforce_wordlist=True, use_character_cipher=True)) # Reminder UI assert isinstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) mnemonic_words = ['all'] * 100 for index, word in enumerate(mnemonic_words): for character in word: if isinstance(ret, proto.Failure): self.assertEndsWith(ret.message, "Too many words entered") return self.assertIsInstance(ret, proto.CharacterRequest) cipher = self.client.debug.read_recovery_cipher() encoded_character = cipher[ord(character) - 97] ret = self.client.call_raw( proto.CharacterAck(character=encoded_character)) auto_completed = self.client.debug.read_recovery_auto_completed_word( ) if word == auto_completed: if len(mnemonic_words) != index + 1: ret = self.client.call_raw( proto.CharacterAck(character=' ')) break # Shouldn't ever get here, assuming the test worked self.assertEquals(True, False)
def test_word_fail(self): ret = self.client.call_raw( proto.RecoveryDevice(word_count=12, passphrase_protection=False, pin_protection=False, label='label', language='english', enforce_wordlist=True)) # Reminder UI assert isinstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) self.assertIsInstance(ret, proto.WordRequest) for _ in range(int(12 * 2)): (word, pos) = self.client.debug.read_recovery_word() if pos != 0: ret = self.client.call_raw(proto.WordAck(word='kwyjibo')) self.assertIsInstance(ret, proto.Failure) break else: self.client.call_raw(proto.WordAck(word=word))
def recovery_loop(self, mnemonic, result): ret = self.client.call_raw( proto.RecoveryDevice( word_count=12, passphrase_protection=False, pin_protection=False, label="label", language="english", enforce_wordlist=True, dry_run=True, use_character_cipher=True, ) ) for index, word in enumerate(mnemonic): for character in word: self.assertIsInstance(ret, proto.CharacterRequest) cipher = self.client.debug.read_recovery_cipher() encoded_character = cipher[ord(character) - 97] ret = self.client.call_raw(proto.CharacterAck(character=encoded_character)) auto_completed = self.client.debug.read_recovery_auto_completed_word() if word == auto_completed: if len(mnemonic) != index + 1: ret = self.client.call_raw(proto.CharacterAck(character=' ')) break self.assertIsInstance(ret, proto.CharacterRequest) ret = self.client.call_raw(proto.CharacterAck(done=True)) assert isinstance(ret, proto.ButtonRequest) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) assert isinstance(ret, result)
def test_reset_and_recover(self): for strength in (128, 192, 256): external_entropy = self.client._get_local_entropy() ret = self.client.call_raw(proto.ResetDevice(display_random=False, strength=strength, passphrase_protection=False, pin_protection=False, language='english', label='test')) # Provide entropy self.assertIsInstance(ret, proto.EntropyRequest) resp = self.client.call_raw(proto.EntropyAck(entropy=external_entropy)) mnemonic = [] while isinstance(resp, proto.ButtonRequest): mnemonic.append(self.client.debug.read_reset_word()) self.client.debug.press_yes() resp = self.client.call_raw(proto.ButtonAck()) mnemonic = ' '.join(mnemonic) # wipe device ret = self.client.call_raw(proto.WipeDevice()) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) # recover devce ret = self.client.call_raw(proto.RecoveryDevice(word_count=(strength/32*3), passphrase_protection=False, pin_protection=False, label='label', language='english', enforce_wordlist=True, use_character_cipher=True)) mnemonic_words = mnemonic.split(' ') for index, word in enumerate(mnemonic_words): for character in word: self.assertIsInstance(ret, proto.CharacterRequest) cipher = self.client.debug.read_recovery_cipher() encoded_character = cipher[ord(character) - 97] ret = self.client.call_raw(proto.CharacterAck(character=encoded_character)) auto_completed = self.client.debug.read_recovery_auto_completed_word() if word == auto_completed: if len(mnemonic_words) != index + 1: ret = self.client.call_raw(proto.CharacterAck(character=' ')) break # Send final ack self.assertIsInstance(ret, proto.CharacterRequest) ret = self.client.call_raw(proto.CharacterAck(done=True)) # Workflow succesfully ended self.assertIsInstance(ret, proto.Success) self.client.init_device() self.assertEqual(self.client.debug.read_mnemonic(), mnemonic) # wipe device ret = self.client.call_raw(proto.WipeDevice()) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck())
def test_ethereum_signtx_data(self): self.setup_mnemonic_nopin_nopassphrase() self.client.apply_policy('AdvancedMode', 0) with self.client: ret = self.client.call_raw( proto.EthereumSignTx( address_n=[0, 0], nonce=int_to_big_endian(0), gas_price=int_to_big_endian(20), gas_limit=int_to_big_endian(20), value=int_to_big_endian(10), to=binascii.unhexlify( '1d1c328764a41bda0492b66baa30c4a339ff85ef'), data_initial_chunk='abcdefghijklmnop' * 64, data_length=1024)) # Confirm the Output self.assertEqual( ret, proto.ButtonRequest( code=proto_types.ButtonRequest_ConfirmOutput)) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) # Confirm Warning about AdvancedMode being turned off self.assertEqual( ret, proto.ButtonRequest(code=proto_types.ButtonRequest_Other)) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) self.assertEqual(ret.code, proto_types.Failure_ActionCancelled) self.client.apply_policy('AdvancedMode', 1) sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=[0, 0], nonce=0, gas_price=20, gas_limit=20, to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'), value=10, data='abcdefghijklmnop' * 16) self.assertEqual(sig_v, 28) self.assertEqual( binascii.hexlify(sig_r), '6da89ed8627a491bedc9e0382f37707ac4e5102e25e7a1234cb697cedb7cd2c0') self.assertEqual( binascii.hexlify(sig_s), '691f73b145647623e2d115b208a7c3455a6a8a83e3b4db5b9c6d9bc75825038a') sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=[0, 0], nonce=123456, gas_price=20000, gas_limit=20000, to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'), value=12345678901234567890, data='ABCDEFGHIJKLMNOP' * 256 + '!!!') self.assertEqual(sig_v, 28) self.assertEqual( binascii.hexlify(sig_r), '4e90b13c45c6a9bf4aaad0e5427c3e62d76692b36eb727c78d332441b7400404') self.assertEqual( binascii.hexlify(sig_s), '3ff236e7d05f0f9b1ee3d70599bb4200638f28388a8faf6bb36db9e04dc544be') self.client.apply_policy('AdvancedMode', 0)