예제 #1
0
async def layout_change_pin(session_id, msg):
    from trezor.messages.Success import Success
    from apps.common.request_pin import protect_by_pin, request_pin_twice
    from apps.common import storage

    if msg.remove:
        if storage.is_protected_by_pin():
            await confirm_remove_pin(session_id)
            await protect_by_pin(session_id, at_least_once=True)
        pin = ''

    else:
        if storage.is_protected_by_pin():
            await confirm_change_pin(session_id)
            await protect_by_pin(session_id, at_least_once=True)
        else:
            await confirm_set_pin(session_id)
        pin = await request_pin_twice(session_id)

    storage.load_settings(pin=pin)
    if pin:
        storage.lock()
        return Success(message='PIN changed')
    else:
        return Success(message='PIN removed')
예제 #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')
예제 #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")
예제 #4
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")
예제 #5
0
async def backup_device(ctx, msg):
    if not storage.is_initialized():
        raise wire.ProcessError("Device is not initialized")
    if not storage.needs_backup():
        raise wire.ProcessError("Seed already backed up")

    mnemonic_secret, mnemonic_type = mnemonic.get()
    slip39 = mnemonic_type == mnemonic.TYPE_SLIP39

    # warn user about mnemonic safety
    await layout.show_backup_warning(ctx, "Back up your seed", "I understand",
                                     slip39)

    storage.set_unfinished_backup(True)
    storage.set_backed_up()

    if slip39:
        await backup_slip39_wallet(ctx, mnemonic_secret)
    else:
        await layout.bip39_show_and_confirm_mnemonic(ctx,
                                                     mnemonic_secret.decode())

    storage.set_unfinished_backup(False)

    return Success(message="Seed successfully backed up")
예제 #6
0
async def apply_settings(ctx, msg):
    if (
        msg.homescreen is None
        and msg.label is None
        and msg.use_passphrase is None
        and msg.passphrase_source is None
    ):
        raise wire.ProcessError("No setting provided")

    if msg.homescreen is not None:
        if len(msg.homescreen) > storage.HOMESCREEN_MAXSIZE:
            raise wire.DataError("Homescreen is too complex")
        await require_confirm_change_homescreen(ctx)

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

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

    if msg.passphrase_source is not None:
        await require_confirm_change_passphrase_source(ctx, msg.passphrase_source)

    storage.load_settings(
        label=msg.label,
        use_passphrase=msg.use_passphrase,
        homescreen=msg.homescreen,
        passphrase_source=msg.passphrase_source,
    )

    return Success(message="Settings applied")
예제 #7
0
async def _finish_recovery_dry_run(
    ctx: wire.Context, secret: bytes, mnemonic_type: int
) -> Success:
    digest_input = sha256(secret).digest()
    stored = mnemonic.get_secret()
    digest_stored = sha256(stored).digest()
    result = utils.consteq(digest_stored, digest_input)

    # Check that the identifier and iteration exponent match as well
    if mnemonic_type == mnemonic.TYPE_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()
        )

    await layout.show_dry_run_result(ctx, result, mnemonic_type)

    storage.recovery.end_progress()

    if result:
        return Success("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")
예제 #8
0
async def layout_load_device(session_id, msg):
    from trezor.crypto import bip39
    from trezor.messages.Success import Success
    from trezor.messages.FailureType import UnexpectedMessage, Other
    from trezor.ui.text import Text
    from ..common.confirm import require_confirm
    from ..common import storage

    if storage.is_initialized():
        raise wire.FailureError(UnexpectedMessage, 'Already initialized')

    if msg.node is not None:
        raise wire.FailureError(Other, 'LoadDevice.node is not supported')

    if not msg.skip_checksum and not bip39.check(msg.mnemonic):
        raise wire.FailureError(Other, 'Mnemonic is not valid')

    await require_confirm(
        session_id,
        Text('Loading seed', ui.ICON_RESET, ui.BOLD, 'Loading private seed',
             'is not recommended.', ui.NORMAL, 'Continue only if you',
             'know what you are doing!'))

    storage.load_mnemonic(msg.mnemonic)
    storage.load_settings(pin=msg.pin,
                          passphrase_protection=msg.passphrase_protection,
                          language=msg.language,
                          label=msg.label)

    return Success(message='Device loaded')
