Пример #1
0
async def _finish_recovery_dry_run(ctx: wire.GenericContext, secret: bytes,
                                   backup_type: BackupType) -> Success:
    if backup_type is None:
        raise RuntimeError

    digest_input = sha256(secret).digest()
    stored = mnemonic.get_secret()
    digest_stored = sha256(stored).digest()
    result = utils.consteq(digest_stored, digest_input)

    is_slip39 = backup_types.is_slip39_backup_type(backup_type)
    # Check that the identifier and iteration exponent match as well
    if is_slip39:
        result &= (storage.device.get_slip39_identifier() ==
                   storage.recovery.get_slip39_identifier())
        result &= (storage.device.get_slip39_iteration_exponent() ==
                   storage.recovery.get_slip39_iteration_exponent())

    storage.recovery.end_progress()

    await layout.show_dry_run_result(ctx, result, is_slip39)

    if result:
        return Success(
            message="The seed is valid and matches the one in the device")
    else:
        raise wire.ProcessError(
            "The seed does not match the one in the device")
Пример #2
0
async def get_firmware(ctx: Context, _msg: GetFirmware) -> Success:
    await confirm_action(
        ctx,
        "dump_firmware",
        title="Extract firmware",
        action="Do you want to extract device firmware?",
        description="Your seed will not be revealed.",
    )
    sector_buffer = bytearray(CHUNK_SIZE)
    packet = FirmwareChunk(chunk=sector_buffer)

    workflow.close_others()
    draw_simple_text("Please wait")

    progress = 0
    _render_progress(progress, PROGRESS_TOTAL)
    for i in range(utils.FIRMWARE_SECTORS_COUNT):
        size = utils.firmware_sector_size(i)
        try:
            for ofs in range(0, size, CHUNK_SIZE):
                utils.get_firmware_chunk(i, ofs, sector_buffer)
                await ctx.call(packet, FirmwareChunkAck)
                progress += CHUNK_SIZE
                _render_progress(progress, PROGRESS_TOTAL)
            # reset progress to known point, in case some sectors are not 128 kB
            progress = (i + 1) * 128 * 1024
            _render_progress(progress, PROGRESS_TOTAL)
        except ValueError:
            raise wire.DataError("Failed to dump firmware.")
    return Success(message="Firmware dumped.")
Пример #3
0
async def handle_CancelAuthorization(
    ctx: wire.Context, msg: CancelAuthorization
) -> protobuf.MessageType:
    from apps.common import authorization

    authorization.clear()
    return Success(message="Authorization cancelled")
Пример #4
0
async def sd_protect_disable(ctx: wire.Context, msg: SdProtect) -> Success:
    if not storage.sd_salt.is_enabled():
        raise wire.ProcessError("SD card protection not enabled")

    # Note that the SD card doesn't need to be present in order to disable SD
    # protection. The cleanup will not happen in such case, but that does not matter.

    # 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, pin, salt, None):
        await error_pin_invalid(ctx)

    storage.device.set_sd_salt_auth_key(None)

    try:
        # Clean up.
        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 overall SD-protection was successfully disabled.
        pass

    await show_success(ctx, "success_sd",
                       "You have successfully disabled SD protection.")
    return Success(message="SD card protection disabled")
Пример #5
0
async def add_resident_credential(
        ctx: wire.Context, msg: WebAuthnAddResidentCredential) -> Success:
    if not storage.device.is_initialized():
        raise wire.NotInitialized("Device is not initialized")
    if not msg.credential_id:
        raise wire.ProcessError("Missing credential ID parameter.")

    try:
        cred = Fido2Credential.from_cred_id(bytes(msg.credential_id), None)
    except Exception:
        await show_error_and_raise(
            ctx,
            "warning_credential",
            header="Import credential",
            button="Close",
            content=
            "The credential you are trying to import does\nnot belong to this authenticator.",
            red=True,
        )

    if not await confirm_webauthn(ctx, ConfirmAddCredential(cred)):
        raise wire.ActionCancelled

    if store_resident_credential(cred):
        return Success(message="Credential added")
    else:
        raise wire.ProcessError("Internal credential storage is full.")
Пример #6
0
    async def dispatch_DebugLinkReseedRandom(
            ctx: wire.Context, msg: DebugLinkReseedRandom) -> Success:
        if msg.value is not None:
            from trezor.crypto import random

            random.reseed(msg.value)
        return Success()
