Skip to content

Commit

Permalink
Added option to generate BIP39 mnemonics from SSKR shares even if sha…
Browse files Browse the repository at this point in the history
…res 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
  • Loading branch information
aido committed Oct 20, 2023
1 parent 3883a28 commit 2f39937
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 49 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
-
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""
Expand Down
4 changes: 2 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Binary file modified icons/seed_tool.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 17 additions & 15 deletions src/nano/nanos_enter_phrase.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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"});

Expand All @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
26 changes: 14 additions & 12 deletions src/nano/nanox_enter_phrase.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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"});

Expand All @@ -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"});

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand All @@ -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);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/nano/ui_nano.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
11 changes: 11 additions & 0 deletions src/nano/ux_nano.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/nano/ux_nano.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include "ux_common/common.h"

/*
#if defined(TARGET_NANOS)
#define ARRAYLEN(array) (sizeof(array) / sizeof(array[0]))
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 1 addition & 6 deletions src/nano/ux_nano_bip39.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,14 @@

#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,
{
.title = "BIP39 Phrase",
.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);

Expand Down
11 changes: 1 addition & 10 deletions src/nano/ux_nano_sskr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 2f39937

Please sign in to comment.