예제 #9
0
async def add_resident_credential(
    ctx: wire.Context, msg: WebAuthnAddResidentCredential
) -> Success:
    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:
        text = Text("Import credential", ui.ICON_WRONG, ui.RED)
        text.normal(
            "The credential you are",
            "trying to import does",
            "not belong to this",
            "authenticator.",
        )
        await require_confirm(ctx, text, confirm=None, cancel="Close")
        raise wire.ActionCancelled("Cancelled") from None

    content = ConfirmContent(ConfirmAddCredential(cred))
    await require_confirm(ctx, content)

    if store_resident_credential(cred):
        return Success(message="Credential added")
    else:
        raise wire.ProcessError("Internal credential storage is full.")
예제 #10
0
async def handle_Ping(ctx: wire.Context, msg: Ping) -> Success:
    if msg.button_protection:
        from trezor.ui.layouts import confirm_action
        from trezor.messages.ButtonRequestType import ProtectCall

        await confirm_action(ctx, "ping", "Confirm", "ping", br_code=ProtectCall)
    return Success(message=msg.message)
예제 #11
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")
예제 #12
0
async def _finish_recovery(
    ctx: wire.Context, secret: bytes, mnemonic_type: int
) -> Success:
    group_count = storage.recovery.get_slip39_group_count()
    if group_count and group_count > 1:
        mnemonic_type = mnemonic.TYPE_SLIP39_GROUP
    storage.device.store_mnemonic_secret(
        secret, mnemonic_type, needs_backup=False, no_backup=False
    )
    if (
        mnemonic_type == mnemonic.TYPE_SLIP39
        or mnemonic_type == mnemonic.TYPE_SLIP39_GROUP
    ):
        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)

    await show_success(ctx, ("You have successfully", "recovered your wallet."))

    storage.recovery.end_progress()
    return Success(message="Device recovered")
예제 #13
0
async def load_device(ctx, msg):

    if storage.is_initialized():
        raise wire.FailureError(UnexpectedMessage, 'Already initialized')

    if msg.node is not None:
        raise wire.FailureError(ProcessError,
                                'LoadDevice.node is not supported')

    if not msg.skip_checksum and not bip39.check(msg.mnemonic):
        raise wire.FailureError(ProcessError, 'Mnemonic is not valid')

    await require_confirm(
        ctx,
        Text('Loading seed', ui.ICON_DEFAULT, ui.BOLD, 'Loading private seed',
             'is not recommended.', ui.NORMAL, 'Continue only if you',
             'know what you are doing!'))

    storage.load_mnemonic(mnemonic=msg.mnemonic, needs_backup=True)
    storage.load_settings(use_passphrase=msg.passphrase_protection,
                          label=msg.label)
    if msg.pin:
        config.change_pin(pin_to_int(''), pin_to_int(msg.pin), None)

    return Success(message='Device loaded')
예제 #14
0
async def _finish_recovery(ctx: wire.Context, secret: bytes,
                           backup_type: EnumTypeBackupType) -> 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)

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

    await show_success(ctx,
                       ("You have successfully", "recovered your wallet."))

    storage.recovery.end_progress()
    return Success(message="Device recovered")
예제 #15
0
async def load_device(ctx, msg):
    # TODO implement SLIP-39
    if storage.is_initialized():
        raise wire.UnexpectedMessage("Already initialized")

    if msg.node is not None:
        raise wire.ProcessError("LoadDevice.node is not supported")

    if not msg.skip_checksum and not bip39.check(msg.mnemonic):
        raise wire.ProcessError("Mnemonic is not valid")

    text = Text("Loading seed")
    text.bold("Loading private seed", "is not recommended.")
    text.normal("Continue only if you", "know what you are doing!")
    await require_confirm(ctx, text)

    secret = bip39.process_all([msg.mnemonic])
    storage.device.store_mnemonic_secret(
        secret=secret,
        mnemonic_type=bip39.get_type(),
        needs_backup=True,
        no_backup=False,
    )
    storage.device.load_settings(use_passphrase=msg.passphrase_protection,
                                 label=msg.label)
    if msg.pin:
        config.change_pin(pin_to_int(""), pin_to_int(msg.pin))

    return Success(message="Device loaded")
