Exemplo n.º 1
0
async def change_pin(ctx, msg):

    # confirm that user wants to change the pin
    await require_confirm_change_pin(ctx, msg)

    # get current pin, return failure if invalid
    if config.has_pin():
        curpin = await request_pin_ack(ctx, "Enter old PIN",
                                       config.get_pin_rem())
        # if removing, defer check to change_pin()
        if not msg.remove:
            if not config.check_pin(pin_to_int(curpin)):
                raise wire.PinInvalid("PIN invalid")
    else:
        curpin = ""

    # get new pin
    if not msg.remove:
        newpin = await request_pin_confirm(ctx)
    else:
        newpin = ""

    # write into storage
    if not config.change_pin(pin_to_int(curpin), pin_to_int(newpin)):
        raise wire.PinInvalid("PIN invalid")

    if newpin:
        return Success(message="PIN changed")
    else:
        return Success(message="PIN removed")
Exemplo n.º 2
0
async def change_pin(ctx, msg):

    # confirm that user wants to change the pin
    await require_confirm_change_pin(ctx, msg)

    # get current pin, return failure if invalid
    if config.has_pin():
        curpin = await request_pin_ack(ctx)
        if not config.check_pin(pin_to_int(curpin), show_pin_timeout):
            raise wire.PinInvalid('PIN invalid')
    else:
        curpin = ''

    # get new pin
    if not msg.remove:
        newpin = await request_pin_confirm(ctx)
    else:
        newpin = ''

    # write into storage
    if not config.change_pin(pin_to_int(curpin), pin_to_int(newpin),
                             show_pin_timeout):
        raise wire.PinInvalid('PIN invalid')

    if newpin:
        return Success(message='PIN changed')
    else:
        return Success(message='PIN removed')
Exemplo n.º 3
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
    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")
Exemplo n.º 4
0
async def sd_protect_disable(ctx: wire.Context, msg: SdProtect) -> Success:
    if device.get_sd_salt_auth_key() is None:
        raise wire.ProcessError("SD card protection not enabled")

    # Confirm that user wants to proceed with the operation.
    await require_confirm_sd_protect(ctx, msg)

    # Get the current PIN and salt from the SD card.
    pin, salt = await request_pin_and_sd_salt(ctx, "Enter PIN")

    # Check PIN and remove salt.
    if not config.change_pin(pin_to_int(pin), pin_to_int(pin), salt, None):
        await show_pin_invalid(ctx)
        raise wire.PinInvalid("PIN invalid")

    device.set_sd_salt_auth_key(None)

    try:
        # Clean up.
        await remove_sd_salt(ctx)
    except Exception:
        # The cleanup is not necessary for the correct functioning of
        # SD-protection. If it fails for any reason, we suppress the exception,
        # because overall SD-protection was successfully disabled.
        pass

    await show_success(ctx,
                       ("You have successfully", "disabled SD protection."))
    return Success(message="SD card protection disabled")
Exemplo n.º 5
0
async def change_pin(ctx: wire.Context, msg: ChangePin) -> Success:
    if not is_initialized():
        raise wire.NotInitialized("Device is not initialized")

    # confirm that user wants to change the pin
    await require_confirm_change_pin(ctx, msg)

    # get old pin
    curpin, salt = await request_pin_and_sd_salt(ctx, "Enter old PIN")

    # if changing pin, pre-check the entered pin before getting new pin
    if curpin and not msg.remove:
        if not config.check_pin(pin_to_int(curpin), salt):
            await show_pin_invalid(ctx)
            raise wire.PinInvalid("PIN invalid")

    # get new pin
    if not msg.remove:
        newpin = await request_pin_confirm(ctx)
    else:
        newpin = ""

    # write into storage
    if not config.change_pin(pin_to_int(curpin), pin_to_int(newpin), salt,
                             salt):
        if newpin:
            await show_pin_matches_wipe_code(ctx)
        else:
            await show_pin_invalid(ctx)
        raise wire.PinInvalid("PIN invalid")

    if newpin:
        if curpin:
            msg_screen = "changed your PIN."
            msg_wire = "PIN changed"
        else:
            msg_screen = "enabled PIN protection."
            msg_wire = "PIN enabled"
    else:
        msg_screen = "disabled PIN protection."
        msg_wire = "PIN removed"

    await show_success(ctx, ("You have successfully", msg_screen))
    return Success(message=msg_wire)
