diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c4695d1..c7d86f23 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ # Change log -## [1.4.2] - 2023-10-18 +## [1.5.0] - 2023-10-20 ### Added -- +- Added option to generate BIP39 mnemonics from SSKR shares even if shares do not validate against seed on device + - A user may have lost or damaged original device and now needs to generate the recovery phrase from another secure device ### Changed - diff --git a/Makefile b/Makefile index 120aeb5a..dad3bf73 100755 --- a/Makefile +++ b/Makefile @@ -27,8 +27,8 @@ all: default APPNAME = "Seed Tool" APPVERSION_M = 1 -APPVERSION_N = 4 -APPVERSION_P = 2 +APPVERSION_N = 5 +APPVERSION_P = 0 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" APP_LOAD_PARAMS = --appFlags 0x10 $(COMMON_LOAD_PARAMS) --curve secp256k1 --path "" diff --git a/TODO.md b/TODO.md index 28f91c4e..3c377dcc 100755 --- a/TODO.md +++ b/TODO.md @@ -16,11 +16,11 @@ - [ ] Write SSKR to BIP39 functionality - [ ] Test with 29-word SSKR shares - [ ] Test with 46-word SSKR shares -- [ ] Add option to generate BIP39 mnemonics from SSKR shares even if shares do not validate against seed on device - - A user may have lost or damaged original device and now needs to generate the recovery phrase from another secure device ### Done ✓ +- [x] Add option to generate BIP39 mnemonics from SSKR shares even if shares do not validate against seed on device + - A user may have lost or damaged original device and now needs to generate the recovery phrase from another secure device - [x] Fix warnings about deprecated functions during build - [x] Remove duplicated nano code - [x] Simplified flow code diff --git a/icons/seed_tool.png b/icons/seed_tool.png index 14f32454..ef43a64f 100644 Binary files a/icons/seed_tool.png and b/icons/seed_tool.png differ diff --git a/src/nano/nanos_enter_phrase.c b/src/nano/nanos_enter_phrase.c index 69305f8a..6a3f636a 100644 --- a/src/nano/nanos_enter_phrase.c +++ b/src/nano/nanos_enter_phrase.c @@ -102,15 +102,15 @@ const bagl_element_t screen_onboarding_word_list_elements[] = { void screen_onboarding_restore_word_display_auto_complete(void); -UX_STEP_CB(restore_1_intro_1, nn, screen_onboarding_restore_word_display_auto_complete(); +UX_STEP_CB(ux_restore_step_1, nn, screen_onboarding_restore_word_display_auto_complete(); , {"Enter", G_ux.string_buffer}); -UX_FLOW(restore_1_intro, &restore_1_intro_1); +UX_FLOW(ux_restore_flow, &ux_restore_step_1); -UX_STEP_CB(restore_1_bip39_invalid_step_1, pbb, screen_onboarding_bip39_restore_init(); +UX_STEP_CB(ux_bip39_invalid_step_1, pbb, screen_onboarding_bip39_restore_init(); , {&C_icon_warning, "BIP39 Recovery", "phrase invalid"}); -UX_FLOW(restore_1_bip39_invalid, &restore_1_bip39_invalid_step_1); +UX_FLOW(ux_bip39_invalid_flow, &ux_bip39_invalid_step_1); UX_STEP_NOCB(ux_bip39_nomatch_step_1, pbb, {&C_icon_warning, "BIP39 Phrase", "doesn't match"}); UX_STEP_NOCB(ux_bip39_nomatch_step_2, @@ -128,9 +128,9 @@ UX_FLOW(ux_bip39_nomatch_flow, UX_STEP_VALID(ux_bip39_match_step_1, pbb, - os_sched_exit(0), + clean_exit(0), {&C_icon_validate_14, "BIP39 Phrase", "is correct"}); -UX_STEP_CB(ux_bip39_match_step_2, pb, os_sched_exit(0), {&C_icon_dashboard_x, "Quit"}); +UX_STEP_CB(ux_bip39_match_step_2, pb, clean_exit(0), {&C_icon_dashboard_x, "Quit"}); UX_STEP_CB(ux_bip39_match_step_3, pbb, set_sskr_descriptor_values(); , {&SSKR_ICON, "Generate", "SSKR phrases"}); @@ -139,10 +139,10 @@ UX_FLOW(ux_bip39_match_flow, &ux_bip39_match_step_2, &ux_bip39_match_step_3); -UX_STEP_CB(restore_1_sskr_invalid_step_1, pbb, screen_onboarding_sskr_restore_init(); +UX_STEP_CB(ux_sskr_invalid_step_1, pbb, screen_onboarding_sskr_restore_init(); , {&C_icon_warning, "SSKR Recovery", "phrase invalid"}); -UX_FLOW(restore_1_sskr_invalid, &restore_1_sskr_invalid_step_1); +UX_FLOW(ux_sskr_invalid_flow, &ux_sskr_invalid_step_1); UX_STEP_NOCB(ux_sskr_nomatch_step_1, pbb, {&C_icon_warning, "SSKR Phrase", "doesn't match"}); UX_STEP_NOCB(ux_sskr_nomatch_step_2, @@ -152,17 +152,20 @@ UX_STEP_NOCB(ux_sskr_nomatch_step_2, "order and spelling", }); UX_STEP_VALID(ux_sskr_nomatch_step_3, pb, ui_idle_init(), {&C_icon_back_x, "Return to menu"}); +UX_STEP_CB(ux_sskr_nomatch_step_4, pbb, generate_bip39(); + , {&BIP39_ICON, "Generate", "BIP39 phrase"}); UX_FLOW(ux_sskr_nomatch_flow, &ux_sskr_nomatch_step_1, &ux_sskr_nomatch_step_2, - &ux_sskr_nomatch_step_3); + &ux_sskr_nomatch_step_3, + &ux_sskr_nomatch_step_4); UX_STEP_VALID(ux_sskr_match_step_1, pbb, - os_sched_exit(0), + clean_exit(0), {&C_icon_validate_14, "SSKR Phrase", "is correct"}); -UX_STEP_CB(ux_sskr_match_step_2, pb, os_sched_exit(0), {&C_icon_dashboard_x, "Quit"}); +UX_STEP_CB(ux_sskr_match_step_2, pb, clean_exit(0), {&C_icon_dashboard_x, "Quit"}); UX_STEP_CB(ux_sskr_match_step_3, pbb, generate_bip39();, {&BIP39_ICON, "Generate", "BIP39 phrase"}); UX_FLOW(ux_sskr_match_flow, &ux_sskr_match_step_1, &ux_sskr_match_step_2, &ux_sskr_match_step_3); @@ -460,7 +463,6 @@ void compare_recovery_phrase(void) { // compare both rootkey if (memcmp_ret) { - memzero(G_bolos_ux_context.words_buffer, G_bolos_ux_context.words_buffer_length); (G_bolos_ux_context.onboarding_type == ONBOARDING_TYPE_BIP39) ? ux_flow_init(0, ux_bip39_nomatch_flow, NULL) : ux_flow_init(0, ux_sskr_nomatch_flow, NULL); @@ -550,7 +552,7 @@ void screen_onboarding_restore_word_validate(void) { G_bolos_ux_context.words_buffer_length); #endif if (!valid) { - ux_flow_init(0, restore_1_bip39_invalid, NULL); + ux_flow_init(0, ux_bip39_invalid_flow, NULL); } else { // alright, the recovery phrase looks ok, finish onboarding // Display processing warning to user @@ -583,7 +585,7 @@ void screen_onboarding_restore_word_validate(void) { G_bolos_ux_context.sskr_words_buffer_length, G_bolos_ux_context.sskr_share_count); if (!valid) { - ux_flow_init(0, restore_1_sskr_invalid, NULL); + ux_flow_init(0, ux_sskr_invalid_flow, NULL); } else { // alright, the recovery phrase looks ok, finish onboarding // Display processing warning to user @@ -708,7 +710,7 @@ void screen_onboarding_restore_word_init(unsigned int action) { "Share#%d Word#%d", G_bolos_ux_context.sskr_share_index + 1, G_bolos_ux_context.onboarding_step + 1); - ux_flow_init(0, restore_1_intro, NULL); + ux_flow_init(0, ux_restore_flow, NULL); } #endif diff --git a/src/nano/nanox_enter_phrase.c b/src/nano/nanox_enter_phrase.c index a46c31b5..5d02fac9 100644 --- a/src/nano/nanox_enter_phrase.c +++ b/src/nano/nanox_enter_phrase.c @@ -148,15 +148,15 @@ const bagl_element_t screen_onboarding_restore_word_select_elements[] = { UX_STEP_NOCB(ux_load_step, pn, {&C_icon_loader, "Processing"}); UX_FLOW(ux_load_flow, &ux_load_step); -UX_STEP_VALID(ux_wrong_seed_step, +UX_STEP_VALID(ux_invalid_step_1, pnn, - os_sched_exit(-1), + clean_exit(-1), { &C_icon_crossmark, "Recovery", "phrase invalid", }); -UX_FLOW(ux_wrong_seed_flow, &ux_wrong_seed_step); +UX_FLOW(ux_invalid_flow, &ux_invalid_step_1); UX_STEP_NOCB(ux_bip39_nomatch_step_1, pbb, {&C_icon_warning, "BIP39 Phrase", "doesn't match"}); UX_STEP_NOCB(ux_bip39_nomatch_step_2, @@ -173,9 +173,9 @@ UX_FLOW(ux_bip39_nomatch_flow, UX_STEP_VALID(ux_bip39_match_step_1, pbb, - os_sched_exit(-1), + clean_exit(-1), {&C_icon_validate_14, "BIP39 Phrase", "is correct"}); -UX_STEP_CB(ux_bip39_match_step_2, pb, os_sched_exit(0), {&C_icon_dashboard_x, "Quit"}); +UX_STEP_CB(ux_bip39_match_step_2, pb, clean_exit(0), {&C_icon_dashboard_x, "Quit"}); UX_STEP_CB(ux_bip39_match_step_3, pbb, set_sskr_descriptor_values(); , {&SSKR_ICON, "Generate", "SSKR phrases"}); @@ -192,16 +192,20 @@ UX_STEP_NOCB(ux_sskr_nomatch_step_2, "order and spelling", }); UX_STEP_VALID(ux_sskr_nomatch_step_3, pb, ui_idle_init(), {&C_icon_back_x, "Return to menu"}); +UX_STEP_CB(ux_sskr_nomatch_step_4, pbb, generate_bip39(); + , {&BIP39_ICON, "Generate", "BIP39 phrases"}); + UX_FLOW(ux_sskr_nomatch_flow, &ux_sskr_nomatch_step_1, &ux_sskr_nomatch_step_2, - &ux_sskr_nomatch_step_3); + &ux_sskr_nomatch_step_3, + &ux_sskr_nomatch_step_4); UX_STEP_VALID(ux_sskr_match_step_1, pbb, - os_sched_exit(-1), + clean_exit(-1), {&C_icon_validate_14, "SSKR Phrase", "is correct"}); -UX_STEP_CB(ux_sskr_match_step_2, pb, os_sched_exit(0), {&C_icon_dashboard_x, "Quit"}); +UX_STEP_CB(ux_sskr_match_step_2, pb, clean_exit(0), {&C_icon_dashboard_x, "Quit"}); UX_STEP_CB(ux_sskr_match_step_3, pbb, generate_bip39(); , {&BIP39_ICON, "Generate", "BIP39 phrases"}); @@ -578,7 +582,7 @@ void screen_onboarding_restore_word_validate(void) { #endif if (!valid) { // invalid recovery phrase - ux_flow_init(0, ux_wrong_seed_flow, NULL); + ux_flow_init(0, ux_invalid_flow, NULL); } else { // alright, the recovery phrase looks ok, compare it to onboarded seed @@ -616,7 +620,7 @@ void screen_onboarding_restore_word_validate(void) { G_bolos_ux_context.sskr_share_count); if (!valid) { // invalid recovery phrase - ux_flow_init(0, ux_wrong_seed_flow, NULL); + ux_flow_init(0, ux_invalid_flow, NULL); } else { // alright, the recovery phrase looks ok, compare it to onboarded seed @@ -625,8 +629,6 @@ void screen_onboarding_restore_word_validate(void) { if (compare_recovery_phrase()) { ux_flow_init(0, ux_sskr_match_flow, NULL); } else { - memzero(G_bolos_ux_context.words_buffer, - G_bolos_ux_context.words_buffer_length); ux_flow_init(0, ux_sskr_nomatch_flow, NULL); } } diff --git a/src/nano/ui_nano.c b/src/nano/ui_nano.c index a33a6f55..87ccbfc4 100644 --- a/src/nano/ui_nano.c +++ b/src/nano/ui_nano.c @@ -136,6 +136,13 @@ UX_FLOW(ux_idle_flow, void ui_idle_init(void) { uiState = UI_IDLE; + memzero(G_bolos_ux_context.words_buffer, sizeof(G_bolos_ux_context.words_buffer)); + memzero(G_bolos_ux_context.string_buffer, sizeof(G_bolos_ux_context.string_buffer)); + memzero(G_bolos_ux_context.sskr_words_buffer, G_bolos_ux_context.sskr_words_buffer_length); + G_bolos_ux_context.words_buffer_length = 0; + G_bolos_ux_context.sskr_words_buffer_length = 0; + G_bolos_ux_context.sskr_share_index = 0; + // reserve a display stack slot if none yet if (G_ux.stack_count == 0) { ux_stack_push(); diff --git a/src/nano/ux_nano.c b/src/nano/ux_nano.c index c56996f8..327e9d18 100644 --- a/src/nano/ux_nano.c +++ b/src/nano/ux_nano.c @@ -23,6 +23,17 @@ bolos_ux_context_t G_bolos_ux_context; +void clean_exit(bolos_task_status_t exit_code) { + memzero(G_bolos_ux_context.words_buffer, sizeof(G_bolos_ux_context.words_buffer)); + memzero(G_bolos_ux_context.string_buffer, sizeof(G_bolos_ux_context.string_buffer)); + memzero(G_bolos_ux_context.sskr_words_buffer, G_bolos_ux_context.sskr_words_buffer_length); + G_bolos_ux_context.words_buffer_length = 0; + G_bolos_ux_context.sskr_words_buffer_length = 0; + G_bolos_ux_context.sskr_share_index = 0; + + os_sched_exit(exit_code); +} + unsigned short io_timeout(unsigned short last_timeout) { UNUSED(last_timeout); // infinite timeout diff --git a/src/nano/ux_nano.h b/src/nano/ux_nano.h index 0d931d46..ba06bdd6 100644 --- a/src/nano/ux_nano.h +++ b/src/nano/ux_nano.h @@ -17,6 +17,7 @@ #pragma once #include "ux_common/common.h" + /* #if defined(TARGET_NANOS) #define ARRAYLEN(array) (sizeof(array) / sizeof(array[0])) @@ -108,6 +109,8 @@ void generate_bip39(void); #include "ux_common/common_bip39.h" #include "ux_common/common_sskr.h" +void clean_exit(bolos_task_status_t exit_code); + #if defined(TARGET_NANOS) extern const bagl_element_t screen_onboarding_word_list_elements[9]; void compare_recovery_phrase(void); diff --git a/src/nano/ux_nano_bip39.c b/src/nano/ux_nano_bip39.c index 99add32b..219b18d7 100644 --- a/src/nano/ux_nano_bip39.c +++ b/src/nano/ux_nano_bip39.c @@ -18,11 +18,6 @@ #if defined(TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) -void bip39_clean_exit(void) { - memzero(G_bolos_ux_context.words_buffer, sizeof(G_bolos_ux_context.words_buffer)); - os_sched_exit(0); -} - UX_STEP_NOCB(step_display_bip39, bnnn_paging, { @@ -30,7 +25,7 @@ UX_STEP_NOCB(step_display_bip39, .text = G_bolos_ux_context.words_buffer, }); -UX_STEP_CB(step_bip39_clean_exit, pb, bip39_clean_exit(), {&C_icon_dashboard_x, "Quit"}); +UX_STEP_CB(step_bip39_clean_exit, pb, clean_exit(0), {&C_icon_dashboard_x, "Quit"}); UX_FLOW(display_bip39_flow, &step_display_bip39, &step_bip39_clean_exit, FLOW_LOOP); diff --git a/src/nano/ux_nano_sskr.c b/src/nano/ux_nano_sskr.c index 48ced31a..01b68af5 100644 --- a/src/nano/ux_nano_sskr.c +++ b/src/nano/ux_nano_sskr.c @@ -52,15 +52,6 @@ void bnnn_paging_edgecase(void) { ux_flow_relayout(); } -void sskr_clean_exit(void) { - memzero(G_bolos_ux_context.sskr_words_buffer, G_bolos_ux_context.sskr_words_buffer_length); - G_bolos_ux_context.sskr_words_buffer_length = 0; - G_bolos_ux_context.sskr_share_index = 0; - memzero(G_bolos_ux_context.words_buffer, sizeof(G_bolos_ux_context.words_buffer)); - memzero(G_bolos_ux_context.string_buffer, sizeof(G_bolos_ux_context.string_buffer)); - os_sched_exit(0); -} - void display_next_state(bool is_upper_delimiter) { if (is_upper_delimiter) { // We're called from the upper delimiter. if (G_bolos_ux_context.current_state == STATIC_SCREEN) { @@ -111,7 +102,7 @@ UX_STEP_NOCB(step_display_shares, UX_STEP_INIT(step_lower_delimiter, NULL, NULL, { display_next_state(false); }); -UX_STEP_CB(step_sskr_clean_exit, pb, sskr_clean_exit(), {&C_icon_dashboard_x, "Quit"}); +UX_STEP_CB(step_sskr_clean_exit, pb, clean_exit(0), {&C_icon_dashboard_x, "Quit"}); UX_FLOW(dynamic_flow, &step_upper_delimiter,