Пример #7
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, pin, old_salt, new_salt):
        await error_pin_invalid(ctx)

    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, "success_sd",
                       "You have successfully refreshed SD protection.")
    return Success(message="SD card protection refreshed")
Пример #8
0
async def verify_message(ctx: Context, msg: EthereumVerifyMessage) -> Success:
    digest = message_digest(msg.message)
    if len(msg.signature) != 65:
        raise wire.DataError("Invalid signature")
    sig = bytearray([msg.signature[64]]) + msg.signature[:64]

    pubkey = secp256k1.verify_recover(sig, digest)

    if not pubkey:
        raise wire.DataError("Invalid signature")

    pkh = sha3_256(pubkey[1:], keccak=True).digest()[-20:]

    address_bytes = bytes_from_address(msg.address)
    if address_bytes != pkh:
        raise wire.DataError("Invalid signature")

    address = address_from_bytes(address_bytes)

    await confirm_signverify(ctx,
                             "ETH",
                             decode_message(msg.message),
                             address=address,
                             verify=True)

    return Success(message="Message verified")
Пример #9
0
async def handle_Ping(ctx: wire.Context, msg: Ping) -> Success:
    if msg.button_protection:
        from trezor.ui.layouts import confirm_action
        from trezor.enums import ButtonRequestType as B

        await confirm_action(ctx, "ping", "Confirm", "ping", br_code=B.ProtectCall)
    return Success(message=msg.message)
Пример #10
0
async def authorize_coinjoin(ctx: wire.Context, msg: AuthorizeCoinJoin,
                             keychain: Keychain, coin: CoinInfo) -> Success:
    if len(msg.coordinator) > _MAX_COORDINATOR_LEN or not all(
            32 <= ord(x) <= 126 for x in msg.coordinator):
        raise wire.DataError("Invalid coordinator name.")

    if msg.max_rounds > _MAX_ROUNDS and safety_checks.is_strict():
        raise wire.DataError("The number of rounds is unexpectedly large.")

    if (msg.max_coordinator_fee_rate > _MAX_COORDINATOR_FEE_RATE
            and safety_checks.is_strict()):
        raise wire.DataError(
            "The coordination fee rate is unexpectedly large.")

    if msg.max_fee_per_kvbyte > 10 * coin.maxfee_kb and safety_checks.is_strict(
    ):
        raise wire.DataError("The fee per vbyte is unexpectedly large.")

    if not msg.address_n:
        raise wire.DataError("Empty path not allowed.")

    await confirm_action(
        ctx,
        "coinjoin_coordinator",
        title="Authorize CoinJoin",
        description=
        "Do you really want to take part in a CoinJoin transaction at:\n{}",
        description_param=msg.coordinator,
        description_param_font=ui.MONO,
        icon=ui.ICON_RECOVERY,
    )

    max_fee_per_vbyte = format_amount(msg.max_fee_per_kvbyte, 3)
    await confirm_coinjoin(ctx, coin.coin_name, msg.max_rounds,
                           max_fee_per_vbyte)

    validation_path = msg.address_n + [0] * BIP32_WALLET_DEPTH
    await validate_path(
        ctx,
        keychain,
        validation_path,
        validate_path_against_script_type(coin,
                                          address_n=validation_path,
                                          script_type=msg.script_type),
    )

    if msg.max_fee_per_kvbyte > coin.maxfee_kb:
        await confirm_metadata(
            ctx,
            "fee_over_threshold",
            "High mining fee",
            "The mining fee of\n{} sats/vbyte\nis unexpectedly high.",
            max_fee_per_vbyte,
            ButtonRequestType.FeeOverThreshold,
        )

    authorization.set(msg)

    return Success(message="CoinJoin authorized")
Пример #11
0
    async def dispatch_DebugLinkWatchLayout(
        ctx: wire.Context, msg: DebugLinkWatchLayout
    ) -> Success:
        from trezor import ui

        layout_change_chan.putters.clear()
        await ui.wait_until_layout_is_running()
        storage.watch_layout_changes = bool(msg.watch)
        log.debug(__name__, "Watch layout changes: %s", storage.watch_layout_changes)
        return Success()
