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 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")
Beispiel #2
0
async def handle_LockDevice(ctx: wire.Context, msg: LockDevice) -> Success:
    lock_device()
    return Success()
Beispiel #3
0
async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success:
    # validate parameters and device state
    _validate_reset_device(msg)

    # make sure user knows they're setting up a new wallet
    await layout.show_reset_device_warning(ctx, msg.backup_type)

    # wipe storage to make sure the device is in a clear state
    storage.reset()

    # request and set new PIN
    if msg.pin_protection:
        newpin = await request_pin_confirm(ctx)
        if not config.change_pin(pin_to_int(""), pin_to_int(newpin), None, None):
            raise wire.ProcessError("Failed to set PIN")

    # generate and display internal entropy
    int_entropy = random.bytes(32)
    if __debug__:
        debug.reset_internal_entropy = int_entropy
    if msg.display_random:
        await layout.show_internal_entropy(ctx, int_entropy)

    # request external entropy and compute the master secret
    entropy_ack = await ctx.call(EntropyRequest(), EntropyAck)
    ext_entropy = entropy_ack.entropy
    # For SLIP-39 this is the Encrypted Master Secret
    secret = _compute_secret_from_entropy(int_entropy, ext_entropy, msg.strength)

    # Check backup type, perform type-specific handling
    if msg.backup_type == BackupType.Bip39:
        # in BIP-39 we store mnemonic string instead of the secret
        secret = bip39.from_data(secret).encode()
    elif msg.backup_type in (BackupType.Slip39_Basic, BackupType.Slip39_Advanced):
        # generate and set SLIP39 parameters
        storage.device.set_slip39_identifier(slip39.generate_random_identifier())
        storage.device.set_slip39_iteration_exponent(slip39.DEFAULT_ITERATION_EXPONENT)
    else:
        # Unknown backup type.
        raise RuntimeError

    # If either of skip_backup or no_backup is specified, we are not doing backup now.
    # Otherwise, we try to do it.
    perform_backup = not msg.no_backup and not msg.skip_backup

    # If doing backup, ask the user to confirm.
    if perform_backup:
        perform_backup = await layout.confirm_backup(ctx)

    # generate and display backup information for the master secret
    if perform_backup:
        await backup_seed(ctx, msg.backup_type, secret)

    # write settings and master secret into storage
    if msg.label is not None:
        storage.device.set_label(msg.label)
    storage.device.set_passphrase_enabled(bool(msg.passphrase_protection))
    storage.device.store_mnemonic_secret(
        secret,  # for SLIP-39, this is the EMS
        msg.backup_type,
        needs_backup=not perform_backup,
        no_backup=msg.no_backup,
    )

    # if we backed up the wallet, show success message
    if perform_backup:
        await layout.show_backup_success(ctx)

    return Success(message="Initialized")
Beispiel #4
0
async def handle_EndSession(ctx: wire.Context, msg: EndSession) -> Success:
    cache.end_current_session()
    return Success()
Beispiel #5
0
async def apply_flags(ctx, msg):
    storage.set_flags(msg.flags)
    return Success(message='Flags applied')
async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success:
    # validate parameters and device state
    _validate_reset_device(msg)

    is_slip39_simple = msg.backup_type == ResetDeviceBackupType.Slip39_Single_Group

    # make sure user knows he's setting up a new wallet
    await _show_reset_device_warning(ctx, is_slip39_simple)

    # request new PIN
    if msg.pin_protection:
        newpin = await request_pin_confirm(ctx)
    else:
        newpin = ""

    # generate and display internal entropy
    int_entropy = random.bytes(32)
    if __debug__:
        debug.reset_internal_entropy = int_entropy
    if msg.display_random:
        await layout.show_internal_entropy(ctx, int_entropy)

    # request external entropy and compute the master secret
    entropy_ack = await ctx.call(EntropyRequest(), EntropyAck)
    ext_entropy = entropy_ack.entropy
    secret = _compute_secret_from_entropy(int_entropy, ext_entropy,
                                          msg.strength)

    if is_slip39_simple:
        storage.slip39.set_identifier(slip39.generate_random_identifier())
        storage.slip39.set_iteration_exponent(
            slip39.DEFAULT_ITERATION_EXPONENT)

    # should we back up the wallet now?
    if not msg.no_backup and not msg.skip_backup:
        if not await layout.confirm_backup(ctx):
            if not await layout.confirm_backup_again(ctx):
                msg.skip_backup = True

    # generate and display backup information for the master secret
    if not msg.no_backup and not msg.skip_backup:
        if is_slip39_simple:
            await backup_slip39_wallet(ctx, secret)
        else:
            await backup_bip39_wallet(ctx, secret)

    # write PIN into storage
    if not config.change_pin(pin_to_int(""), pin_to_int(newpin)):
        raise wire.ProcessError("Could not change PIN")

    # write settings and master secret into storage
    storage.device.load_settings(label=msg.label,
                                 use_passphrase=msg.passphrase_protection)
    if is_slip39_simple:
        mnemonic.slip39.store(secret=secret,
                              needs_backup=msg.skip_backup,
                              no_backup=msg.no_backup)
    else:
        # in BIP-39 we store mnemonic string instead of the secret
        mnemonic.bip39.store(
            secret=bip39.from_data(secret).encode(),
            needs_backup=msg.skip_backup,
            no_backup=msg.no_backup,
        )

    # if we backed up the wallet, show success message
    if not msg.no_backup and not msg.skip_backup:
        await layout.show_backup_success(ctx)

    return Success(message="Initialized")