async def change_wipe_code(ctx: wire.Context, msg: ChangeWipeCode) -> Success:
    if not is_initialized():
        raise wire.NotInitialized("Device is not initialized")

    # Confirm that user wants to set or remove the wipe code.
    has_wipe_code = config.has_wipe_code()
    await _require_confirm_action(ctx, msg, has_wipe_code)

    # Get the unlocking PIN.
    pin, salt = await request_pin_and_sd_salt(ctx)

    if not msg.remove:
        # Pre-check the entered PIN.
        if config.has_pin() and not config.check_pin(pin_to_int(pin), salt):
            await show_pin_invalid(ctx)
            raise wire.PinInvalid("PIN invalid")

        # Get new wipe code.
        wipe_code = await _request_wipe_code_confirm(ctx, pin)
    else:
        wipe_code = ""

    # Write into storage.
    if not config.change_wipe_code(pin_to_int(pin), salt,
                                   pin_to_int(wipe_code)):
        await show_pin_invalid(ctx)
        raise wire.PinInvalid("PIN invalid")

    if wipe_code:
        if has_wipe_code:
            msg_screen = "changed the wipe code."
            msg_wire = "Wipe code changed"
        else:
            msg_screen = "set the wipe code."
            msg_wire = "Wipe code set"
    else:
        msg_screen = "disabled the wipe code."
        msg_wire = "Wipe code removed"

    await show_success(ctx, ("You have successfully", msg_screen))
    return Success(message=msg_wire)
Exemplo n.º 7
0
async def recovery_device(ctx: wire.Context, msg: RecoveryDevice) -> Success:
    """
    Recover BIP39/SLIP39 seed into empty device.
    Recovery is also possible with replugged Trezor. We call this process Persistance.
    User starts the process here using the RecoveryDevice msg and then they can unplug
    the device anytime and continue without a computer.
    """
    _check_state(msg)

    if not msg.dry_run:
        title = "Recovery mode"
        text = Text(title, ui.ICON_RECOVERY)
        text.normal("Do you really want to", "recover a wallet?", "")
    else:
        title = "Seed check"
        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)

    # for dry run pin needs to entered
    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")

    # set up pin if requested
    if msg.pin_protection:
        if msg.dry_run:
            raise wire.ProcessError("Can't setup PIN during dry_run recovery.")
        newpin = await request_pin_confirm(ctx, allow_cancel=False)
        config.change_pin(pin_to_int(""), pin_to_int(newpin))

    if msg.u2f_counter:
        storage.device.set_u2f_counter(msg.u2f_counter)
    storage.device.load_settings(label=msg.label,
                                 use_passphrase=msg.passphrase_protection)
    storage.recovery.set_in_progress(True)
    if msg.dry_run:
        storage.recovery.set_dry_run(msg.dry_run)

    result = await recovery_process(ctx)

    return result
Exemplo n.º 8
0
async def sd_protect_enable(ctx: wire.Context, msg: SdProtect) -> Success:
    salt_auth_key = device.get_sd_salt_auth_key()
    if salt_auth_key is not None:
        raise wire.ProcessError("SD card protection already enabled")

    # Confirm that user wants to proceed with the operation.
    await require_confirm_sd_protect(ctx, msg)

    # Get the current PIN.
    if config.has_pin():
        pin = pin_to_int(await request_pin_ack(ctx, "Enter PIN",
                                               config.get_pin_rem()))
    else:
        pin = pin_to_int("")

    # Check PIN and prepare salt file.
    salt = random.bytes(SD_SALT_LEN_BYTES)
    salt_auth_key = random.bytes(SD_SALT_AUTH_KEY_LEN_BYTES)
    salt_tag = hmac.new(salt_auth_key, salt,
                        sha256).digest()[:SD_SALT_AUTH_TAG_LEN_BYTES]
    try:
        await set_sd_salt(ctx, salt, salt_tag)
    except Exception:
        raise wire.ProcessError("Failed to write to SD card")

    if not config.change_pin(pin, pin, None, salt):
        # Wrong PIN. Clean up the prepared salt file.
        try:
            await remove_sd_salt(ctx)
        except Exception:
            # The cleanup is not necessary for the correct functioning of
            # SD-protection. If it fails for any reason, we suppress the
            # exception, because primarily we need to raise wire.PinInvalid.
            pass
        await show_pin_invalid(ctx)
        raise wire.PinInvalid("PIN invalid")

    device.set_sd_salt_auth_key(salt_auth_key)

    await show_success(ctx,
                       ("You have successfully", "enabled SD protection."))
    return Success(message="SD card protection enabled")
Exemplo n.º 9
0
async def sd_protect_refresh(ctx: wire.Context, msg: SdProtect) -> Success:
    if device.get_sd_salt_auth_key() is None:
        raise wire.ProcessError("SD card protection not enabled")

    # Confirm that user wants to proceed with the operation.
    await require_confirm_sd_protect(ctx, msg)

    # Get the current PIN and salt from the SD card.
    pin, old_salt = await request_pin_and_sd_salt(ctx, "Enter PIN")

    # Check PIN and change salt.
    new_salt = random.bytes(SD_SALT_LEN_BYTES)
    new_salt_auth_key = random.bytes(SD_SALT_AUTH_KEY_LEN_BYTES)
    new_salt_tag = hmac.new(new_salt_auth_key, new_salt,
                            sha256).digest()[:SD_SALT_AUTH_TAG_LEN_BYTES]
    try:
        await stage_sd_salt(ctx, new_salt, new_salt_tag)
    except Exception:
        raise wire.ProcessError("Failed to write to SD card")

    if not config.change_pin(pin_to_int(pin), pin_to_int(pin), old_salt,
                             new_salt):
        await show_pin_invalid(ctx)
        raise wire.PinInvalid("PIN invalid")

    device.set_sd_salt_auth_key(new_salt_auth_key)

    try:
        # Clean up.
        await commit_sd_salt(ctx)
    except Exception:
        # If the cleanup fails, then request_sd_salt() will bring the SD card
        # into a consistent state. We suppress the exception, because overall
        # SD-protection was successfully refreshed.
        pass

    await show_success(ctx,
                       ("You have successfully", "refreshed SD protection."))
    return Success(message="SD card protection refreshed")