예제 #16
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, group_count = slip39.combine_mnemonics(
            msg.mnemonics)
        if group_count == 1:
            backup_type = BackupType.Slip39_Basic
        elif group_count > 1:
            backup_type = BackupType.Slip39_Advanced
        else:
            raise RuntimeError("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=True,
                                         no_backup=False)
    storage.device.load_settings(use_passphrase=msg.passphrase_protection,
                                 label=msg.label)
    if msg.pin:
        config.change_pin(pin_to_int(""), pin_to_int(msg.pin), None, None)

    return Success(message="Device loaded")
예제 #17
0
async def reset_device(ctx, msg):
    if __debug__:
        global internal_entropy

    # validate parameters and device state
    if msg.strength not in (128, 192, 256):
        raise wire.FailureError(
            FailureType.ProcessError,
            'Invalid strength (has to be 128, 192 or 256 bits)')
    if storage.is_initialized():
        raise wire.FailureError(
            FailureType.UnexpectedMessage,
            'Already initialized')

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

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

    # request external entropy and compute mnemonic
    ack = await ctx.call(EntropyRequest(), wire_types.EntropyAck)
    mnemonic = generate_mnemonic(
        msg.strength, internal_entropy, ack.entropy)

    if msg.skip_backup:
        # let user backup the mnemonic later
        pass
    else:
        # warn user about mnemonic safety
        await show_warning(ctx)
        while True:
            # show mnemonic and require confirmation of a random word
            await show_mnemonic(ctx, mnemonic)
            if await check_mnemonic(ctx, mnemonic):
                break
            await show_wrong_entry(ctx)

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

    # write settings and mnemonic into storage
    storage.load_settings(
        label=msg.label, use_passphrase=msg.passphrase_protection)
    storage.load_mnemonic(
        mnemonic=mnemonic, needs_backup=msg.skip_backup)

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

    return Success(message='Initialized')
예제 #18
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,
        )

    content = ConfirmContent(ConfirmAddCredential(cred))
    await require_confirm(ctx, content)

    if store_resident_credential(cred):
        return Success(message="Credential added")
    else:
        raise wire.ProcessError("Internal credential storage is full.")
예제 #19
0
async def handle_ClearSession(ctx: wire.Context, msg: ClearSession) -> Success:
    """
    This is currently a no-op on T. This should be called LockSession/LockDevice
    and lock the device. In other words the cache should stay but the PIN should
    be forgotten and required again.
    """
    return Success()
예제 #20
0
async def layout_verify_message(ctx, msg):
    from trezor.messages.Success import Success
    from trezor.crypto.curve import secp256k1
    from trezor.crypto.hashlib import ripemd160, sha256
    from trezor.crypto import base58
    from ..common import address_type
    from ..common import coins
    from ..common.signverify import message_digest

    coin_name = msg.coin_name or 'Bitcoin'
    coin = coins.by_name(coin_name)

    digest = message_digest(coin, msg.message)
    pubkey = secp256k1.verify_recover(msg.signature, digest)

    if not pubkey:
        raise ValueError('Invalid signature')

    raw_address = base58.decode_check(msg.address)
    at, pkh = address_type.split(coin, raw_address)
    pkh2 = ripemd160(sha256(pubkey).digest()).digest()

    if pkh != pkh2:
        raise ValueError('Invalid signature')

    ui.display.clear()
    ui.display.text(10, 30, 'Verifying message', ui.BOLD, ui.LIGHT_GREEN,
                    ui.BG)
    ui.display.text(10, 60, msg.message, ui.MONO, ui.FG, ui.BG)
    ui.display.text(10, 80, msg.address, ui.MONO, ui.FG, ui.BG)

    return Success(message='Message verified')