async def apply_flags(ctx, msg):
    if not storage.device.is_initialized():
        raise wire.NotInitialized("Device is not initialized")
    set_flags(msg.flags)
    return Success(message="Flags applied")
Beispiel #8
0
async def apply_flags(ctx, msg):
    set_flags(msg.flags)
    return Success(message="Flags applied")
Beispiel #9
0
async def reset_device(ctx, msg):
    # validate parameters and device state
    if msg.strength not in (128, 192, 256):
        raise wire.ProcessError(
            "Invalid strength (has to be 128, 192 or 256 bits)")
    if msg.display_random and (msg.skip_backup or msg.no_backup):
        raise wire.ProcessError(
            "Can't show internal entropy when backup is skipped")
    if storage.is_initialized():
        raise wire.UnexpectedMessage("Already initialized")

    text = Text("Create a new wallet", ui.ICON_RESET, new_lines=False)
    text.normal("Do you really want to")
    text.br()
    text.normal("create a new wallet?")
    text.br()
    text.br_half()
    text.normal("By continuing you agree")
    text.br()
    text.normal("to")
    text.bold("https://trezor.io/tos")

    await require_confirm(ctx, text, code=ButtonRequestType.ResetDevice)

    # request new PIN
    if msg.pin_protection:
        newpin = await request_pin_confirm(ctx)
    else:
        newpin = ""

    # generate and display internal entropy
    internal_ent = random.bytes(32)
    if __debug__:
        debug.reset_internal_entropy = internal_ent
    if msg.display_random:
        await show_entropy(ctx, internal_ent)

    # request external entropy and compute mnemonic
    ent_ack = await ctx.call(EntropyRequest(), MessageType.EntropyAck)
    words = generate_mnemonic(msg.strength, internal_ent, ent_ack.entropy)

    beam_nonce_seed = random.bytes(32)
    create_master_nonce(beam_nonce_seed)

    if not msg.skip_backup and not msg.no_backup:
        # require confirmation of the mnemonic safety
        await show_warning(ctx)

        # show mnemonic and require confirmation of a random word
        while True:
            await show_mnemonic(ctx, words)
            if await check_mnemonic(ctx, words):
                break
            await show_wrong_entry(ctx)

    # write PIN into storage
    if newpin:
        if not config.change_pin(pin_to_int(""), pin_to_int(newpin)):
            raise wire.ProcessError("Could not change PIN")

    secret = mnemonic.process([words], mnemonic.TYPE_BIP39)
    # write settings and mnemonic into storage
    storage.load_settings(label=msg.label,
                          use_passphrase=msg.passphrase_protection)
    storage.store_mnemonic(
        secret=secret,
        mnemonic_type=mnemonic.TYPE_BIP39,
        needs_backup=msg.skip_backup,
        no_backup=msg.no_backup,
    )

    # show success message.  if we skipped backup, it's possible that homescreen
    # is still running, uninterrupted.  restart it to pick up new label.
    if not msg.skip_backup and not msg.no_backup:
        await show_success(ctx)
    else:
        workflow.restartdefault()

    return Success(message="Initialized")
Beispiel #10
0
async def handle_CancelAuthorization(
        ctx: wire.Context, msg: CancelAuthorization) -> protobuf.MessageType:
    from apps.common import authorization

    authorization.clear()
    return Success(message="Authorization cancelled")