Exemplo n.º 10
0
async def recovery_device(ctx: wire.Context, msg: RecoveryDevice) -> Success:
    """
    Recover BIP39/SLIP39 seed into empty device.
    Recovery is also possible with replugged Trezor. We call this process Persistance.
    User starts the process here using the RecoveryDevice msg and then they can unplug
    the device anytime and continue without a computer.
    """
    _check_state(msg)

    if storage.recovery.is_in_progress():
        return await recovery_process(ctx)

    await _continue_dialog(ctx, msg)

    # for dry run pin needs to be entered
    if msg.dry_run:
        curpin, salt = await request_pin_and_sd_salt(ctx, "Enter PIN")
        if not config.check_pin(pin_to_int(curpin), salt):
            await show_pin_invalid(ctx)
            raise wire.PinInvalid("PIN invalid")

    # set up pin if requested
    if msg.pin_protection:
        if msg.dry_run:
            raise wire.ProcessError("Can't setup PIN during dry_run recovery.")
        newpin = await request_pin_confirm(ctx, allow_cancel=False)
        config.change_pin(pin_to_int(""), pin_to_int(newpin), None, None)

    if msg.u2f_counter:
        storage.device.set_u2f_counter(msg.u2f_counter)
    storage.device.load_settings(label=msg.label,
                                 use_passphrase=msg.passphrase_protection)
    storage.recovery.set_in_progress(True)
    if msg.dry_run:
        storage.recovery.set_dry_run(msg.dry_run)

    workflow.replace_default(recovery_homescreen)
    return await recovery_process(ctx)
Exemplo n.º 11
0
async def sd_protect_enable(ctx: wire.Context, msg: SdProtect) -> Success:
    if storage.sd_salt.is_enabled():
        raise wire.ProcessError("SD card protection already enabled")

    # Confirm that user wants to proceed with the operation.
    await require_confirm_sd_protect(ctx, msg)

    # Make sure SD card is present.
    await ensure_sdcard(ctx)

    # Get the current PIN.
    if config.has_pin():
        pin = pin_to_int(await request_pin_ack(ctx, "Enter PIN",
                                               config.get_pin_rem()))
    else:
        pin = pin_to_int("")

    # Check PIN and prepare salt file.
    salt, salt_auth_key, salt_tag = _make_salt()
    await _set_salt(ctx, salt, salt_tag)

    if not config.change_pin(pin, pin, None, salt):
        # Wrong PIN. Clean up the prepared salt file.
        try:
            storage.sd_salt.remove_sd_salt()
        except Exception:
            # The cleanup is not necessary for the correct functioning of
            # SD-protection. If it fails for any reason, we suppress the
            # exception, because primarily we need to raise wire.PinInvalid.
            pass
        await show_pin_invalid(ctx)
        raise wire.PinInvalid("PIN invalid")

    storage.device.set_sd_salt_auth_key(salt_auth_key)

    await show_success(ctx,
                       ("You have successfully", "enabled SD protection."))
    return Success(message="SD card protection enabled")
Exemplo n.º 12
0
async def sd_protect_refresh(ctx: wire.Context, msg: SdProtect) -> Success:
    if not storage.sd_salt.is_enabled():
        raise wire.ProcessError("SD card protection not enabled")

    # Confirm that user wants to proceed with the operation.
    await require_confirm_sd_protect(ctx, msg)

    # Make sure SD card is present.
    await ensure_sdcard(ctx)

    # Get the current PIN and salt from the SD card.
    pin, old_salt = await request_pin_and_sd_salt(ctx, "Enter PIN")

    # Check PIN and change salt.
    new_salt, new_auth_key, new_salt_tag = _make_salt()
    await _set_salt(ctx, new_salt, new_salt_tag, stage=True)

    if not config.change_pin(pin_to_int(pin), pin_to_int(pin), old_salt,
                             new_salt):
        await show_pin_invalid(ctx)
        raise wire.PinInvalid("PIN invalid")

    storage.device.set_sd_salt_auth_key(new_auth_key)

    try:
        # Clean up.
        storage.sd_salt.commit_sd_salt()
    except Exception:
        # If the cleanup fails, then request_sd_salt() will bring the SD card
        # into a consistent state. We suppress the exception, because overall
        # SD-protection was successfully refreshed.
        pass

    await show_success(ctx,
                       ("You have successfully", "refreshed SD protection."))
    return Success(message="SD card protection refreshed")
Exemplo n.º 13
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")