Пример #12
0
    async def dispatch_DebugLinkRecordScreen(
            ctx: wire.Context, msg: DebugLinkRecordScreen) -> Success:
        if msg.target_directory:
            storage.save_screen_directory = msg.target_directory
            storage.save_screen = True
        else:
            storage.save_screen = False
            display.clear_save()  # clear C buffers

        return Success()
Пример #13
0
async def verify_message(ctx: wire.Context, msg: VerifyMessage) -> Success:
    message = msg.message
    address = msg.address
    signature = msg.signature
    coin_name = msg.coin_name or "Bitcoin"
    coin = coins.by_name(coin_name)

    digest = message_digest(coin, message)

    recid = signature[0]
    if 27 <= recid <= 34:
        # p2pkh
        script_type = InputScriptType.SPENDADDRESS
    elif 35 <= recid <= 38:
        # segwit-in-p2sh
        script_type = InputScriptType.SPENDP2SHWITNESS
        signature = bytes([signature[0] - 4]) + signature[1:]
    elif 39 <= recid <= 42:
        # native segwit
        script_type = InputScriptType.SPENDWITNESS
        signature = bytes([signature[0] - 8]) + signature[1:]
    else:
        raise wire.ProcessError("Invalid signature")

    pubkey = secp256k1.verify_recover(signature, digest)

    if not pubkey:
        raise wire.ProcessError("Invalid signature")

    if script_type == InputScriptType.SPENDADDRESS:
        addr = address_pkh(pubkey, coin)
        if coin.cashaddr_prefix is not None:
            addr = address_to_cashaddr(addr, coin)
    elif script_type == InputScriptType.SPENDP2SHWITNESS:
        addr = address_p2wpkh_in_p2sh(pubkey, coin)
    elif script_type == InputScriptType.SPENDWITNESS:
        addr = address_p2wpkh(pubkey, coin)
    else:
        raise wire.ProcessError("Invalid signature")

    if addr != address:
        raise wire.ProcessError("Invalid signature")

    await confirm_signverify(
        ctx,
        coin.coin_shortcut,
        decode_message(message),
        address=address_short(coin, address),
        verify=True,
    )

    return Success(message="Message verified")
Пример #14
0
async def verify_message(ctx, msg):
    digest = message_digest(msg.message)
    verified = ed25519.verify(msg.public_key, msg.signature, digest)
    if not verified:
        raise wire.ProcessError("Invalid signature")

    address = get_address_from_public_key(msg.public_key)
    await confirm_signverify(ctx,
                             "Lisk",
                             decode_message(msg.message),
                             address=address)

    return Success(message="Message verified")
Пример #15
0
async def set_u2f_counter(ctx: wire.Context, msg: SetU2FCounter) -> Success:
    if not storage.device.is_initialized():
        raise wire.NotInitialized("Device is not initialized")
    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.device.set_u2f_counter(msg.u2f_counter)

    return Success(message="U2F counter set")
Пример #16
0
async def remove_resident_credential(
        ctx: wire.Context, msg: WebAuthnRemoveResidentCredential) -> Success:
    if not storage.device.is_initialized():
        raise wire.NotInitialized("Device is not initialized")
    if msg.index is None:
        raise wire.ProcessError("Missing credential index parameter.")

    cred = get_resident_credential(msg.index)
    if cred is None:
        raise wire.ProcessError("Invalid credential index.")

    if not await confirm_webauthn(ctx, ConfirmRemoveCredential(cred)):
        raise wire.ActionCancelled

    assert cred.index is not None
    storage.resident_credentials.delete(cred.index)
    return Success(message="Credential removed")