async def apply_settings(ctx: wire.Context, msg: ApplySettings):
    if not storage.device.is_initialized():
        raise wire.NotInitialized("Device is not initialized")
    if (msg.homescreen is None and msg.label is None
            and msg.use_passphrase is None
            and msg.passphrase_always_on_device is None
            and msg.display_rotation is None and msg.auto_lock_delay_ms is None
            and msg.safety_checks is None
            and msg.experimental_features is None):
        raise wire.ProcessError("No setting provided")

    if msg.homescreen is not None:
        validate_homescreen(msg.homescreen)
        await require_confirm_change_homescreen(ctx)
        try:
            storage.device.set_homescreen(msg.homescreen)
        except ValueError:
            raise wire.DataError("Invalid homescreen")

    if msg.label is not None:
        await require_confirm_change_label(ctx, msg.label)
        storage.device.set_label(msg.label)

    if msg.use_passphrase is not None:
        await require_confirm_change_passphrase(ctx, msg.use_passphrase)
        storage.device.set_passphrase_enabled(msg.use_passphrase)

    if msg.passphrase_always_on_device is not None:
        if not storage.device.is_passphrase_enabled():
            raise wire.DataError("Passphrase is not enabled")
        await require_confirm_change_passphrase_source(
            ctx, msg.passphrase_always_on_device)
        storage.device.set_passphrase_always_on_device(
            msg.passphrase_always_on_device)

    if msg.auto_lock_delay_ms is not None:
        if msg.auto_lock_delay_ms < storage.device.AUTOLOCK_DELAY_MINIMUM:
            raise wire.ProcessError("Auto-lock delay too short")
        if msg.auto_lock_delay_ms > storage.device.AUTOLOCK_DELAY_MAXIMUM:
            raise wire.ProcessError("Auto-lock delay too long")
        await require_confirm_change_autolock_delay(ctx,
                                                    msg.auto_lock_delay_ms)
        storage.device.set_autolock_delay_ms(msg.auto_lock_delay_ms)
        # use the value that was stored, not the one that was supplied by the user
        workflow.idle_timer.set(storage.device.get_autolock_delay_ms(),
                                lock_device)

    if msg.safety_checks is not None:
        await require_confirm_safety_checks(ctx, msg.safety_checks)
        safety_checks.apply_setting(msg.safety_checks)

    if msg.display_rotation is not None:
        await require_confirm_change_display_rotation(ctx,
                                                      msg.display_rotation)
        storage.device.set_rotation(msg.display_rotation)
        ui.display.orientation(storage.device.get_rotation())

    if msg.experimental_features is not None:
        await require_confirm_experimental_features(ctx,
                                                    msg.experimental_features)
        storage.device.set_experimental_features(msg.experimental_features)
        wire.experimental_enabled = msg.experimental_features

    return Success(message="Settings applied")
Beispiel #12
0
async def handle_ClearSession(ctx, msg):
    cache.clear(keep_passphrase=True)
    return Success(message="Session cleared")
Beispiel #13
0
async def respond_ClearSession(ctx, msg):
    cache.clear()
    return Success(message='Session cleared')
Beispiel #14
0
async def reset_device(ctx, msg):
    # validate parameters and device state
    if msg.strength not in (128, 192, 256):
        raise wire.ProcessError(
            "Invalid strength (has to be 128, 192 or 256 bits)")
    if msg.display_random and (msg.skip_backup or msg.no_backup):
        raise wire.ProcessError(
            "Can't show internal entropy when backup is skipped")
    if storage.is_initialized():
        raise wire.UnexpectedMessage("Already initialized")

    # make sure use knows he's setting up a new wallet
    await show_reset_warning(ctx)

    # request new PIN
    if msg.pin_protection:
        newpin = await request_pin_confirm(ctx)
    else:
        newpin = ""

    # generate and display internal entropy
    internal_ent = random.bytes(32)
    if __debug__:
        debug.reset_internal_entropy = internal_ent
    if msg.display_random:
        await show_entropy(ctx, internal_ent)

    # request external entropy and compute mnemonic
    ent_ack = await ctx.call(EntropyRequest(), MessageType.EntropyAck)
    words = generate_mnemonic(msg.strength, internal_ent, ent_ack.entropy)

    if not msg.skip_backup and not msg.no_backup:
        # require confirmation of the mnemonic safety
        await show_backup_warning(ctx)

        # show mnemonic and require confirmation of a random word
        while True:
            await show_mnemonic(ctx, words)
            if await check_mnemonic(ctx, words):
                break
            await show_wrong_entry(ctx)

    # write PIN into storage
    if newpin:
        if not config.change_pin(pin_to_int(""), pin_to_int(newpin)):
            raise wire.ProcessError("Could not change PIN")

    secret = mnemonic.process([words], mnemonic.TYPE_BIP39)
    # write settings and mnemonic into storage
    storage.load_settings(label=msg.label,
                          use_passphrase=msg.passphrase_protection)
    storage.store_mnemonic(
        secret=secret,
        mnemonic_type=mnemonic.TYPE_BIP39,
        needs_backup=msg.skip_backup,
        no_backup=msg.no_backup,
    )

    # show success message
    if not msg.skip_backup and not msg.no_backup:
        await show_success(ctx)

    return Success(message="Initialized")
