async def recovery_device(ctx, msg): """ Recover BIP39 seed into empty device. 1. Ask for the number of words in recovered seed. 2. Let user type in the mnemonic words one by one. 3. Optionally check the seed validity. 4. Optionally ask for the PIN, with confirmation. 5. Save into storage. """ if not msg.dry_run and storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") text = Text("Device recovery", ui.ICON_RECOVERY) text.normal("Do you really want to", "recover the device?", "") await require_confirm(ctx, text, code=ProtectCall) if msg.dry_run and config.has_pin(): curpin = await request_pin_ack(ctx, "Enter PIN", config.get_pin_rem()) if not config.check_pin(pin_to_int(curpin)): raise wire.PinInvalid("PIN invalid") # ask for the number of words wordcount = await request_wordcount(ctx) # ask for mnemonic words one by one mnemonic = await request_mnemonic(ctx, wordcount) # check mnemonic validity if msg.enforce_wordlist or msg.dry_run: if not bip39.check(mnemonic): raise wire.ProcessError("Mnemonic is not valid") # ask for pin repeatedly if msg.pin_protection: newpin = await request_pin_confirm(ctx, cancellable=False) # dry run if msg.dry_run: digest_input = sha256(mnemonic).digest() digest_stored = sha256(storage.get_mnemonic()).digest() if consteq(digest_stored, digest_input): return Success( message="The seed is valid and matches the one in the device") else: raise wire.ProcessError( "The seed is valid but does not match the one in the device") # save into storage if msg.pin_protection: config.change_pin(pin_to_int(""), pin_to_int(newpin)) storage.set_u2f_counter(msg.u2f_counter) storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) storage.load_mnemonic(mnemonic=mnemonic, needs_backup=False, no_backup=False) return Success(message="Device recovered")
async def set_u2f_counter(ctx, msg): if msg.u2f_counter is None: raise wire.ProcessError("No value provided") text = Text("Set U2F counter", ui.ICON_CONFIG) text.normal("Do you really want to", "set the U2F counter") text.bold("to %d?" % msg.u2f_counter) await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) storage.set_u2f_counter(msg.u2f_counter) return Success(message="U2F counter set")
async def set_u2f_counter(ctx, msg): if msg.u2f_counter is None: raise wire.ProcessError('No value provided') text = Text('Set U2F counter', ui.ICON_CONFIG) text.normal('Do you really want to', 'set the U2F counter') text.bold('to %d?' % msg.u2f_counter) await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) storage.set_u2f_counter(msg.u2f_counter) return Success(message='U2F counter set')
async def set_u2f_counter(ctx, msg): if msg.u2f_counter is None: raise wire.FailureError(FailureType.ProcessError, 'No value provided provided') await require_confirm(ctx, Text('Set U2F counter', ui.ICON_CONFIG, 'Do you really want to', 'set the U2F counter', ui.BOLD, 'to %d?' % msg.u2f_counter), code=ButtonRequestType.ProtectCall) storage.set_u2f_counter(msg.u2f_counter) return Success(message='U2F counter set')
def test_counter(self): config.init() config.wipe() for i in range(150): self.assertEqual(storage.next_u2f_counter(), i) storage.set_u2f_counter(350) for i in range(351, 500): self.assertEqual(storage.next_u2f_counter(), i) storage.set_u2f_counter(0) self.assertEqual(storage.next_u2f_counter(), 1) storage.set_u2f_counter(None) self.assertEqual(storage.next_u2f_counter(), 0)
async def recovery_device(ctx, msg): """ Recover BIP39/SLIP39 seed into empty device. 1. Ask for the number of words in recovered seed. 2. Let user type in the mnemonic words one by one. 3. Optionally check the seed validity. 4. Optionally ask for the PIN, with confirmation. 5. Save into storage. """ if not msg.dry_run and storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") if not storage.is_slip39_in_progress(): if not msg.dry_run: title = "Wallet recovery" text = Text(title, ui.ICON_RECOVERY) text.normal("Do you really want to", "recover the wallet?", "") else: title = "Simulated recovery" text = Text(title, ui.ICON_RECOVERY) text.normal("Do you really want to", "check the recovery", "seed?") await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) if msg.dry_run: if config.has_pin(): curpin = await request_pin_ack(ctx, "Enter PIN", config.get_pin_rem()) else: curpin = "" if not config.check_pin(pin_to_int(curpin)): raise wire.PinInvalid("PIN invalid") # ask for the number of words wordcount = await request_wordcount(ctx, title) mnemonic_module = mnemonic.module_from_words_count(wordcount) else: wordcount = storage.get_slip39_words_count() mnemonic_module = mnemonic.slip39 if mnemonic_module == mnemonic.slip39: # show a note about the keyboard await show_keyboard_info(ctx) if msg.dry_run: dry_run_mnemonics = [] dry_run_mnemonic_count = None secret = None while secret is None: # ask for mnemonic words one by one words = await request_mnemonic(ctx, wordcount, mnemonic_module == mnemonic.slip39) try: if msg.dry_run: if dry_run_mnemonic_count is None: dry_run_mnemonic_count = mnemonic_module.get_mnemonic_count( words) dry_run_mnemonics.append(words) else: secret = mnemonic_module.process_single(words) except slip39.MnemonicError as e: raise wire.ProcessError("Mnemonic is not valid: " + str(e)) if msg.dry_run: remaining = dry_run_mnemonic_count - len(dry_run_mnemonics) if remaining == 0: secret = mnemonic_module.process_all(dry_run_mnemonics) else: remaining = storage.get_slip39_remaining() # show a number of remaining mnemonics for SLIP39 if secret is None and mnemonic_module == mnemonic.slip39: await show_remaining_slip39_mnemonics(ctx, title, remaining) # check mnemonic validity # it is checked automatically in SLIP-39 if mnemonic_module == mnemonic.bip39 and (msg.enforce_wordlist or msg.dry_run): if not mnemonic_module.check(secret): raise wire.ProcessError("Mnemonic is not valid") # ask for pin repeatedly if msg.pin_protection: newpin = await request_pin_confirm(ctx, allow_cancel=False) else: newpin = "" # dry run if msg.dry_run: return mnemonic.dry_run(secret) # save into storage if msg.pin_protection: config.change_pin(pin_to_int(""), pin_to_int(newpin)) storage.set_u2f_counter(msg.u2f_counter) storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) mnemonic_module.store(secret=secret, needs_backup=False, no_backup=False) await show_success(ctx) display_homescreen() return Success(message="Device recovered")