async def get_entropy(ctx, msg): text = Text('Confirm entropy') text.bold('Do you really want', 'to send entropy?') text.normal('Continue only if you', 'know what you are doing!') await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) size = min(msg.size, 1024) entropy = random.bytes(size) return Entropy(entropy=entropy)
def test_bytes_uniform(self): for _ in range(100): c = {} for h in '0123456789abcdef': c[h] = 0 for _ in range(8): b = random.bytes(1000) for h in hexlify(b): c[chr(h)] += 1 for h in '0123456789abcdef': self.assertAlmostEqual(c[h], 1000, delta=200)
def start_session(received_session_id: bytes = None) -> bytes: if received_session_id and received_session_id in _session_ids: session_id = received_session_id else: session_id = random.bytes(32) _caches[session_id] = {} global _active_session_id _active_session_id = session_id _move_session_ids_queue(session_id) return _active_session_id
def encrypt(key: bytes, plaintext: bytes, associated_data: bytes | None = None): """ Uses ChaCha20Poly1305 for encryption """ nonce = random.bytes(12) cipher = ChaCha20Poly1305(key, nonce) if associated_data: cipher.auth(associated_data) ciphertext = cipher.encrypt(plaintext) tag = cipher.finish() return nonce, ciphertext + tag, b""
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")
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 storage.is_initialized(): raise wire.UnexpectedMessage('Already initialized') # 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(), wire_types.EntropyAck) mnemonic = generate_mnemonic(msg.strength, internal_ent, ent_ack.entropy) if not msg.skip_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, 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.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 we skipped backup, it's possible that homescreen # is still running, uninterrupted. restart it to pick up new label. if not msg.skip_backup: await show_success(ctx) else: workflow.restartdefault() return Success(message='Initialized')
def __init__(self, creds: misc.AccountCreds): self.state = State.FINISHED self.creds = creds self.inputs_size = 0 self.outputs_size = 0 self.extra_size = 0 self.dst_amounts = {} self.inputs_counter = 0 self.outputs_counter = 0 self.extra_counter = 0 self.random_seed = random.bytes(32) # bcncrypto.cn_fast_hash(b"bcn") # self.tx_inputs_stream = bcncrypto.get_keccak() self.tx_inputs_hash = None self.tx_prefix_stream = bcncrypto.get_keccak() self.inputs_amount = 0 self.dst_amount = 0 self.change_amount = 0 self.c0 = None self.encryption_key = random.bytes(32) # bcncrypto.cn_fast_hash(b"bcn") # self.step_args_hash = None self.change_amount = 0
def _split_secret(threshold, share_count, shared_secret): if threshold < 1: raise ValueError( "The requested threshold ({}) must be a positive integer.".format(threshold) ) if threshold > share_count: raise ValueError( "The requested threshold ({}) must not exceed the number of shares ({}).".format( threshold, share_count ) ) if share_count > MAX_SHARE_COUNT: raise ValueError( "The requested number of shares ({}) must not exceed {}.".format( share_count, MAX_SHARE_COUNT ) ) # If the threshold is 1, then the digest of the shared secret is not used. if threshold == 1: return [(i, shared_secret) for i in range(share_count)] random_share_count = threshold - 2 shares = [(i, random.bytes(len(shared_secret))) for i in range(random_share_count)] random_part = random.bytes(len(shared_secret) - _DIGEST_LENGTH_BYTES) digest = _create_digest(random_part, shared_secret) base_shares = shares + [ (_DIGEST_INDEX, digest + random_part), (_SECRET_INDEX, shared_secret), ] for i in range(random_share_count, share_count): shares.append((i, shamir.interpolate(base_shares, i))) return shares
async def layout_reset_device(session_id, msg): from trezor.ui.text import Text from trezor.crypto import hashlib, random, bip39 from trezor.messages.EntropyRequest import EntropyRequest from trezor.messages.Success import Success from trezor.messages import FailureType from trezor.messages import ButtonRequestType from trezor.messages.wire_types import EntropyAck from apps.common.request_pin import request_pin_twice from apps.common.confirm import require_confirm from apps.common import storage if __debug__: global internal_entropy if msg.strength not in (128, 192, 256): raise wire.FailureError( FailureType.Other, 'Invalid strength (has to be 128, 192 or 256 bits)') if storage.is_initialized(): raise wire.FailureError( FailureType.UnexpectedMessage, 'Already initialized') internal_entropy = random.bytes(32) if msg.display_random: entropy_lines = chunks(ubinascii.hexlify(internal_entropy), 16) entropy_content = Text('Internal entropy', ui.ICON_RESET, *entropy_lines) await require_confirm(session_id, entropy_content, ButtonRequestType.ResetDevice) if msg.pin_protection: pin = await request_pin_twice(session_id) else: pin = None external_entropy_ack = await wire.call(session_id, EntropyRequest(), EntropyAck) ctx = hashlib.sha256() ctx.update(internal_entropy) ctx.update(external_entropy_ack.entropy) entropy = ctx.digest() mnemonic = bip39.from_data(entropy[:msg.strength // 8]) await show_mnemonic_by_word(session_id, mnemonic) storage.load_mnemonic(mnemonic) storage.load_settings(pin=pin, passphrase_protection=msg.passphrase_protection, language=msg.language, label=msg.label) return Success(message='Initialized')
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")
def get_state(prev_state: bytes = None, passphrase: str = None) -> Optional[bytes]: if prev_state is None: salt = random.bytes(32) # generate a random salt if no state provided else: salt = prev_state[:32] # use salt from provided state if len(salt) != 32: return None # invalid state if passphrase is None: if _cached_passphrase is None: return None # we don't have any passphrase to compute the state else: passphrase = _cached_passphrase # use cached passphrase return _compute_state(salt, passphrase)
async def get_entropy(ctx, msg): await require_confirm(ctx, Text('Confirm entropy', ui.ICON_DEFAULT, ui.BOLD, 'Do you really want', 'to send entropy?', ui.NORMAL, 'Continue only if you', 'know what you are doing!'), code=ButtonRequestType.ProtectCall) size = min(msg.size, 1024) entropy = random.bytes(size) return Entropy(entropy=entropy)
async def get_entropy(ctx: Context, msg: GetEntropy) -> Entropy: await confirm_action( ctx, "get_entropy", "Confirm entropy", action="Do you really want\nto send entropy?", description="Continue only if you\nknow what you are doing!", br_code=ButtonRequestType.ProtectCall, ) size = min(msg.size, 1024) entropy = random.bytes(size) return Entropy(entropy=entropy)
def test_lock(self): for _ in range(128): config.init() config.wipe() self.assertEqual(config.unlock(pin_to_int('')), True) appid, key = random_entry() value = random.bytes(16) config.set(appid, key, value) config.init() self.assertEqual(config.get(appid, key), None) with self.assertRaises(RuntimeError): config.set(appid, key, bytes()) config.init() config.wipe()
def get_state(state: bytes = None, passphrase: str = None): if state is None: salt = random.bytes(32) # generate a random salt if no state provided else: salt = state[:32] # use salt from provided state if passphrase is None: global _passphrase if _passphrase is None: return None passphrase = _passphrase # use cached passphrase # state = HMAC(passphrase, salt || device_id) msg = salt + storage.get_device_id().encode() state = hmac.new(passphrase.encode(), msg, hashlib.sha256).digest() return salt + state
def get_state(salt: bytes = None, passphrase: str = None): global _passphrase, _state_salt if salt is None: # generate a random salt if not provided and not already cached if _state_salt is None: _state_salt = random.bytes(32) else: # otherwise copy provided salt to cached salt _state_salt = salt # state = HMAC(passphrase, salt || device_id) if passphrase is None: key = _passphrase if _passphrase is not None else '' else: key = passphrase msg = _state_salt + storage.get_device_id().encode() state = hmac.new(key.encode(), msg, hashlib.sha256).digest() return _state_salt + state
def generate_mnemonics_random( group_threshold, groups, strength_bits=128, passphrase=b"", iteration_exponent=0 ): """ Generates a random master secret and splits it into mnemonic shares using Shamir's secret sharing scheme. :param int group_threshold: The number of groups required to reconstruct the master secret. :param groups: A list of (member_threshold, member_count) pairs for each group, where member_count is the number of shares to generate for the group and member_threshold is the number of members required to reconstruct the group secret. :type groups: List of pairs of integers. :param int strength_bits: The entropy of the randomly generated master secret in bits. :param passphrase: The passphrase used to encrypt the master secret. :type passphrase: Array of bytes. :param int iteration_exponent: The iteration exponent. :return: List of mnemonics. :rtype: List of byte arrays. """ if strength_bits < MIN_STRENGTH_BITS: raise ValueError( "The requested strength of the master secret ({} bits) must be at least {} bits.".format( strength_bits, MIN_STRENGTH_BITS ) ) if strength_bits % 16 != 0: raise ValueError( "The requested strength of the master secret ({} bits) must be a multiple of 16 bits.".format( strength_bits ) ) return generate_mnemonics( group_threshold, groups, random.bytes(strength_bits // 8), passphrase, iteration_exponent, )
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) beam_nonce_seed = random.bytes(32) create_beam_master_nonce(beam_nonce_seed) return Success(message="Device loaded")
def generate_id(self) -> None: self._creation_time = storage.device.next_u2f_counter() or 0 data = cbor.encode({ key: value for key, value in ( (_CRED_ID_RP_ID, self.rp_id), (_CRED_ID_RP_NAME, self.rp_name), (_CRED_ID_USER_ID, self.user_id), (_CRED_ID_USER_NAME, self.user_name), (_CRED_ID_USER_DISPLAY_NAME, self.user_display_name), (_CRED_ID_CREATION_TIME, self._creation_time), (_CRED_ID_HMAC_SECRET, self.hmac_secret), ) if value }) key = seed.derive_slip21_node_without_passphrase( [b"SLIP-0022", _CRED_ID_VERSION, b"Encryption key"]).key() iv = random.bytes(12) ctx = chacha20poly1305(key, iv) ctx.auth(self.rp_id_hash) ciphertext = ctx.encrypt(data) tag = ctx.finish() self.id = _CRED_ID_VERSION + iv + ciphertext + tag
def generate_id(self) -> None: self.creation_time = storage.device.next_u2f_counter() or 0 if not self.check_required_fields(): raise AssertionError data = { key: value for key, value in ( (_CRED_ID_RP_ID, self.rp_id), (_CRED_ID_RP_NAME, self.rp_name), (_CRED_ID_USER_ID, self.user_id), (_CRED_ID_USER_NAME, self.user_name), (_CRED_ID_USER_DISPLAY_NAME, self.user_display_name), (_CRED_ID_CREATION_TIME, self.creation_time), (_CRED_ID_HMAC_SECRET, self.hmac_secret), (_CRED_ID_USE_SIGN_COUNT, self.use_sign_count), ) if value } if self.algorithm != _DEFAULT_ALGORITHM or self.curve != _DEFAULT_CURVE: data[_CRED_ID_ALGORITHM] = self.algorithm data[_CRED_ID_CURVE] = self.curve key = seed.derive_slip21_node_without_passphrase( [b"SLIP-0022", _CRED_ID_VERSION, b"Encryption key"] ).key() iv = random.bytes(12) ctx = chacha20poly1305(key, iv) ctx.auth(self.rp_id_hash) ciphertext = ctx.encrypt(cbor.encode(data)) tag = ctx.finish() self.id = _CRED_ID_VERSION + iv + ciphertext + tag if len(self.id) > CRED_ID_MAX_LENGTH: raise AssertionError
def _encrypt(node, public_key: bytes, payload: bytes) -> bytes: salt = random.bytes(NEM_SALT_SIZE) iv = random.bytes(AES_BLOCK_SIZE) encrypted = node.nem_encrypt(public_key, iv, salt, payload) return iv + salt + encrypted
def generate_random_identifier() -> int: """Returns a randomly generated integer in the range 0, ... , 2**_ID_LENGTH_BITS - 1.""" identifier = int.from_bytes(random.bytes(_bits_to_bytes(_ID_LENGTH_BITS)), "big") return identifier & ((1 << _ID_LENGTH_BITS) - 1)
def _make_salt() -> Tuple[bytes, bytes, bytes]: salt = random.bytes(storage.sd_salt.SD_SALT_LEN_BYTES) auth_key = random.bytes(storage.device.SD_SALT_AUTH_KEY_LEN_BYTES) tag = storage.sd_salt.compute_auth_tag(salt, auth_key) return salt, auth_key, tag
async def get_nonce(ctx: wire.Context, msg: GetNonce) -> Nonce: nonce = random.bytes(32) cache.set(cache.APP_COMMON_NONCE, nonce) return Nonce(nonce=nonce)
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__: 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=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")
def _new_device_id() -> str: return hexlify(random.bytes(12)).decode().upper()
def _protect_signature(state: State, mg_buffer: list[bytes]) -> list[bytes]: """ Encrypts the signature with keys derived from state.opening_key. After protocol finishes without error, opening_key is sent to the host. """ from trezor.crypto import random from trezor.crypto import chacha20poly1305 from apps.monero.signing import offloading_keys if state.last_step != state.STEP_SIGN: state.opening_key = random.bytes(32) nonce = offloading_keys.key_signature(state.opening_key, state.current_input_index, True)[:12] key = offloading_keys.key_signature(state.opening_key, state.current_input_index, False) cipher = chacha20poly1305(key, nonce) # cipher.update() input has to be 512 bit long (besides the last block). # Thus we go over mg_buffer and buffer 512 bit input blocks before # calling cipher.update(). CHACHA_BLOCK = 64 # 512 bit chacha key-stream block size buff = bytearray(CHACHA_BLOCK) buff_len = 0 # valid bytes in the block buffer mg_len = 0 for data in mg_buffer: mg_len += len(data) # Preallocate array of ciphertext blocks, ceil, add tag block mg_res = [None] * (1 + (mg_len + CHACHA_BLOCK - 1) // CHACHA_BLOCK) mg_res_c = 0 for ix, data in enumerate(mg_buffer): data_ln = len(data) data_off = 0 while data_ln > 0: to_add = min(CHACHA_BLOCK - buff_len, data_ln) if to_add: buff[buff_len:buff_len + to_add] = data[data_off:data_off + to_add] data_ln -= to_add buff_len += to_add data_off += to_add if len(buff) != CHACHA_BLOCK or buff_len > CHACHA_BLOCK: raise ValueError("Invariant error") if buff_len == CHACHA_BLOCK: mg_res[mg_res_c] = cipher.encrypt(buff) mg_res_c += 1 buff_len = 0 mg_buffer[ix] = None if ix & 7 == 0: gc.collect() # The last block can be incomplete if buff_len: mg_res[mg_res_c] = cipher.encrypt(buff[:buff_len]) mg_res_c += 1 mg_res[mg_res_c] = cipher.finish() return mg_res
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) else: # trigger reload of homescreen workflow.restartdefault() return Success(message='Initialized')
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) text.normal("Do you really want to", "create a new wallet?", "") 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) mnemonic = 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_warning(ctx) # show mnemonic and require confirmation of a random word while True: 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.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, 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")
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 # For SLIP-39 this is the Encrypted Master Secret secret = _compute_secret_from_entropy(int_entropy, ext_entropy, msg.strength) if is_slip39_simple: storage.device.set_slip39_identifier( slip39.generate_random_identifier()) storage.device.set_slip39_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: storage.device.store_mnemonic_secret( secret, # this is the EMS in SLIP-39 terminology mnemonic.TYPE_SLIP39, needs_backup=msg.skip_backup, no_backup=msg.no_backup, ) else: # in BIP-39 we store mnemonic string instead of the secret storage.device.store_mnemonic_secret( bip39.from_data(secret).encode(), mnemonic.TYPE_BIP39, 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")