예제 #21
0
async def apply_settings(ctx, msg):
    if msg.homescreen is None and msg.label is None and msg.use_passphrase is None:
        raise wire.FailureError(FailureType.ProcessError,
                                'No setting provided')

    if msg.homescreen is not None:
        await require_confirm(ctx,
                              Text('Change homescreen', ui.ICON_CONFIG,
                                   'Do you really want to',
                                   'change homescreen?'),
                              code=ButtonRequestType.ProtectCall)

    # TODO: split label (bold) and '?' (normal) once we support mixed styles on one line
    if msg.label is not None:
        await require_confirm(ctx,
                              Text('Change label', ui.ICON_CONFIG,
                                   'Do you really want to', 'change label to',
                                   ui.BOLD, '%s?' % msg.label),
                              code=ButtonRequestType.ProtectCall)

    if msg.use_passphrase is not None:
        await require_confirm(ctx,
                              Text(
                                  'Enable passphrase' if msg.use_passphrase
                                  else 'Disable passphrase', ui.ICON_CONFIG,
                                  'Do you really want to',
                                  'enable passphrase' if msg.use_passphrase
                                  else 'disable passphrase', 'encryption?'),
                              code=ButtonRequestType.ProtectCall)

    storage.load_settings(label=msg.label,
                          use_passphrase=msg.use_passphrase,
                          homescreen=msg.homescreen)

    return Success(message='Settings applied')
예제 #22
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(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 error_pin_invalid(ctx)

    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")
예제 #23
0
async def ethereum_verify_message(ctx, msg):
    from .sign_message import message_digest
    from trezor.crypto.curve import secp256k1
    from trezor.crypto.hashlib import sha3_256
    from trezor import ui
    from trezor.messages.Success import Success

    digest = message_digest(msg.message)
    sig = bytearray([msg.signature[64]]) + msg.signature[:64]
    pubkey = secp256k1.verify_recover(sig, digest)

    if not pubkey:
        raise ValueError('Invalid signature')

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

    if msg.address != pkh:
        raise ValueError('Invalid signature')

    ui.display.clear()
    ui.display.text(10, 30, 'Verifying message', ui.BOLD, ui.LIGHT_GREEN,
                    ui.BG)
    ui.display.text(10, 60, msg.message, ui.MONO, ui.FG, ui.BG)
    ui.display.text(10, 80, msg.address, ui.MONO, ui.FG, ui.BG)

    return Success(message='Message verified')
예제 #24
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()
예제 #25
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 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, ("You have successfully", "refreshed SD protection."))
    return Success(message="SD card protection refreshed")
예제 #26
0
async def verify_message(ctx, msg):
    digest = message_digest(msg.message)
    if len(msg.signature) != 65:
        raise wire.DataError("Invalid signature")
    sig = bytearray([msg.signature[64]]) + msg.signature[:64]

    try:
        pubkey = secp256k1.verify_recover(sig, digest)
    except ValueError:
        raise wire.DataError("Invalid signature")

    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 require_confirm_verify_message(ctx, address, msg.message)

    return Success(message="Message verified")
예제 #27
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_to_int(pin), pin_to_int(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, ("You have successfully", "disabled SD protection."))
    return Success(message="SD card protection disabled")
예제 #28
0
async def show_text(ctx: wire.Context, msg: DebugLinkShowText) -> Success:
    if msg.header_icon is not None:
        icon_name = "ICON_" + msg.header_icon
        icon = getattr(style, icon_name)
        if not isinstance(icon, str):
            raise wire.DataError("Invalid icon name: {}".format(
                msg.header_icon))
    else:
        icon = style.ICON_DEFAULT

    if msg.icon_color is not None:
        color = getattr(style, msg.icon_color)
        if not isinstance(color, int):
            raise wire.DataError("Invalid color name: {}".format(
                msg.icon_color))
    else:
        color = style.ORANGE_ICON

    dlg = Text(msg.header_text, icon, color, new_lines=False)
    for item in msg.body_text:
        if item.style in STYLES:
            dlg.content.append(STYLES[item.style])
        elif item.style == S.SET_COLOR:
            color = getattr(style, item.content)
            if not isinstance(color, int):
                raise wire.DataError("Invalid color name: {}".format(
                    item.content))
            dlg.content.append(color)

        elif item.content is not None:
            dlg.content.append(item.content)

    await confirm(ctx, dlg)
    return Success("text shown")
예제 #29
0
async def _finish_recovery_dry_run(ctx: wire.GenericContext, secret: bytes,
                                   backup_type: EnumTypeBackupType) -> 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())

    await layout.show_dry_run_result(ctx, result, is_slip39)

    storage_recovery.end_progress()

    if result:
        return Success("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")
예제 #30
0
async def layout_apply_flags(ctx, msg):
    from trezor.messages.Success import Success
    from ..common import storage

    storage.set_flags(msg.flags)

    return Success(message='Flags applied')