diff --git a/legacy/firmware/.changelog.d/+entropy_check.added b/legacy/firmware/.changelog.d/+entropy_check.added new file mode 100644 index 0000000000..c138763493 --- /dev/null +++ b/legacy/firmware/.changelog.d/+entropy_check.added @@ -0,0 +1 @@ +Entropy check workflow in ResetDevice. diff --git a/legacy/firmware/fsm.c b/legacy/firmware/fsm.c index eefed373db..639ca78c33 100644 --- a/legacy/firmware/fsm.c +++ b/legacy/firmware/fsm.c @@ -410,6 +410,7 @@ void fsm_msgRebootToBootloader(void) { } void fsm_abortWorkflows(void) { + reset_abort(); recovery_abort(); signing_abort(); authorization_type = 0; diff --git a/legacy/firmware/fsm.h b/legacy/firmware/fsm.h index 37d2183c02..abce2e9ec2 100644 --- a/legacy/firmware/fsm.h +++ b/legacy/firmware/fsm.h @@ -64,6 +64,7 @@ void fsm_msgLoadDevice(const LoadDevice *msg); #endif void fsm_msgResetDevice(const ResetDevice *msg); void fsm_msgEntropyAck(const EntropyAck *msg); +void fsm_msgEntropyCheckContinue(const EntropyCheckContinue *msg); void fsm_msgBackupDevice(const BackupDevice *msg); void fsm_msgCancel(const Cancel *msg); void fsm_msgLockDevice(const LockDevice *msg); diff --git a/legacy/firmware/fsm_msg_common.h b/legacy/firmware/fsm_msg_common.h index ab6beb5820..849d579be4 100644 --- a/legacy/firmware/fsm_msg_common.h +++ b/legacy/firmware/fsm_msg_common.h @@ -321,6 +321,8 @@ void fsm_msgResetDevice(const ResetDevice *msg) { msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); + fsm_abortWorkflows(); + reset_init(msg->has_strength ? msg->strength : 128, msg->has_passphrase_protection && msg->passphrase_protection, msg->has_pin_protection && msg->pin_protection, @@ -328,13 +330,18 @@ void fsm_msgResetDevice(const ResetDevice *msg) { msg->has_label ? msg->label : 0, msg->has_u2f_counter ? msg->u2f_counter : 0, msg->has_skip_backup ? msg->skip_backup : false, - msg->has_no_backup ? msg->no_backup : false); + msg->has_no_backup ? msg->no_backup : false, + msg->has_entropy_check ? msg->entropy_check : false); } void fsm_msgEntropyAck(const EntropyAck *msg) { reset_entropy(msg->entropy.bytes, msg->entropy.size); } +void fsm_msgEntropyCheckContinue(const EntropyCheckContinue *msg) { + reset_continue(msg->has_finish ? msg->finish : false); +} + void fsm_msgBackupDevice(const BackupDevice *msg) { (void)msg; @@ -497,6 +504,8 @@ void fsm_msgRecoveryDevice(const RecoveryDevice *msg) { msg->type == RecoveryType_DryRun, _("UnlockRepeatedBackup not supported")) + fsm_abortWorkflows(); + const bool dry_run = msg->has_type ? msg->type == RecoveryType_DryRun : false; if (!dry_run) { CHECK_NOT_INITIALIZED diff --git a/legacy/firmware/protob/Makefile b/legacy/firmware/protob/Makefile index 0b9490a3f1..92b81ada57 100644 --- a/legacy/firmware/protob/Makefile +++ b/legacy/firmware/protob/Makefile @@ -11,7 +11,7 @@ SKIPPED_MESSAGES := Binance Cardano DebugMonero Eos Monero Ontology Ripple SdPro UnlockBootloader AuthenticateDevice AuthenticityProof \ Solana StellarClaimClaimableBalanceOp \ ChangeLanguage TranslationDataRequest TranslationDataAck \ - SetBrightness DebugLinkOptigaSetSecMax EntropyCheckReady EntropyCheckContinue \ + SetBrightness DebugLinkOptigaSetSecMax \ BenchmarkListNames BenchmarkRun BenchmarkNames BenchmarkResult \ NostrGetPubkey NostrPubkey NostrSignEvent NostrEventSignature \ BleUnpair diff --git a/legacy/firmware/protob/messages-management.options b/legacy/firmware/protob/messages-management.options index e9a2aa0954..17c5c0850b 100644 --- a/legacy/firmware/protob/messages-management.options +++ b/legacy/firmware/protob/messages-management.options @@ -30,8 +30,8 @@ BackupDevice.groups type:FT_IGNORE Entropy.entropy max_size:1024 -EntropyRequest.entropy_commitment type:FT_IGNORE -EntropyRequest.prev_entropy type:FT_IGNORE +EntropyRequest.entropy_commitment max_size:32 +EntropyRequest.prev_entropy max_size:32 EntropyAck.entropy max_size:128 diff --git a/legacy/firmware/reset.c b/legacy/firmware/reset.c index 928465f53a..677d1dce95 100644 --- a/legacy/firmware/reset.c +++ b/legacy/firmware/reset.c @@ -22,6 +22,7 @@ #include "config.h" #include "fsm.h" #include "gettext.h" +#include "hmac.h" #include "layout2.h" #include "memzero.h" #include "messages.h" @@ -34,18 +35,37 @@ static uint32_t strength; static uint8_t int_entropy[32]; -static bool awaiting_entropy = false; +static uint8_t seed[64]; +static const char *reset_mnemonic; static bool skip_backup = false; static bool no_backup = false; +static bool entropy_check = false; + +static enum { + RESET_NONE = 0, + RESET_ENTROPY_REQUEST, + RESET_ENTROPY_CHECK_READY, +} reset_state = RESET_NONE; + +static void send_entropy_request(bool set_prev_entropy); +static void reset_finish(void); + +static void entropy_check_progress(uint32_t iter, uint32_t total) { + (void)iter; + (void)total; + layoutProgress(_("Entropy check"), 0); +} void reset_init(uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, - uint32_t u2f_counter, bool _skip_backup, bool _no_backup) { + uint32_t u2f_counter, bool _skip_backup, bool _no_backup, + bool _entropy_check) { if (_strength != 128 && _strength != 192 && _strength != 256) return; strength = _strength; skip_backup = _skip_backup; no_backup = _no_backup; + entropy_check = _entropy_check; layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("create a new wallet?"), NULL, @@ -56,8 +76,6 @@ void reset_init(uint32_t _strength, bool passphrase_protection, return; } - random_buffer(int_entropy, 32); - if (pin_protection && !protectChangePin(false)) { layoutHome(); return; @@ -67,36 +85,79 @@ void reset_init(uint32_t _strength, bool passphrase_protection, config_setLanguage(language); config_setLabel(label); config_setU2FCounter(u2f_counter); + send_entropy_request(false); +} +static void send_entropy_request(bool set_prev_entropy) { EntropyRequest resp = {0}; - memzero(&resp, sizeof(EntropyRequest)); + if (set_prev_entropy) { + memcpy(resp.prev_entropy.bytes, int_entropy, sizeof(int_entropy)); + resp.prev_entropy.size = sizeof(int_entropy); + resp.has_prev_entropy = true; + } + + random_buffer(int_entropy, sizeof(int_entropy)); + if (entropy_check) { + hmac_sha256(int_entropy, sizeof(int_entropy), NULL, 0, + resp.entropy_commitment.bytes); + resp.entropy_commitment.size = SHA256_DIGEST_LENGTH; + resp.has_entropy_commitment = true; + } msg_write(MessageType_MessageType_EntropyRequest, &resp); - awaiting_entropy = true; + reset_state = RESET_ENTROPY_REQUEST; } void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { - if (!awaiting_entropy) { + if (reset_state != RESET_ENTROPY_REQUEST) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, - _("Not in Reset mode")); + _("Entropy not requested")); return; } - awaiting_entropy = false; + uint8_t secret[SHA256_DIGEST_LENGTH] = {0}; SHA256_CTX ctx = {0}; sha256_Init(&ctx); SHA256_UPDATE_BYTES(&ctx, int_entropy, 32); sha256_Update(&ctx, ext_entropy, len); - sha256_Final(&ctx, int_entropy); - const char *mnemonic = mnemonic_from_data(int_entropy, strength / 8); - memzero(int_entropy, 32); + sha256_Final(&ctx, secret); + reset_mnemonic = mnemonic_from_data(secret, strength / 8); + memzero(secret, sizeof(secret)); + if (!entropy_check) { + reset_finish(); + return; + } + reset_state = RESET_ENTROPY_CHECK_READY; + mnemonic_to_seed(reset_mnemonic, "", seed, entropy_check_progress); + EntropyCheckReady resp = {0}; + msg_write(MessageType_MessageType_EntropyCheckReady, &resp); +} + +void reset_continue(bool finish) { + if (reset_state != RESET_ENTROPY_CHECK_READY) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Entropy check not ready")); + return; + } + + if (finish) { + reset_finish(); + } else { + send_entropy_request(true); + } +} + +static void reset_finish(void) { + memzero(int_entropy, sizeof(int_entropy)); + memzero(seed, sizeof(seed)); + reset_state = RESET_NONE; if (skip_backup || no_backup) { if (no_backup) { config_setNoBackup(); } else { config_setNeedsBackup(true); } - if (config_setMnemonic(mnemonic)) { + if (config_setMnemonic(reset_mnemonic)) { fsm_sendSuccess(_("Device successfully initialized")); } else { fsm_sendFailure(FailureType_Failure_ProcessError, @@ -104,11 +165,18 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { } layoutHome(); } else { - reset_backup(false, mnemonic); + reset_backup(false, reset_mnemonic); } mnemonic_clear(); } +const uint8_t *reset_get_seed(void) { + if (reset_state != RESET_ENTROPY_CHECK_READY) { + return NULL; + } + return seed; +} + static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage @@ -170,6 +238,15 @@ void reset_backup(bool separated, const char *mnemonic) { layoutHome(); } +void reset_abort(void) { + memzero(int_entropy, sizeof(int_entropy)); + memzero(seed, sizeof(seed)); + if (reset_state != RESET_NONE) { + reset_state = RESET_NONE; + layoutHome(); + } +} + #if DEBUG_LINK uint32_t reset_get_int_entropy(uint8_t *entropy) { diff --git a/legacy/firmware/reset.h b/legacy/firmware/reset.h index cebf33cc23..5d0bee744c 100644 --- a/legacy/firmware/reset.h +++ b/legacy/firmware/reset.h @@ -25,10 +25,14 @@ void reset_init(uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, - uint32_t u2f_counter, bool _skip_backup, bool _no_backup); + uint32_t u2f_counter, bool _skip_backup, bool _no_backup, + bool _entropy_check); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); +void reset_continue(bool finish); +const uint8_t *reset_get_seed(void); void reset_backup(bool separated, const char *mnemonic); uint32_t reset_get_int_entropy(uint8_t *entropy); const char *reset_get_word(void); +void reset_abort(void); #endif