async def authorize_coinjoin(ctx: wire.Context, msg: AuthorizeCoinJoin,
                             keychain: Keychain, coin: CoinInfo) -> Success:
    if len(msg.coordinator) > _MAX_COORDINATOR_LEN or not all(
            32 <= ord(x) <= 126 for x in msg.coordinator):
        raise wire.DataError("Invalid coordinator name.")

    if not msg.address_n:
        raise wire.DataError("Empty path not allowed.")

    validation_path = msg.address_n + [0] * BIP32_WALLET_DEPTH
    await validate_path(
        ctx,
        keychain,
        validation_path,
        validate_path_against_script_type(coin,
                                          address_n=validation_path,
                                          script_type=msg.script_type),
    )

    await confirm_action(
        ctx,
        "coinjoin_coordinator",
        title="Authorize CoinJoin",
        description=
        "Do you really want to take part in a CoinJoin transaction at:\n{}",
        description_param=msg.coordinator,
        description_param_font=ui.MONO,
        icon=ui.ICON_RECOVERY,
    )

    if msg.fee_per_anonymity:
        fee_per_anonymity: str | None = format_amount(
            msg.fee_per_anonymity, FEE_PER_ANONYMITY_DECIMALS)
    else:
        fee_per_anonymity = None

    await confirm_coinjoin(
        ctx,
        fee_per_anonymity,
        format_coin_amount(msg.max_total_fee, coin, msg.amount_unit),
    )

    authorization.set(msg)

    return Success(message="CoinJoin authorized")
Пример #18
0
async def reboot_to_bootloader(ctx: wire.Context,
                               msg: RebootToBootloader) -> NoReturn:
    if not storage.device.get_experimental_features():
        raise wire.UnexpectedMessage("Experimental features are not enabled")

    await confirm_action(
        ctx,
        "reboot",
        "Go to bootloader",
        "Do you want to restart Trezor in bootloader mode?",
        hold_danger=True,
        verb="Restart",
    )
    await ctx.write(Success(message="Rebooting"))
    # make sure the outgoing USB buffer is flushed
    await loop.wait(ctx.iface.iface_num() | io.POLL_WRITE)
    utils.reboot_to_bootloader()
    raise RuntimeError
Пример #19
0
async def backup_device(ctx, msg):
    if not storage.device.is_initialized():
        raise wire.NotInitialized("Device is not initialized")
    if not storage.device.needs_backup():
        raise wire.ProcessError("Seed already backed up")

    mnemonic_secret, mnemonic_type = mnemonic.get()

    storage.device.set_unfinished_backup(True)
    storage.device.set_backed_up()

    await backup_seed(ctx, mnemonic_type, mnemonic_secret)

    storage.device.set_unfinished_backup(False)

    await layout.show_backup_success(ctx)

    return Success(message="Seed successfully backed up")
Пример #20
0
async def set_u2f_counter(ctx: wire.Context, msg: SetU2FCounter) -> Success:
    if not storage.device.is_initialized():
        raise wire.NotInitialized("Device is not initialized")
    if msg.u2f_counter is None:
        raise wire.ProcessError("No value provided")

    await confirm_action(
        ctx,
        "set_u2f_counter",
        title="Set U2F counter",
        description="Do you really want to\nset the U2F counter\nto {}?",
        description_param=str(msg.u2f_counter),
        icon=ui.ICON_CONFIG,
        br_code=ButtonRequestType.ProtectCall,
    )

    storage.device.set_u2f_counter(msg.u2f_counter)

    return Success(message="U2F counter set")
Пример #21
0
async def wipe_device(ctx, msg):
    await confirm_action(
        ctx,
        "confirm_wipe",
        title="Wipe device",
        description="Do you really want to\nwipe the device?\n",
        action="All data will be lost.",
        reverse=True,
        verb="Hold to confirm",
        hold=True,
        hold_danger=True,
        icon=ui.ICON_WIPE,
        icon_color=ui.RED,
        br_code=ButtonRequestType.WipeDevice,
    )

    storage.wipe()
    reload_settings_from_storage()

    return Success(message="Device wiped")