Beispiel #15
0
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
    words = await request_mnemonic(ctx, wordcount)

    # check mnemonic validity
    if msg.enforce_wordlist or msg.dry_run:
        if not bip39.check(words):
            raise wire.ProcessError("Mnemonic is not valid")

    # ask for pin repeatedly
    if msg.pin_protection:
        newpin = await request_pin_confirm(ctx, cancellable=False)
    else:
        newpin = ""

    secret = mnemonic.process([words], mnemonic.TYPE_BIP39)

    # dry run
    if msg.dry_run:
        digest_input = sha256(secret).digest()
        stored, _ = mnemonic.get()
        digest_stored = sha256(stored).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 newpin:
        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.store_mnemonic(
        secret=secret,
        mnemonic_type=mnemonic.TYPE_BIP39,
        needs_backup=False,
        no_backup=False,
    )

    return Success(message="Device recovered")
Beispiel #16
0
async def handle_ClearSession(ctx, msg):
    cache.clear()
    return Success(message="Session cleared")
Beispiel #17
0
async def apply_settings(ctx: wire.Context, msg: ApplySettings):
    if not storage.device.is_initialized():
        raise wire.NotInitialized("Device is not initialized")
    if (msg.homescreen is None and msg.label is None
            and msg.use_passphrase is None
            and msg.passphrase_always_on_device is None
            and msg.display_rotation is None and msg.auto_lock_delay_ms is None
            and msg.safety_checks is None
            and msg.experimental_features is None):
        raise wire.ProcessError("No setting provided")

    if msg.homescreen is not None:
        validate_homescreen(msg.homescreen)
        await require_confirm_change_homescreen(ctx)
        try:
            storage.device.set_homescreen(msg.homescreen)
        except ValueError:
            raise wire.DataError("Invalid homescreen")

    if msg.label is not None:
        if len(msg.label) > storage.device.LABEL_MAXLENGTH:
            raise wire.DataError("Label too long")
        await require_confirm_change_label(ctx, msg.label)
        storage.device.set_label(msg.label)

    if msg.use_passphrase is not None:
        await require_confirm_change_passphrase(ctx, msg.use_passphrase)
        storage.device.set_passphrase_enabled(msg.use_passphrase)

    if msg.passphrase_always_on_device is not None:
        if not storage.device.is_passphrase_enabled():
            raise wire.DataError("Passphrase is not enabled")
        await require_confirm_change_passphrase_source(
            ctx, msg.passphrase_always_on_device)
        storage.device.set_passphrase_always_on_device(
            msg.passphrase_always_on_device)

    if msg.auto_lock_delay_ms is not None:
        if msg.auto_lock_delay_ms < storage.device.AUTOLOCK_DELAY_MINIMUM:
            raise wire.ProcessError("Auto-lock delay too short")
        if msg.auto_lock_delay_ms > storage.device.AUTOLOCK_DELAY_MAXIMUM:
            raise wire.ProcessError("Auto-lock delay too long")
        await require_confirm_change_autolock_delay(ctx,
                                                    msg.auto_lock_delay_ms)
        storage.device.set_autolock_delay_ms(msg.auto_lock_delay_ms)

    if msg.safety_checks is not None:
        await require_confirm_safety_checks(ctx, msg.safety_checks)
        safety_checks.apply_setting(msg.safety_checks)

    if msg.display_rotation is not None:
        await require_confirm_change_display_rotation(ctx,
                                                      msg.display_rotation)
        storage.device.set_rotation(msg.display_rotation)

    if msg.experimental_features is not None:
        await require_confirm_experimental_features(ctx,
                                                    msg.experimental_features)
        storage.device.set_experimental_features(msg.experimental_features)

    reload_settings_from_storage()

    return Success(message="Settings applied")
Beispiel #18
0
 async def dispatch_DebugLinkReseedRandom(
         ctx: wire.Context, msg: DebugLinkReseedRandom) -> Success:
     if msg.value is not None:
         crypto.random.reseed(msg.value)
     return Success()
Beispiel #19
0
async def handle_ClearSession(ctx: wire.Context, msg: ClearSession) -> Success:
    cache.clear(keep_passphrase=True)
    return Success(message="Session cleared")
async def verify_merkle_proof(ctx, msg):
    return Success(message="Message verified")