feat(core): Support 50 digit PIN and wipe code.

pull/1546/head
Andrew Kozlik 4 years ago committed by Andrew Kozlik
parent c68e91c12a
commit 3084d1196d

@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Allow decreasing the output value in RBF transactions. [#1491] - Allow decreasing the output value in RBF transactions. [#1491]
- Cardano: Allow stake pool registrations with zero margin. [#1502] - Cardano: Allow stake pool registrations with zero margin. [#1502]
- Cardano: Assets are now shown as CIP-0014. [#1510] - Cardano: Assets are now shown as CIP-0014. [#1510]
- Support PIN of unlimited length. [#1167]
### Deprecated ### Deprecated
@ -358,6 +359,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#1139]: https://github.com/trezor/trezor-firmware/issues/1139 [#1139]: https://github.com/trezor/trezor-firmware/issues/1139
[#1159]: https://github.com/trezor/trezor-firmware/issues/1159 [#1159]: https://github.com/trezor/trezor-firmware/issues/1159
[#1165]: https://github.com/trezor/trezor-firmware/pull/1165 [#1165]: https://github.com/trezor/trezor-firmware/pull/1165
[#1167]: https://github.com/trezor/trezor-firmware/issues/1167
[#1173]: https://github.com/trezor/trezor-firmware/pull/1173 [#1173]: https://github.com/trezor/trezor-firmware/pull/1173
[#1184]: https://github.com/trezor/trezor-firmware/issues/1184 [#1184]: https://github.com/trezor/trezor-firmware/issues/1184
[#1188]: https://github.com/trezor/trezor-firmware/issues/1188 [#1188]: https://github.com/trezor/trezor-firmware/issues/1188

@ -66,13 +66,15 @@ STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_init_obj, 0, 1, STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_init_obj, 0, 1,
mod_trezorconfig_init); mod_trezorconfig_init);
/// def unlock(pin: int, ext_salt: Optional[bytes]) -> bool: /// def unlock(pin: str, ext_salt: Optional[bytes]) -> bool:
/// """ /// """
/// Attempts to unlock the storage with the given PIN and external salt. /// Attempts to unlock the storage with the given PIN and external salt.
/// Returns True on success, False on failure. /// Returns True on success, False on failure.
/// """ /// """
STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin, mp_obj_t ext_salt) { STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin, mp_obj_t ext_salt) {
uint32_t pin_i = trezor_obj_get_uint(pin); mp_buffer_info_t pin_b = {0};
mp_get_buffer_raise(pin, &pin_b, MP_BUFFER_READ);
mp_buffer_info_t ext_salt_b = {0}; mp_buffer_info_t ext_salt_b = {0};
ext_salt_b.buf = NULL; ext_salt_b.buf = NULL;
if (ext_salt != mp_const_none) { if (ext_salt != mp_const_none) {
@ -81,7 +83,7 @@ STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin, mp_obj_t ext_salt) {
mp_raise_msg(&mp_type_ValueError, "Invalid length of external salt."); mp_raise_msg(&mp_type_ValueError, "Invalid length of external salt.");
} }
if (sectrue != storage_unlock(pin_i, ext_salt_b.buf)) { if (sectrue != storage_unlock(pin_b.buf, pin_b.len, ext_salt_b.buf)) {
return mp_const_false; return mp_const_false;
} }
return mp_const_true; return mp_const_true;
@ -89,7 +91,7 @@ STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin, mp_obj_t ext_salt) {
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorconfig_unlock_obj, STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorconfig_unlock_obj,
mod_trezorconfig_unlock); mod_trezorconfig_unlock);
/// def check_pin(pin: int, ext_salt: Optional[bytes]) -> bool: /// def check_pin(pin: str, ext_salt: Optional[bytes]) -> bool:
/// """ /// """
/// Check the given PIN with the given external salt. /// Check the given PIN with the given external salt.
/// Returns True on success, False on failure. /// Returns True on success, False on failure.
@ -148,8 +150,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_get_pin_rem_obj,
mod_trezorconfig_get_pin_rem); mod_trezorconfig_get_pin_rem);
/// def change_pin( /// def change_pin(
/// oldpin: int, /// oldpin: str,
/// newpin: int, /// newpin: str,
/// old_ext_salt: Optional[bytes], /// old_ext_salt: Optional[bytes],
/// new_ext_salt: Optional[bytes], /// new_ext_salt: Optional[bytes],
/// ) -> bool: /// ) -> bool:
@ -158,8 +160,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_get_pin_rem_obj,
/// """ /// """
STATIC mp_obj_t mod_trezorconfig_change_pin(size_t n_args, STATIC mp_obj_t mod_trezorconfig_change_pin(size_t n_args,
const mp_obj_t *args) { const mp_obj_t *args) {
uint32_t oldpin = trezor_obj_get_uint(args[0]); mp_buffer_info_t oldpin = {0};
uint32_t newpin = trezor_obj_get_uint(args[1]); mp_get_buffer_raise(args[0], &oldpin, MP_BUFFER_READ);
mp_buffer_info_t newpin = {0};
mp_get_buffer_raise(args[1], &newpin, MP_BUFFER_READ);
mp_buffer_info_t ext_salt_b = {0}; mp_buffer_info_t ext_salt_b = {0};
const uint8_t *old_ext_salt = NULL; const uint8_t *old_ext_salt = NULL;
if (args[2] != mp_const_none) { if (args[2] != mp_const_none) {
@ -176,8 +182,8 @@ STATIC mp_obj_t mod_trezorconfig_change_pin(size_t n_args,
new_ext_salt = ext_salt_b.buf; new_ext_salt = ext_salt_b.buf;
} }
if (sectrue != if (sectrue != storage_change_pin(oldpin.buf, oldpin.len, newpin.buf,
storage_change_pin(oldpin, newpin, old_ext_salt, new_ext_salt)) { newpin.len, old_ext_salt, new_ext_salt)) {
return mp_const_false; return mp_const_false;
} }
return mp_const_true; return mp_const_true;
@ -185,13 +191,14 @@ STATIC mp_obj_t mod_trezorconfig_change_pin(size_t n_args,
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_change_pin_obj, 4, STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_change_pin_obj, 4,
4, mod_trezorconfig_change_pin); 4, mod_trezorconfig_change_pin);
/// def ensure_not_wipe_code(pin: int) -> None: /// def ensure_not_wipe_code(pin: str) -> None:
/// """ /// """
/// Wipes the device if the entered PIN is the wipe code. /// Wipes the device if the entered PIN is the wipe code.
/// """ /// """
STATIC mp_obj_t mod_trezorconfig_ensure_not_wipe_code(mp_obj_t pin) { STATIC mp_obj_t mod_trezorconfig_ensure_not_wipe_code(mp_obj_t pin) {
uint32_t pin_i = trezor_obj_get_uint(pin); mp_buffer_info_t pin_b = {0};
storage_ensure_not_wipe_code(pin_i); mp_get_buffer_raise(pin, &pin_b, MP_BUFFER_READ);
storage_ensure_not_wipe_code(pin_b.buf, pin_b.len);
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_ensure_not_wipe_code_obj, STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_ensure_not_wipe_code_obj,
@ -211,17 +218,21 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_has_wipe_code_obj,
mod_trezorconfig_has_wipe_code); mod_trezorconfig_has_wipe_code);
/// def change_wipe_code( /// def change_wipe_code(
/// pin: int, /// pin: str,
/// ext_salt: Optional[bytes], /// ext_salt: Optional[bytes],
/// wipe_code: int, /// wipe_code: str,
/// ) -> bool: /// ) -> bool:
/// """ /// """
/// Change wipe code. Returns True on success, False on failure. /// Change wipe code. Returns True on success, False on failure.
/// """ /// """
STATIC mp_obj_t mod_trezorconfig_change_wipe_code(size_t n_args, STATIC mp_obj_t mod_trezorconfig_change_wipe_code(size_t n_args,
const mp_obj_t *args) { const mp_obj_t *args) {
uint32_t pin = trezor_obj_get_uint(args[0]); mp_buffer_info_t pin_b = {0};
uint32_t wipe_code = trezor_obj_get_uint(args[2]); mp_get_buffer_raise(args[0], &pin_b, MP_BUFFER_READ);
mp_buffer_info_t wipe_code_b = {0};
mp_get_buffer_raise(args[2], &wipe_code_b, MP_BUFFER_READ);
mp_buffer_info_t ext_salt_b = {0}; mp_buffer_info_t ext_salt_b = {0};
const uint8_t *ext_salt = NULL; const uint8_t *ext_salt = NULL;
if (args[1] != mp_const_none) { if (args[1] != mp_const_none) {
@ -231,7 +242,8 @@ STATIC mp_obj_t mod_trezorconfig_change_wipe_code(size_t n_args,
ext_salt = ext_salt_b.buf; ext_salt = ext_salt_b.buf;
} }
if (sectrue != storage_change_wipe_code(pin, ext_salt, wipe_code)) { if (sectrue != storage_change_wipe_code(pin_b.buf, pin_b.len, ext_salt,
wipe_code_b.buf, wipe_code_b.len)) {
return mp_const_false; return mp_const_false;
} }
return mp_const_true; return mp_const_true;

@ -39,6 +39,6 @@
/* /*
* Current storage version. * Current storage version.
*/ */
#define NORCOW_VERSION ((uint32_t)0x00000002) #define NORCOW_VERSION ((uint32_t)0x00000003)
#endif #endif

@ -12,7 +12,7 @@ def init(
# extmod/modtrezorconfig/modtrezorconfig.c # extmod/modtrezorconfig/modtrezorconfig.c
def unlock(pin: int, ext_salt: Optional[bytes]) -> bool: def unlock(pin: str, ext_salt: Optional[bytes]) -> bool:
""" """
Attempts to unlock the storage with the given PIN and external salt. Attempts to unlock the storage with the given PIN and external salt.
Returns True on success, False on failure. Returns True on success, False on failure.
@ -20,7 +20,7 @@ def unlock(pin: int, ext_salt: Optional[bytes]) -> bool:
# extmod/modtrezorconfig/modtrezorconfig.c # extmod/modtrezorconfig/modtrezorconfig.c
def check_pin(pin: int, ext_salt: Optional[bytes]) -> bool: def check_pin(pin: str, ext_salt: Optional[bytes]) -> bool:
""" """
Check the given PIN with the given external salt. Check the given PIN with the given external salt.
Returns True on success, False on failure. Returns True on success, False on failure.
@ -57,8 +57,8 @@ def get_pin_rem() -> int:
# extmod/modtrezorconfig/modtrezorconfig.c # extmod/modtrezorconfig/modtrezorconfig.c
def change_pin( def change_pin(
oldpin: int, oldpin: str,
newpin: int, newpin: str,
old_ext_salt: Optional[bytes], old_ext_salt: Optional[bytes],
new_ext_salt: Optional[bytes], new_ext_salt: Optional[bytes],
) -> bool: ) -> bool:
@ -68,7 +68,7 @@ def change_pin(
# extmod/modtrezorconfig/modtrezorconfig.c # extmod/modtrezorconfig/modtrezorconfig.c
def ensure_not_wipe_code(pin: int) -> None: def ensure_not_wipe_code(pin: str) -> None:
""" """
Wipes the device if the entered PIN is the wipe code. Wipes the device if the entered PIN is the wipe code.
""" """
@ -83,9 +83,9 @@ def has_wipe_code() -> bool:
# extmod/modtrezorconfig/modtrezorconfig.c # extmod/modtrezorconfig/modtrezorconfig.c
def change_wipe_code( def change_wipe_code(
pin: int, pin: str,
ext_salt: Optional[bytes], ext_salt: Optional[bytes],
wipe_code: int, wipe_code: str,
) -> bool: ) -> bool:
""" """
Change wipe code. Returns True on success, False on failure. Change wipe code. Returns True on success, False on failure.

@ -3,7 +3,6 @@ import utime
import storage.sd_salt import storage.sd_salt
from trezor import config, ui, wire from trezor import config, ui, wire
from trezor.messages import ButtonRequestType from trezor.messages import ButtonRequestType
from trezor.pin import pin_to_int
from trezor.ui.components.tt.pin import CANCELLED, PinDialog from trezor.ui.components.tt.pin import CANCELLED, PinDialog
from trezor.ui.components.tt.text import Text from trezor.ui.components.tt.text import Text
from trezor.ui.popup import Popup from trezor.ui.popup import Popup
@ -71,7 +70,7 @@ async def request_pin_and_sd_salt(
) -> Tuple[str, Optional[bytearray]]: ) -> Tuple[str, Optional[bytearray]]:
if config.has_pin(): if config.has_pin():
pin = await request_pin(ctx, prompt, config.get_pin_rem(), allow_cancel) pin = await request_pin(ctx, prompt, config.get_pin_rem(), allow_cancel)
config.ensure_not_wipe_code(pin_to_int(pin)) config.ensure_not_wipe_code(pin)
else: else:
pin = "" pin = ""
@ -98,7 +97,7 @@ async def verify_user_pin(
if config.has_pin(): if config.has_pin():
pin = await request_pin(ctx, prompt, config.get_pin_rem(), allow_cancel) pin = await request_pin(ctx, prompt, config.get_pin_rem(), allow_cancel)
config.ensure_not_wipe_code(pin_to_int(pin)) config.ensure_not_wipe_code(pin)
else: else:
pin = "" pin = ""
@ -106,7 +105,7 @@ async def verify_user_pin(
salt = await request_sd_salt(ctx) salt = await request_sd_salt(ctx)
except SdCardUnavailable: except SdCardUnavailable:
raise wire.PinCancelled("SD salt is unavailable") raise wire.PinCancelled("SD salt is unavailable")
if config.unlock(pin_to_int(pin), salt): if config.unlock(pin, salt):
_last_successful_unlock = utime.ticks_ms() _last_successful_unlock = utime.ticks_ms()
return return
elif not config.has_pin(): elif not config.has_pin():
@ -116,7 +115,7 @@ async def verify_user_pin(
pin = await request_pin( pin = await request_pin(
ctx, "Wrong PIN, enter again", config.get_pin_rem(), allow_cancel ctx, "Wrong PIN, enter again", config.get_pin_rem(), allow_cancel
) )
if config.unlock(pin_to_int(pin), salt): if config.unlock(pin, salt):
_last_successful_unlock = utime.ticks_ms() _last_successful_unlock = utime.ticks_ms()
return return

@ -4,7 +4,6 @@ from trezor import config, wire
from trezor.crypto import bip39, slip39 from trezor.crypto import bip39, slip39
from trezor.messages import BackupType from trezor.messages import BackupType
from trezor.messages.Success import Success from trezor.messages.Success import Success
from trezor.pin import pin_to_int
from trezor.ui.layouts import confirm_action, require from trezor.ui.layouts import confirm_action, require
from apps.management import backup_types from apps.management import backup_types
@ -46,7 +45,7 @@ async def load_device(ctx, msg):
storage.device.set_passphrase_enabled(msg.passphrase_protection) storage.device.set_passphrase_enabled(msg.passphrase_protection)
storage.device.set_label(msg.label or "") storage.device.set_label(msg.label or "")
if msg.pin: if msg.pin:
config.change_pin(pin_to_int(""), pin_to_int(msg.pin), None, None) config.change_pin("", msg.pin, None, None)
return Success(message="Device loaded") return Success(message="Device loaded")

@ -1,7 +1,6 @@
from storage.device import is_initialized from storage.device import is_initialized
from trezor import config, ui, wire from trezor import config, ui, wire
from trezor.messages.Success import Success from trezor.messages.Success import Success
from trezor.pin import pin_to_int
from trezor.ui.components.tt.text import Text from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import require, show_success from trezor.ui.layouts import require, show_success
@ -29,7 +28,7 @@ async def change_pin(ctx: wire.Context, msg: ChangePin) -> Success:
# if changing pin, pre-check the entered pin before getting new pin # if changing pin, pre-check the entered pin before getting new pin
if curpin and not msg.remove: if curpin and not msg.remove:
if not config.check_pin(pin_to_int(curpin), salt): if not config.check_pin(curpin, salt):
await error_pin_invalid(ctx) await error_pin_invalid(ctx)
# get new pin # get new pin
@ -39,7 +38,7 @@ async def change_pin(ctx: wire.Context, msg: ChangePin) -> Success:
newpin = "" newpin = ""
# write into storage # write into storage
if not config.change_pin(pin_to_int(curpin), pin_to_int(newpin), salt, salt): if not config.change_pin(curpin, newpin, salt, salt):
if newpin: if newpin:
await error_pin_matches_wipe_code(ctx) await error_pin_matches_wipe_code(ctx)
else: else:

@ -1,7 +1,6 @@
from storage.device import is_initialized from storage.device import is_initialized
from trezor import config, ui, wire from trezor import config, ui, wire
from trezor.messages.Success import Success from trezor.messages.Success import Success
from trezor.pin import pin_to_int
from trezor.ui.components.tt.text import Text from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import require, show_success from trezor.ui.layouts import require, show_success
from trezor.ui.popup import Popup from trezor.ui.popup import Popup
@ -30,7 +29,7 @@ async def change_wipe_code(ctx: wire.Context, msg: ChangeWipeCode) -> Success:
if not msg.remove: if not msg.remove:
# Pre-check the entered PIN. # Pre-check the entered PIN.
if config.has_pin() and not config.check_pin(pin_to_int(pin), salt): if config.has_pin() and not config.check_pin(pin, salt):
await error_pin_invalid(ctx) await error_pin_invalid(ctx)
# Get new wipe code. # Get new wipe code.
@ -39,7 +38,7 @@ async def change_wipe_code(ctx: wire.Context, msg: ChangeWipeCode) -> Success:
wipe_code = "" wipe_code = ""
# Write into storage. # Write into storage.
if not config.change_wipe_code(pin_to_int(pin), salt, pin_to_int(wipe_code)): if not config.change_wipe_code(pin, salt, wipe_code):
await error_pin_invalid(ctx) await error_pin_invalid(ctx)
if wipe_code: if wipe_code:

@ -4,7 +4,6 @@ import storage.recovery
from trezor import config, ui, wire, workflow from trezor import config, ui, wire, workflow
from trezor.messages import ButtonRequestType from trezor.messages import ButtonRequestType
from trezor.messages.Success import Success from trezor.messages.Success import Success
from trezor.pin import pin_to_int
from trezor.ui.components.tt.text import Text from trezor.ui.components.tt.text import Text
from apps.common.confirm import require_confirm from apps.common.confirm import require_confirm
@ -47,14 +46,14 @@ async def recovery_device(ctx: wire.Context, msg: RecoveryDevice) -> Success:
# for dry run pin needs to be entered # for dry run pin needs to be entered
if msg.dry_run: if msg.dry_run:
curpin, salt = await request_pin_and_sd_salt(ctx, "Enter PIN") curpin, salt = await request_pin_and_sd_salt(ctx, "Enter PIN")
if not config.check_pin(pin_to_int(curpin), salt): if not config.check_pin(curpin, salt):
await error_pin_invalid(ctx) await error_pin_invalid(ctx)
if not msg.dry_run: if not msg.dry_run:
# set up pin if requested # set up pin if requested
if msg.pin_protection: if msg.pin_protection:
newpin = await request_pin_confirm(ctx, allow_cancel=False) newpin = await request_pin_confirm(ctx, allow_cancel=False)
config.change_pin(pin_to_int(""), pin_to_int(newpin), None, None) config.change_pin("", newpin, None, None)
storage.device.set_passphrase_enabled(bool(msg.passphrase_protection)) storage.device.set_passphrase_enabled(bool(msg.passphrase_protection))
if msg.u2f_counter is not None: if msg.u2f_counter is not None:

@ -6,7 +6,6 @@ from trezor.messages import BackupType
from trezor.messages.EntropyAck import EntropyAck from trezor.messages.EntropyAck import EntropyAck
from trezor.messages.EntropyRequest import EntropyRequest from trezor.messages.EntropyRequest import EntropyRequest
from trezor.messages.Success import Success from trezor.messages.Success import Success
from trezor.pin import pin_to_int
from trezor.ui.layouts import confirm_backup, confirm_reset_device, require from trezor.ui.layouts import confirm_backup, confirm_reset_device, require
from trezor.ui.loader import LoadingAnimation from trezor.ui.loader import LoadingAnimation
@ -43,7 +42,7 @@ async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success:
# request and set new PIN # request and set new PIN
if msg.pin_protection: if msg.pin_protection:
newpin = await request_pin_confirm(ctx) newpin = await request_pin_confirm(ctx)
if not config.change_pin(pin_to_int(""), pin_to_int(newpin), None, None): if not config.change_pin("", newpin, None, None):
raise wire.ProcessError("Failed to set PIN") raise wire.ProcessError("Failed to set PIN")
# generate and display internal entropy # generate and display internal entropy

@ -4,7 +4,6 @@ from trezor import config, ui, wire
from trezor.crypto import random from trezor.crypto import random
from trezor.messages import SdProtectOperationType from trezor.messages import SdProtectOperationType
from trezor.messages.Success import Success from trezor.messages.Success import Success
from trezor.pin import pin_to_int
from trezor.ui.components.tt.text import Text from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import require, show_success from trezor.ui.layouts import require, show_success
@ -66,9 +65,9 @@ async def sd_protect_enable(ctx: wire.Context, msg: SdProtect) -> Success:
# Get the current PIN. # Get the current PIN.
if config.has_pin(): if config.has_pin():
pin = pin_to_int(await request_pin(ctx, "Enter PIN", config.get_pin_rem())) pin = await request_pin(ctx, "Enter PIN", config.get_pin_rem())
else: else:
pin = pin_to_int("") pin = ""
# Check PIN and prepare salt file. # Check PIN and prepare salt file.
salt, salt_auth_key, salt_tag = _make_salt() salt, salt_auth_key, salt_tag = _make_salt()
@ -107,7 +106,7 @@ async def sd_protect_disable(ctx: wire.Context, msg: SdProtect) -> Success:
pin, salt = await request_pin_and_sd_salt(ctx, "Enter PIN") pin, salt = await request_pin_and_sd_salt(ctx, "Enter PIN")
# Check PIN and remove salt. # Check PIN and remove salt.
if not config.change_pin(pin_to_int(pin), pin_to_int(pin), salt, None): if not config.change_pin(pin, pin, salt, None):
await error_pin_invalid(ctx) await error_pin_invalid(ctx)
storage.device.set_sd_salt_auth_key(None) storage.device.set_sd_salt_auth_key(None)
@ -144,7 +143,7 @@ async def sd_protect_refresh(ctx: wire.Context, msg: SdProtect) -> Success:
new_salt, new_auth_key, new_salt_tag = _make_salt() new_salt, new_auth_key, new_salt_tag = _make_salt()
await _set_salt(ctx, new_salt, new_salt_tag, stage=True) 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): if not config.change_pin(pin, pin, old_salt, new_salt):
await error_pin_invalid(ctx) await error_pin_invalid(ctx)
storage.device.set_sd_salt_auth_key(new_auth_key) storage.device.set_sd_salt_auth_key(new_auth_key)

@ -4,10 +4,6 @@ if False:
from typing import Any, Optional from typing import Any, Optional
def pin_to_int(pin: str) -> int:
return int("1" + pin)
_previous_progress: Optional[int] = None _previous_progress: Optional[int] = None
_previous_seconds: Optional[int] = None _previous_seconds: Optional[int] = None
keepalive_callback: Any = None keepalive_callback: Any = None

@ -41,16 +41,40 @@ class PinInput(ui.Component):
self.repaint = False self.repaint = False
def render_pin(self) -> None: def render_pin(self) -> None:
display.bar(0, 0, ui.WIDTH, 50, ui.BG) MAX_LENGTH = const(14) # maximum length of displayed PIN
count = len(self.pin) CONTD_MARK = "<"
BOX_WIDTH = const(240) BOX_WIDTH = const(240)
DOT_SIZE = const(10) DOT_SIZE = const(10)
PADDING = const(14) PADDING = const(4)
RENDER_Y = const(20) RENDER_Y = const(20)
render_x = (BOX_WIDTH - count * PADDING) // 2 TWITCH = const(3)
display.bar(0, 0, ui.WIDTH, 50, ui.BG)
if len(self.pin) > MAX_LENGTH:
contd_width = display.text_width(CONTD_MARK, ui.BOLD) + PADDING
twitch = TWITCH * (len(self.pin) % 2)
else:
contd_width = 0
twitch = 0
count = min(len(self.pin), MAX_LENGTH)
render_x = (BOX_WIDTH - count * (DOT_SIZE + PADDING) - contd_width) // 2
if contd_width:
display.text(
render_x, RENDER_Y + DOT_SIZE, CONTD_MARK, ui.BOLD, ui.GREY, ui.BG
)
for i in range(0, count): for i in range(0, count):
display.bar_radius( display.bar_radius(
render_x + i * PADDING, RENDER_Y, DOT_SIZE, DOT_SIZE, ui.GREY, ui.BG, 4 render_x + contd_width + twitch + i * (DOT_SIZE + PADDING),
RENDER_Y,
DOT_SIZE,
DOT_SIZE,
ui.GREY,
ui.BG,
4,
) )
def render_prompt(self) -> None: def render_prompt(self) -> None:
@ -82,7 +106,7 @@ class PinDialog(ui.Layout):
prompt: str, prompt: str,
subprompt: Optional[str], subprompt: Optional[str],
allow_cancel: bool = True, allow_cancel: bool = True,
maxlength: int = 9, maxlength: int = 50,
) -> None: ) -> None:
self.maxlength = maxlength self.maxlength = maxlength
self.input = PinInput(prompt, subprompt, "") self.input = PinInput(prompt, subprompt, "")

@ -1,5 +1,4 @@
from common import * from common import *
from trezor.pin import pin_to_int
from trezor import config from trezor import config
from storage import device from storage import device

@ -1,7 +1,6 @@
from common import * from common import *
from trezor.crypto import random from trezor.crypto import random
from trezor.pin import pin_to_int
from trezor import config from trezor import config
@ -27,7 +26,7 @@ class TestConfig(unittest.TestCase):
def test_wipe(self): def test_wipe(self):
config.init() config.init()
config.wipe() config.wipe()
self.assertEqual(config.unlock(pin_to_int(''), None), True) self.assertEqual(config.unlock('', None), True)
config.set(1, 1, b'hello') config.set(1, 1, b'hello')
config.set(1, 2, b'world') config.set(1, 2, b'world')
v0 = config.get(1, 1) v0 = config.get(1, 1)
@ -44,7 +43,7 @@ class TestConfig(unittest.TestCase):
for _ in range(128): for _ in range(128):
config.init() config.init()
config.wipe() config.wipe()
self.assertEqual(config.unlock(pin_to_int(''), None), True) self.assertEqual(config.unlock('', None), True)
appid, key = random_entry() appid, key = random_entry()
value = random.bytes(16) value = random.bytes(16)
config.set(appid, key, value) config.set(appid, key, value)
@ -58,7 +57,7 @@ class TestConfig(unittest.TestCase):
def test_public(self): def test_public(self):
config.init() config.init()
config.wipe() config.wipe()
self.assertEqual(config.unlock(pin_to_int(''), None), True) self.assertEqual(config.unlock('', None), True)
appid, key = random_entry() appid, key = random_entry()
@ -84,20 +83,46 @@ class TestConfig(unittest.TestCase):
def test_change_pin(self): def test_change_pin(self):
config.init() config.init()
config.wipe() config.wipe()
self.assertEqual(config.unlock(pin_to_int(''), None), True) self.assertTrue(config.unlock('', None))
with self.assertRaises(RuntimeError):
config.set(PINAPP, PINKEY, b'value')
self.assertEqual(config.change_pin(pin_to_int('000'), pin_to_int('666'), None, None), False)
self.assertEqual(config.change_pin(pin_to_int(''), pin_to_int('000'), None, None), True)
self.assertEqual(config.get(PINAPP, PINKEY), None)
config.set(1, 1, b'value') config.set(1, 1, b'value')
config.init() PINS = ('123', '123', 'Trezor T', '3141592653589793238462643383279502884197', '')
self.assertEqual(config.unlock(pin_to_int('000'), None), True) old_pin = ''
config.change_pin(pin_to_int('000'), pin_to_int(''), None, None) for new_pin in PINS:
config.init() self.assertTrue(config.unlock(old_pin, None))
self.assertEqual(config.unlock(pin_to_int('000'), None), False)
self.assertEqual(config.unlock(pin_to_int(''), None), True) # The APP namespace which is reserved for storage related values is inaccessible even
self.assertEqual(config.get(1, 1), b'value') # when unlocked.
with self.assertRaises(RuntimeError):
config.set(PINAPP, PINKEY, b'value')
self.assertTrue(config.change_pin(old_pin, new_pin, None, None))
# Old PIN cannot be used to change the current PIN.
if old_pin != new_pin:
self.assertFalse(config.change_pin(old_pin, '666', None, None))
# Storage remains unlocked.
self.assertEqual(config.get(1, 1), b'value')
# The APP namespace which is reserved for storage related values is inaccessible even
# when unlocked.
self.assertEqual(config.get(PINAPP, PINKEY), None)
# Old PIN cannot be used to unlock storage.
if old_pin != new_pin:
config.init()
self.assertFalse(config.unlock(old_pin, None))
self.assertEqual(config.get(1, 1), None)
with self.assertRaises(RuntimeError):
config.set(1, 1, b'new value')
# New PIN unlocks the storage.
self.assertTrue(config.unlock(new_pin, None))
self.assertEqual(config.get(1, 1), b'value')
# Lock the storage.
config.init()
old_pin = new_pin
def test_change_sd_salt(self): def test_change_sd_salt(self):
salt1 = b"0123456789abcdef0123456789abcdef" salt1 = b"0123456789abcdef0123456789abcdef"
@ -106,37 +131,37 @@ class TestConfig(unittest.TestCase):
# Enable PIN and SD salt. # Enable PIN and SD salt.
config.init() config.init()
config.wipe() config.wipe()
self.assertTrue(config.unlock(pin_to_int(''), None)) self.assertTrue(config.unlock('', None))
config.set(1, 1, b'value') config.set(1, 1, b'value')
self.assertFalse(config.change_pin(pin_to_int(''), pin_to_int(''), salt1, None)) self.assertFalse(config.change_pin('', '', salt1, None))
self.assertTrue(config.change_pin(pin_to_int(''), pin_to_int('000'), None, salt1)) self.assertTrue(config.change_pin('', '000', None, salt1))
self.assertEqual(config.get(1, 1), b'value') self.assertEqual(config.get(1, 1), b'value')
# Disable PIN and change SD salt. # Disable PIN and change SD salt.
config.init() config.init()
self.assertFalse(config.unlock(pin_to_int('000'), None)) self.assertFalse(config.unlock('000', None))
self.assertIsNone(config.get(1, 1)) self.assertIsNone(config.get(1, 1))
self.assertTrue(config.unlock(pin_to_int('000'), salt1)) self.assertTrue(config.unlock('000', salt1))
self.assertTrue(config.change_pin(pin_to_int('000'), pin_to_int(''), salt1, salt2)) self.assertTrue(config.change_pin('000', '', salt1, salt2))
self.assertEqual(config.get(1, 1), b'value') self.assertEqual(config.get(1, 1), b'value')
# Disable SD salt. # Disable SD salt.
config.init() config.init()
self.assertFalse(config.unlock(pin_to_int('000'), salt2)) self.assertFalse(config.unlock('000', salt2))
self.assertIsNone(config.get(1, 1)) self.assertIsNone(config.get(1, 1))
self.assertTrue(config.unlock(pin_to_int(''), salt2)) self.assertTrue(config.unlock('', salt2))
self.assertTrue(config.change_pin(pin_to_int(''), pin_to_int(''), salt2, None)) self.assertTrue(config.change_pin('', '', salt2, None))
self.assertEqual(config.get(1, 1), b'value') self.assertEqual(config.get(1, 1), b'value')
# Check that PIN and SD salt are disabled. # Check that PIN and SD salt are disabled.
config.init() config.init()
self.assertTrue(config.unlock(pin_to_int(''), None)) self.assertTrue(config.unlock('', None))
self.assertEqual(config.get(1, 1), b'value') self.assertEqual(config.get(1, 1), b'value')
def test_set_get(self): def test_set_get(self):
config.init() config.init()
config.wipe() config.wipe()
self.assertEqual(config.unlock(pin_to_int(''), None), True) self.assertEqual(config.unlock('', None), True)
for _ in range(32): for _ in range(32):
appid, key = random_entry() appid, key = random_entry()
value = random.bytes(128) value = random.bytes(128)
@ -147,7 +172,7 @@ class TestConfig(unittest.TestCase):
def test_compact(self): def test_compact(self):
config.init() config.init()
config.wipe() config.wipe()
self.assertEqual(config.unlock(pin_to_int(''), None), True) self.assertEqual(config.unlock('', None), True)
appid, key = 1, 1 appid, key = 1, 1
for _ in range(259): for _ in range(259):
value = random.bytes(259) value = random.bytes(259)
@ -158,7 +183,7 @@ class TestConfig(unittest.TestCase):
def test_get_default(self): def test_get_default(self):
config.init() config.init()
config.wipe() config.wipe()
self.assertEqual(config.unlock(pin_to_int(''), None), True) self.assertEqual(config.unlock('', None), True)
for _ in range(128): for _ in range(128):
appid, key = random_entry() appid, key = random_entry()
value = config.get(appid, key) value = config.get(appid, key)

Loading…
Cancel
Save