/* * layout_cipher() - Draws recover cipher * * INPUT * - current_word: current word that is being typed in at this point in recovery * - cipher: randomized cipher * OUTPUT * none */ void layout_cipher(const char *current_word, const char *cipher) { DrawableParams sp; const Font *title_font = get_body_font(); Canvas *canvas = layout_get_canvas(); call_leaving_handler(); layout_clear(); /* Draw prompt */ sp.y = 11; sp.x = 4; sp.color = BODY_COLOR; draw_string(canvas, title_font, "Recovery Cipher:", &sp, 58, font_height(title_font) + 3); /* Draw current word */ sp.y = 46; sp.x = 4; sp.color = BODY_COLOR; draw_string(canvas, title_font, current_word, &sp, 68, font_height(title_font)); display_refresh(); /* Animate cipher */ layout_add_animation(&layout_animate_cipher, (void *)cipher, CIPHER_ANIMATION_FREQUENCY_MS * 30); }
/* * layout_transaction_notification() - Display transaction notification * * INPUT * - amount: amount of transaction * - address: destination address * - type: notification type * OUTPUT * none */ void layout_transaction_notification(const char *amount, const char *address, NotificationType type) { call_leaving_handler(); layout_clear(); Canvas *canvas = layout_get_canvas(); DrawableParams sp; const Font *amount_font = get_title_font(); const Font *address_font = get_title_font(); /* Unbold fonts if address becomes too long */ if(calc_str_width(address_font, address) > TRANSACTION_WIDTH) { amount_font = get_body_font(); address_font = get_body_font(); } /* Determine vertical alignment and body width */ sp.y = TOP_MARGIN_FOR_ONE_LINE; /* Format amount line */ char title[BODY_CHAR_MAX]; snprintf(title, BODY_CHAR_MAX, "Send %s to", amount); /* Draw amount */ sp.x = LEFT_MARGIN; sp.color = TITLE_COLOR; draw_string(canvas, amount_font, title, &sp, TRANSACTION_WIDTH, font_height(amount_font)); /* Draw address */ sp.y += font_height(address_font) + TRANSACTION_TOP_MARGIN; sp.x = LEFT_MARGIN; sp.color = BODY_COLOR; draw_string(canvas, address_font, address, &sp, TRANSACTION_WIDTH, font_height(address_font) + BODY_FONT_LINE_PADDING); layout_notification_icon(type, &sp); }
/* * layout_pin() - Draws pin matrix * * INPUT * - str: string prompt to display next to pin matrix * - pin: randomized pin matric * OUTPUT * none */ void layout_pin(const char *str, char pin[]) { DrawableParams sp; Canvas *canvas = layout_get_canvas(); call_leaving_handler(); layout_clear(); /* Draw prompt */ const Font *font = get_body_font(); sp.y = 29; sp.x = (140 - calc_str_width(font, str)) / 2; sp.color = BODY_COLOR; draw_string(canvas, font, str, &sp, TITLE_WIDTH, font_height(font)); display_refresh(); /* Animate pin scrambling */ layout_add_animation(&layout_animate_pin, (void *)pin, PIN_MAX_ANIMATION_MS); }
/* * layout_address_notification() - Display address notification * * INPUT * - desc: description of address being shown (normal or multisig) * - address: address to display both as string and QR * - type: notification type * OUTPUT * none */ void layout_address_notification(const char *desc, const char *address, NotificationType type) { call_leaving_handler(); layout_clear(); Canvas *canvas = layout_get_canvas(); DrawableParams sp; const Font *address_font = get_title_font(); /* Unbold fonts if address becomes too long */ if(calc_str_width(address_font, address) > TRANSACTION_WIDTH) { address_font = get_body_font(); } /* Determine vertical alignment and body width */ sp.y = TOP_MARGIN_FOR_ONE_LINE; /* Draw address */ sp.y += font_height(address_font) + ADDRESS_TOP_MARGIN; sp.x = LEFT_MARGIN; sp.color = BODY_COLOR; draw_string(canvas, address_font, address, &sp, TRANSACTION_WIDTH, font_height(address_font) + BODY_FONT_LINE_PADDING); /* Draw description */ if(strcmp(desc, "") != 0) { sp.y = TOP_MARGIN_FOR_ONE_LINE; sp.x = MULTISIG_LEFT_MARGIN; sp.color = BODY_COLOR; draw_string(canvas, address_font, desc, &sp, TRANSACTION_WIDTH, font_height(address_font) + BODY_FONT_LINE_PADDING); } layout_address(address); layout_notification_icon(type, &sp); }
void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { if(!awaiting_entropy) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Reset mode"); return; } SHA256_CTX ctx; sha256_Init(&ctx); sha256_Update(&ctx, int_entropy, 32); sha256_Update(&ctx, ext_entropy, len); sha256_Final(int_entropy, &ctx); const char *temp_mnemonic = mnemonic_from_data(int_entropy, strength / 8); memset(int_entropy, 0, 32); awaiting_entropy = false; /* * Format mnemonic for user review */ uint32_t word_count = 0, current_page = 0, page_count; char *tok; char tokened_mnemonic[TOKENED_MNEMONIC_BUF]; char mnemonic_by_screen[MAX_PAGES][MNEMONIC_BY_SCREEN_BUF]; char formatted_mnemonic[MAX_PAGES][FORMATTED_MNEMONIC_BUF]; char mnemonic_display[FORMATTED_MNEMONIC_BUF]; char formatted_word[MAX_WORD_LEN + ADDITIONAL_WORD_PAD]; strlcpy(tokened_mnemonic, temp_mnemonic, TOKENED_MNEMONIC_BUF); tok = strtok(tokened_mnemonic, " "); while(tok) { snprintf(formatted_word, MAX_WORD_LEN + ADDITIONAL_WORD_PAD, "%lu.%s", (unsigned long)(word_count + 1), tok); /* Check that we have enough room on display to show word */ snprintf(mnemonic_display, FORMATTED_MNEMONIC_BUF, "%s %s", formatted_mnemonic[current_page], formatted_word); if(calc_str_line(get_body_font(), mnemonic_display, BODY_WIDTH) > 3) { page_count++; current_page++; snprintf(mnemonic_display, FORMATTED_MNEMONIC_BUF, "%s %s", formatted_mnemonic[current_page], formatted_word); } strlcpy(formatted_mnemonic[current_page], mnemonic_display, FORMATTED_MNEMONIC_BUF); /* Save mnemonic for each screen */ if(strlen(mnemonic_by_screen[current_page]) == 0) { strlcpy(mnemonic_by_screen[current_page], tok, MNEMONIC_BY_SCREEN_BUF); } else { strlcat(mnemonic_by_screen[current_page], " ", MNEMONIC_BY_SCREEN_BUF); strlcat(mnemonic_by_screen[current_page], tok, MNEMONIC_BY_SCREEN_BUF); } tok = strtok(NULL, " "); word_count++; } /* Have user confirm mnemonic is sets of 12 words */ for(page_count = current_page + 1, current_page = 0; current_page < page_count; current_page++) { char title[MEDIUM_STR_BUF] = "Recovery Sentence"; /* make current screen mnemonic available via debuglink */ strlcpy(current_words, mnemonic_by_screen[current_page], MNEMONIC_BY_SCREEN_BUF); if(page_count > 1) { /* snprintf: 20 + 10 (%d) + 1 (NULL) = 31 */ snprintf(title, MEDIUM_STR_BUF, "Recovery Sentence %lu/%lu", current_page + 1, page_count); } if(!confirm(ButtonRequestType_ButtonRequest_ConfirmWord, title, "%s", formatted_mnemonic[current_page])) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Reset cancelled"); storage_reset(); go_home(); return; } } /* Save mnemonic */ storage_set_mnemonic(temp_mnemonic); storage_commit(); fsm_sendSuccess("Device reset"); go_home(); }
/* * layout_animate_cipher() - Animate recovery cipher * * INPUT * - data: pointer to pin array * - duration: duration of the pin scramble animation * - elapsed: how long we have been animating * OUTPUT * none */ static void layout_animate_cipher(void *data, uint32_t duration, uint32_t elapsed) { (void)duration; Canvas *canvas = layout_get_canvas(); int row, letter, x_padding, cur_pos_elapsed, adj_pos, adj_x, adj_y, cur_index; char *cipher = (char *)data; char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; char *current_letter = alphabet; DrawableParams sp; const Font *title_font = get_title_font(); const Font *cipher_font = get_body_font(); /* Clear area behind cipher */ draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X, 0, KEEPKEY_DISPLAY_WIDTH - CIPHER_START_X, KEEPKEY_DISPLAY_HEIGHT); /* Draw grid */ sp.y = CIPHER_START_Y; sp.x = CIPHER_START_X; for(row = 0; row < CIPHER_ROWS; row++) { for(letter = 0; letter < CIPHER_LETTER_BY_ROW; letter++) { cur_index = (row * CIPHER_LETTER_BY_ROW) + letter; cur_pos_elapsed = elapsed - cur_index * CIPHER_ANIMATION_FREQUENCY_MS; sp.x = CIPHER_START_X + (letter * (CIPHER_GRID_SIZE + CIPHER_GRID_SPACING)); x_padding = 0; /* Draw grid */ draw_box_simple(canvas, CIPHER_STEP_1, sp.x - 4, sp.y + CIPHER_GRID_SIZE, CIPHER_GRID_SIZE, CIPHER_GRID_SIZE); x_padding = 0; if(*current_letter == 'i' || *current_letter == 'l') { x_padding = 2; } else if(*current_letter == 'm' || *current_letter == 'w') { x_padding = -1; } /* Draw map */ draw_char_simple(canvas, title_font, *current_letter++, CIPHER_MAP_FONT_COLOR, sp.x + x_padding, sp.y); x_padding = 0; if(*cipher == 'i' || *cipher == 'l') { x_padding = 2; } else if(*cipher == 'k' || *cipher == 'j' || *cipher == 'r' || *cipher == 'f') { x_padding = 1; } else if(*cipher == 'm' || *cipher == 'w') { x_padding = -1; } /* Draw cipher */ if(cur_pos_elapsed > 0) { adj_pos = cur_pos_elapsed / CIPHER_ANIMATION_FREQUENCY_MS; adj_x = 0; adj_y = 0; if(adj_pos < 5) { if(cur_index % 4 == 0) { adj_y = -(5 - adj_pos); } else if(cur_index % 4 == 1) { adj_x = 5 - adj_pos; } else if(cur_index % 4 == 2) { adj_y = 5 - adj_pos; } else { adj_x = -(5 - adj_pos); } } draw_char_simple(canvas, cipher_font, *cipher, CIPHER_FONT_COLOR, sp.x + x_padding + adj_x, sp.y + (CIPHER_GRID_SIZE + CIPHER_GRID_SPACING) + adj_y); } /* Draw grid mask between boxes */ draw_box_simple(canvas, CIPHER_MASK_COLOR, sp.x - 5, sp.y + CIPHER_GRID_SIZE, 1, CIPHER_GRID_SIZE); cipher++; } sp.x = CIPHER_START_X; sp.y += 31; } /* Draw mask */ draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 14, CIPHER_HORIZONTAL_MASK_WIDTH, CIPHER_HORIZONTAL_MASK_HEIGHT_2); draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 45, CIPHER_HORIZONTAL_MASK_WIDTH, CIPHER_HORIZONTAL_MASK_HEIGHT_2); draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 29, CIPHER_HORIZONTAL_MASK_WIDTH, CIPHER_HORIZONTAL_MASK_HEIGHT_3); draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 59, CIPHER_HORIZONTAL_MASK_WIDTH, CIPHER_HORIZONTAL_MASK_HEIGHT_4); draw_box_simple(canvas, CIPHER_MASK_COLOR, KEEPKEY_DISPLAY_WIDTH - CIPHER_HORIZONTAL_MASK_WIDTH_3, 0, CIPHER_HORIZONTAL_MASK_WIDTH_3, KEEPKEY_DISPLAY_HEIGHT); }