Пример #22
0
    async def dispatch_DebugLinkEraseSdCard(
            ctx: wire.Context, msg: DebugLinkEraseSdCard) -> Success:
        from trezor import io

        try:
            io.sdcard.power_on()
            if msg.format:
                io.fatfs.mkfs()
            else:
                # trash first 1 MB of data to destroy the FAT filesystem
                assert io.sdcard.capacity() >= 1024 * 1024
                empty_block = bytes([0xFF] * io.sdcard.BLOCK_SIZE)
                for i in range(1024 * 1024 // io.sdcard.BLOCK_SIZE):
                    io.sdcard.write(i, empty_block)

        except OSError:
            raise wire.ProcessError("SD card operation failed")
        finally:
            io.sdcard.power_off()
        return Success()
Пример #23
0
async def load_device(ctx, msg):
    word_count = _validate(msg)
    is_slip39 = backup_types.is_slip39_word_count(word_count)

    if not is_slip39 and not msg.skip_checksum and not bip39.check(
            msg.mnemonics[0]):
        raise wire.ProcessError("Mnemonic is not valid")

    await _warn(ctx)

    if not is_slip39:  # BIP-39
        secret = msg.mnemonics[0].encode()
        backup_type = BackupType.Bip39
    else:
        identifier, iteration_exponent, secret = slip39.recover_ems(
            msg.mnemonics)

        # this must succeed if the recover_ems call succeeded
        share = slip39.decode_mnemonic(msg.mnemonics[0])
        if share.group_count == 1:
            backup_type = BackupType.Slip39_Basic
        elif share.group_count > 1:
            backup_type = BackupType.Slip39_Advanced
        else:
            raise wire.ProcessError("Invalid group count")

        storage.device.set_slip39_identifier(identifier)
        storage.device.set_slip39_iteration_exponent(iteration_exponent)

    storage.device.store_mnemonic_secret(
        secret,
        backup_type,
        needs_backup=msg.needs_backup is True,
        no_backup=msg.no_backup is True,
    )
    storage.device.set_passphrase_enabled(msg.passphrase_protection)
    storage.device.set_label(msg.label or "")
    if msg.pin:
        config.change_pin("", msg.pin, None, None)

    return Success(message="Device loaded")
Пример #24
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(curpin, salt):
            await error_pin_invalid(ctx)

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

    # write into storage
    if not config.change_pin(curpin, newpin, salt, salt):
        if newpin:
            await error_pin_matches_wipe_code(ctx)
        else:
            await error_pin_invalid(ctx)

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

    await show_success(ctx, "success_pin", msg_screen)
    return Success(message=msg_wire)
Пример #25
0
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, salt):
            await error_pin_invalid(ctx)

        # 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, salt, wipe_code):
        await error_pin_invalid(ctx)

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

    await show_success(ctx, "success_wipe_code", msg_screen)
    return Success(message=msg_wire)
Пример #26
0
async def _finish_recovery(ctx: wire.GenericContext, secret: bytes,
                           backup_type: BackupType) -> Success:
    if backup_type is None:
        raise RuntimeError

    storage.device.store_mnemonic_secret(secret,
                                         backup_type,
                                         needs_backup=False,
                                         no_backup=False)
    if backup_type in (BackupType.Slip39_Basic, BackupType.Slip39_Advanced):
        identifier = storage.recovery.get_slip39_identifier()
        exponent = storage.recovery.get_slip39_iteration_exponent()
        if identifier is None or exponent is None:
            # Identifier and exponent need to be stored in storage at this point
            raise RuntimeError
        storage.device.set_slip39_identifier(identifier)
        storage.device.set_slip39_iteration_exponent(exponent)

    storage.recovery.end_progress()

    await show_success(ctx, "success_recovery",
                       "You have successfully recovered your wallet.")
    return Success(message="Device recovered")
Пример #27
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 = await request_pin(ctx, "Enter PIN", config.get_pin_rem())
    else:
        pin = ""

    # 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 error_pin_invalid(ctx)

    storage.device.set_sd_salt_auth_key(salt_auth_key)

    await show_success(ctx, "success_sd",
                       "You have successfully enabled SD protection.")
    return Success(message="SD card protection enabled")
Пример #28
0
async def handle_EndSession(ctx: wire.Context, msg: EndSession) -> Success:
    storage.cache.end_current_session()
    return Success()
Пример #29
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
    if msg.backup_type == BackupType.Slip39_Basic:
        prompt = "Create a new wallet\nwith Shamir Backup?"
    elif msg.backup_type == BackupType.Slip39_Advanced:
        prompt = "Create a new wallet\nwith Super Shamir?"
    else:
        prompt = "Do you want to create\na new wallet?"
    await confirm_reset_device(ctx, prompt)
    await LoadingAnimation()

    # 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("", newpin, None, None):
            raise wire.ProcessError("Failed to set PIN")

    # generate and display internal entropy
    int_entropy = random.bytes(32)
    if __debug__:
        storage.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 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=bool(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")
Пример #30
0
async def apply_settings(ctx: wire.Context, msg: ApplySettings) -> Success:
    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")