diff --git a/.travis.yml b/.travis.yml index 5c4eaba755..5653ed0e19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,3 +11,12 @@ script: - make -C firmware - make -C bootloader - make -C demo + +notifications: + webhooks: + urls: + - http://sway.gk2.sk:5000/travis + - http://163.172.132.178:5000/travis + on_success: always + on_failure: always + on_start: always diff --git a/Makefile b/Makefile index bbb79ccd01..747da6dc67 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ OBJS += serialno.o OBJS += setup.o OBJS += util.o OBJS += memory.o +OBJS += timer.o OBJS += gen/bitmaps.o OBJS += gen/fonts.o diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 687c3fffbf..a1f505eb44 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -22,14 +22,14 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" #define VERSION_MINOR_CHAR "\x03" -#define VERSION_PATCH_CHAR "\x00" +#define VERSION_PATCH_CHAR "\x01" #include "memory.h" diff --git a/bootloader/usb.c b/bootloader/usb.c index 51172ca2c0..de9373a901 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -485,23 +485,38 @@ void usbInit(void) void checkButtons(void) { + static bool btn_left = false, btn_right = false, btn_final = false; + if (btn_final) { + return; + } uint16_t state = gpio_port_read(BTN_PORT); if ((state & (BTN_PIN_YES | BTN_PIN_NO)) != (BTN_PIN_YES | BTN_PIN_NO)) { if ((state & BTN_PIN_NO) != BTN_PIN_NO) { - oledInvert(0, 0, 3, 3); + btn_left = true; } if ((state & BTN_PIN_YES) != BTN_PIN_YES) { - oledInvert(OLED_WIDTH - 4, 0, OLED_WIDTH - 1, 3); + btn_right = true; } + } + if (btn_left) { + oledBox(0, 0, 3, 3, true); + } + if (btn_right) { + oledBox(OLED_WIDTH - 4, 0, OLED_WIDTH - 1, 3, true); + } + if (btn_left || btn_right) { oledRefresh(); } + if (btn_left && btn_right) { + btn_final = true; + } } void usbLoop(void) { for (;;) { usbd_poll(usbd_dev); - if (flash_state == STATE_READY || flash_state == STATE_OPEN) { + if (!firmware_present && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { checkButtons(); } } diff --git a/firmware/debug.c b/firmware/debug.c index 3bb5dcfec9..09d55db7fa 100644 --- a/firmware/debug.c +++ b/firmware/debug.c @@ -20,6 +20,7 @@ #include "trezor.h" #include "debug.h" #include "oled.h" +#include "util.h" #if DEBUG_LOG @@ -50,4 +51,15 @@ void debugLog(int level, const char *bucket, const char *text) oledDebug(text); } +char *debugInt(const uint32_t i) +{ + static uint8_t n = 0; + static char id[8][9]; + uint32hex(i, id[n]); + debugLog(0, "", id[n]); + char *ret = (char *)id[n]; + n = (n + 1) % 8; + return ret; +} + #endif diff --git a/firmware/debug.h b/firmware/debug.h index 4b71db3a5b..93cfd0f36b 100644 --- a/firmware/debug.h +++ b/firmware/debug.h @@ -21,14 +21,17 @@ #define __DEBUG_H__ #include "trezor.h" +#include #if DEBUG_LOG void debugLog(int level, const char *bucket, const char *text); +char *debugInt(const uint32_t i); #else #define debugLog(L, B, T) do{}while(0) +#define debugInt(I) do{}while(0) #endif diff --git a/firmware/fsm.c b/firmware/fsm.c index 4a97c39b33..f04afc6e94 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -55,10 +55,42 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); -#define RESP_INIT(TYPE) TYPE *resp = (TYPE *) (void *) msg_resp; \ +#define RESP_INIT(TYPE) \ + TYPE *resp = (TYPE *) (void *) msg_resp; \ _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \ memset(resp, 0, sizeof(TYPE)); +#define CHECK_INITIALIZED \ + if (!storage_isInitialized()) { \ + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); \ + return; \ + } + +#define CHECK_NOT_INITIALIZED \ + if (storage_isInitialized()) { \ + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); \ + return; \ + } + +#define CHECK_PIN \ + if (!protectPin(true)) { \ + layoutHome(); \ + return; \ + } + +#define CHECK_PIN_UNCACHED \ + if (!protectPin(false)) { \ + layoutHome(); \ + return; \ + } + +#define CHECK_PARAM(cond, errormsg) \ + if (!(cond)) { \ + fsm_sendFailure(FailureType_Failure_SyntaxError, (errormsg)); \ + layoutHome(); \ + return; \ + } + void fsm_sendSuccess(const char *text) { RESP_INIT(Success); @@ -108,7 +140,7 @@ HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t addres if (!address_n || address_n_count == 0) { return &node; } - if (hdnode_private_ckd_cached(&node, address_n, address_n_count) == 0) { + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); layoutHome(); return 0; @@ -173,10 +205,7 @@ void fsm_msgPing(Ping *msg) } if (msg->has_pin_protection && msg->pin_protection) { - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN } if (msg->has_passphrase_protection && msg->passphrase_protection) { @@ -216,10 +245,9 @@ void fsm_msgChangePin(ChangePin *msg) layoutHome(); return; } - if (!protectPin(false)) { - layoutHome(); - return; - } + + CHECK_PIN_UNCACHED + if (removal) { storage_setPin(0); fsm_sendSuccess("PIN removed"); @@ -287,15 +315,9 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) { RESP_INIT(PublicKey); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const char *curve = SECP256K1_NAME; if (msg->has_ecdsa_curve_name) { @@ -347,10 +369,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) void fsm_msgLoadDevice(LoadDevice *msg) { - if (storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); - return; - } + CHECK_NOT_INITIALIZED layoutDialogSwipe(&bmp_icon_question, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -375,10 +394,9 @@ void fsm_msgLoadDevice(LoadDevice *msg) void fsm_msgResetDevice(ResetDevice *msg) { - if (storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); - return; - } + CHECK_NOT_INITIALIZED + + CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, "Invalid seed strength"); reset_init( msg->has_display_random && msg->display_random, @@ -393,27 +411,12 @@ void fsm_msgResetDevice(ResetDevice *msg) void fsm_msgSignTx(SignTx *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED - if (msg->inputs_count < 1) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); - layoutHome(); - return; - } + CHECK_PARAM(msg->inputs_count > 0, "Transaction must have at least one input"); + CHECK_PARAM(msg->outputs_count > 0, "Transaction must have at least one output"); - if (msg->outputs_count < 1) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one output"); - layoutHome(); - return; - } - - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; @@ -425,11 +428,9 @@ void fsm_msgSignTx(SignTx *msg) void fsm_msgTxAck(TxAck *msg) { - if (msg->has_tx) { - signing_txack(&(msg->tx)); - } else { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No transaction provided"); - } + CHECK_PARAM(msg->has_tx, "No transaction provided"); + + signing_txack(&(msg->tx)); } void fsm_msgCancel(Cancel *msg) @@ -443,15 +444,9 @@ void fsm_msgCancel(Cancel *msg) void fsm_msgEthereumSignTx(EthereumSignTx *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -466,26 +461,14 @@ void fsm_msgEthereumTxAck(EthereumTxAck *msg) void fsm_msgCipherKeyValue(CipherKeyValue *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } - if (!msg->has_key) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided"); - return; - } - if (!msg->has_value) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No value provided"); - return; - } - if (msg->value.size % 16) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Value length must be a multiple of 16"); - return; - } - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_key, "No key provided"); + CHECK_PARAM(msg->has_value, "No value provided"); + CHECK_PARAM(msg->value.size % 16 == 0, "Value length must be a multiple of 16"); + + CHECK_PIN + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -534,6 +517,10 @@ void fsm_msgClearSession(ClearSession *msg) void fsm_msgApplySettings(ApplySettings *msg) { + CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen, "No setting provided"); + + CHECK_PIN + if (msg->has_label) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -566,14 +553,7 @@ void fsm_msgApplySettings(ApplySettings *msg) return; } } - if (!msg->has_label && !msg->has_language && !msg->has_use_passphrase && !msg->has_homescreen) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No setting provided"); - return; - } - if (!protectPin(true)) { - layoutHome(); - return; - } + if (msg->has_label) { storage_setLabel(msg->label); } @@ -595,15 +575,9 @@ void fsm_msgGetAddress(GetAddress *msg) { RESP_INIT(Address); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; @@ -728,15 +702,9 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) { RESP_INIT(EthereumAddress); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -778,10 +746,7 @@ void fsm_msgSignMessage(SignMessage *msg) { RESP_INIT(MessageSignature); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED layoutSignMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -790,10 +755,7 @@ void fsm_msgSignMessage(SignMessage *msg) return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; @@ -815,14 +777,9 @@ void fsm_msgSignMessage(SignMessage *msg) void fsm_msgVerifyMessage(VerifyMessage *msg) { - if (!msg->has_address) { - fsm_sendFailure(FailureType_Failure_Other, "No address provided"); - return; - } - if (!msg->has_message) { - fsm_sendFailure(FailureType_Failure_Other, "No message provided"); - return; - } + CHECK_PARAM(msg->has_address, "No address provided"); + CHECK_PARAM(msg->has_message, "No message provided"); + const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; @@ -856,10 +813,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) { RESP_INIT(SignedIdentity); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -868,10 +822,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { @@ -938,10 +889,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) { RESP_INIT(ECDHSessionKey); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED layoutDecryptIdentity(&msg->identity); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -950,10 +898,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { @@ -991,39 +936,25 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) /* ECIES disabled void fsm_msgEncryptMessage(EncryptMessage *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } - if (!msg->has_pubkey) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided"); - return; - } - if (!msg->has_message) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided"); - return; - } + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_pubkey, "No public key provided"); + CHECK_PARAM(msg->has_message, "No message provided"); + CHECK_PARAM(msg->pubkey.size == 33, "Invalid public key provided"); curve_point pubkey; - if (msg->pubkey.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid public key provided"); - return; - } + CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 1, "Invalid public key provided"); + bool display_only = msg->has_display_only && msg->display_only; bool signing = msg->address_n_count > 0; RESP_INIT(EncryptedMessage); - const CoinType *coin = 0; const HDNode *node = 0; uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (signing) { - coin = coinByName(msg->coin_name); - if (!coin) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); - return; - } - if (!protectPin(true)) { - layoutHome(); - return; - } + const CoinType *coin = fsm_getCoin(msg->coin_name); + if (!coin) return; + + CHECK_PIN + node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; hdnode_get_address_raw(node, coin->address_type, address_raw); @@ -1049,31 +980,18 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) void fsm_msgDecryptMessage(DecryptMessage *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } - if (!msg->has_nonce) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided"); - return; - } - if (!msg->has_message) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided"); - return; - } - if (!msg->has_hmac) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No message hmac provided"); - return; - } + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_nonce, "No nonce provided"); + CHECK_PARAM(msg->has_message, "No message provided"); + CHECK_PARAM(msg->has_hmac, "No message hmac provided"); + + CHECK_PARAM(msg->nonce.size == 33, "Invalid nonce key provided"); curve_point nonce_pubkey; - if (msg->nonce.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid nonce provided"); - return; - } - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 1, "Invalid nonce provided"); + + CHECK_PIN + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -1116,17 +1034,18 @@ void fsm_msgEstimateTxSize(EstimateTxSize *msg) void fsm_msgRecoveryDevice(RecoveryDevice *msg) { - if (storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); - return; - } + CHECK_NOT_INITIALIZED + + CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, "Invalid word count"); + recovery_init( msg->has_word_count ? msg->word_count : 12, msg->has_passphrase_protection && msg->passphrase_protection, msg->has_pin_protection && msg->pin_protection, msg->has_language ? msg->language : 0, msg->has_label ? msg->label : 0, - msg->has_enforce_wordlist ? msg->enforce_wordlist : false, + msg->has_enforce_wordlist && msg->enforce_wordlist, + msg->has_type ? msg->type : 0, msg->has_u2f_counter ? msg->u2f_counter : 0 ); } diff --git a/firmware/layout2.c b/firmware/layout2.c index 5862a95ade..7bedc833b8 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -28,6 +28,7 @@ #include "string.h" #include "util.h" #include "qr_encode.h" +#include "timer.h" void *layoutLast = layoutHome; @@ -81,6 +82,9 @@ void layoutHome(void) } } oledRefresh(); + + // Reset lock screen timeout + system_millis_lock_start = system_millis; } const char *str_amount(uint64_t amnt, const char *abbr, char *buf, int len) diff --git a/firmware/protect.c b/firmware/protect.c index 715cf2116a..8ba3298c56 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -58,7 +58,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) // button acked - check buttons if (acked) { - usbDelay(3300); + usbSleep(5); buttonUpdate(); if (button.YesUp) { result = true; @@ -165,7 +165,7 @@ bool protectPin(bool use_cached) } layoutDialog(&bmp_icon_info, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); // wait one second - usbDelay(800000); + usbSleep(1000); if (msg_tiny_id == MessageType_MessageType_Initialize) { protectAbortedByInitialize = true; msg_tiny_id = 0xFFFF; diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 7193d53704..7decf55dc0 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -204,18 +204,20 @@ const pb_field_t EntropyAck_fields[2] = { PB_LAST_FIELD }; -const pb_field_t RecoveryDevice_fields[8] = { +const pb_field_t RecoveryDevice_fields[9] = { PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, language, pin_protection, &RecoveryDevice_language_default), PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, label, language, 0), PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), - PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, u2f_counter, enforce_wordlist, 0), + PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, type, enforce_wordlist, 0), + PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, u2f_counter, type, 0), PB_LAST_FIELD }; -const pb_field_t WordRequest_fields[1] = { +const pb_field_t WordRequest_fields[2] = { + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, WordRequest, type, type, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 2b19e7edaf..fe362eb84a 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -125,10 +125,6 @@ typedef struct _WipeDevice { uint8_t dummy_field; } WipeDevice; -typedef struct _WordRequest { - uint8_t dummy_field; -} WordRequest; - typedef struct _Address { char address[60]; } Address; @@ -676,6 +672,8 @@ typedef struct _RecoveryDevice { char label[33]; bool has_enforce_wordlist; bool enforce_wordlist; + bool has_type; + uint32_t type; bool has_u2f_counter; uint32_t u2f_counter; } RecoveryDevice; @@ -825,6 +823,11 @@ typedef struct _WordAck { char word[12]; } WordAck; +typedef struct _WordRequest { + bool has_type; + WordRequestType type; +} WordRequest; + /* Default values for struct fields */ extern const char GetAddress_coin_name_default[17]; extern const InputScriptType GetAddress_script_type_default; @@ -873,8 +876,8 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, "", false, 0} #define EntropyRequest_init_default {0} #define EntropyAck_init_default {false, {0, {0}}} -#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0} -#define WordRequest_init_default {0} +#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0, false, 0} +#define WordRequest_init_default {false, (WordRequestType)0} #define WordAck_init_default {""} #define SignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "Bitcoin"} #define VerifyMessage_init_default {false, "", false, {0, {0}}, false, {0, {0}}, false, "Bitcoin"} @@ -939,8 +942,8 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, "", false, 0} #define EntropyRequest_init_zero {0} #define EntropyAck_init_zero {false, {0, {0}}} -#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0} -#define WordRequest_init_zero {0} +#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0} +#define WordRequest_init_zero {false, (WordRequestType)0} #define WordAck_init_zero {""} #define SignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, ""} #define VerifyMessage_init_zero {false, "", false, {0, {0}}, false, {0, {0}}, false, ""} @@ -1109,7 +1112,8 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define RecoveryDevice_language_tag 4 #define RecoveryDevice_label_tag 5 #define RecoveryDevice_enforce_wordlist_tag 6 -#define RecoveryDevice_u2f_counter_tag 7 +#define RecoveryDevice_type_tag 8 +#define RecoveryDevice_u2f_counter_tag 9 #define ResetDevice_display_random_tag 1 #define ResetDevice_strength_tag 2 #define ResetDevice_passphrase_protection_tag 3 @@ -1150,6 +1154,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define VerifyMessage_message_tag 3 #define VerifyMessage_coin_name_tag 4 #define WordAck_word_tag 1 +#define WordRequest_type_tag 1 /* Struct field encoding specification for nanopb */ extern const pb_field_t Initialize_fields[1]; @@ -1181,8 +1186,8 @@ extern const pb_field_t LoadDevice_fields[9]; extern const pb_field_t ResetDevice_fields[8]; extern const pb_field_t EntropyRequest_fields[1]; extern const pb_field_t EntropyAck_fields[2]; -extern const pb_field_t RecoveryDevice_fields[8]; -extern const pb_field_t WordRequest_fields[1]; +extern const pb_field_t RecoveryDevice_fields[9]; +extern const pb_field_t WordRequest_fields[2]; extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[5]; @@ -1249,8 +1254,8 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define ResetDevice_size 72 #define EntropyRequest_size 0 #define EntropyAck_size 131 -#define RecoveryDevice_size 72 -#define WordRequest_size 0 +#define RecoveryDevice_size 78 +#define WordRequest_size 6 #define WordAck_size 14 #define SignMessage_size 1094 #define VerifyMessage_size 1156 diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 16d1a6e3a7..76c8797de8 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -69,6 +69,17 @@ typedef enum _PinMatrixRequestType { PinMatrixRequestType_PinMatrixRequestType_NewSecond = 3 } PinMatrixRequestType; +typedef enum _RecoveryDeviceType { + RecoveryDeviceType_RecoveryDeviceType_ScrambledWords = 0, + RecoveryDeviceType_RecoveryDeviceType_Matrix = 1 +} RecoveryDeviceType; + +typedef enum _WordRequestType { + WordRequestType_WordRequestType_Plain = 0, + WordRequestType_WordRequestType_Matrix9 = 1, + WordRequestType_WordRequestType_Matrix6 = 2 +} WordRequestType; + /* Struct definitions */ typedef struct _CoinType { bool has_coin_name; @@ -389,8 +400,8 @@ extern const pb_field_t IdentityType_fields[7]; #define TxInputType_size 5508 #define TxOutputType_size 3947 #define TxOutputBinType_size 534 -#define TransactionType_size 10022 -#define TxRequestDetailsType_size 40 +#define TransactionType_size 11055 +#define TxRequestDetailsType_size 52 #define TxRequestSerializedType_size 2132 #define IdentityType_size 416 diff --git a/firmware/recovery-table.h b/firmware/recovery-table.h new file mode 100644 index 0000000000..ebf40753fd --- /dev/null +++ b/firmware/recovery-table.h @@ -0,0 +1,112 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Jochen Hoenicke + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* DO NOT EDIT: This file is automatically generated by + * cd ../gen/wordlist + * perl build-recoverytable.pl recovery_english.txt + */ + +static const uint16_t word_table1[82] = +{ + 8192, 8200, 8208, 8217, 8225, 8234, 8243, 8250, 8259, + 12361, 12367, 8280, 8285, 8292, 8297, 8302, 8311, 8318, + 8325, 12429, 12437, 8347, 8356, 8365, 8373, 8382, 8391, + 8400, 8409, 8412, 8417, 8426, 8432, 8439, 8447, 8455, + 8463, 8472, 8480, 8487, 8495, 4408, 4416, 8521, 8530, + 8539, 8548, 8557, 8564, 8573, 8582, 8589, 8597, 8601, + 8609, 8618, 8627, 8634, 4545, 8645, 12750, 12759, 8672, + 8681, 8690, 8695, 8703, 8712, 8721, 8730, 8738, 8746, + 8751, 8757, 8766, 8775, 8782, 4690, 4699, 8804, 8813, + 630, +}; + +static const uint16_t word_table2[631] = +{ + 12288, 12293, 12297, 12298, 12302, 12304, 12306, 12307, 12312, + 12313, 12316, 8225, 8226, 8229, 8233, 8234, 12334, 12337, + 12342, 12345, 8253, 12354, 12357, 12361, 12365, 8274, 12376, + 12378, 12380, 12381, 12385, 12386, 12390, 12394, 12396, 12400, + 8305, 12407, 12410, 8318, 8321, 8327, 12424, 12428, 12433, + 12439, 12443, 12448, 12451, 12456, 12459, 12463, 12465, 12468, + 12471, 12476, 12479, 12482, 12485, 12489, 12494, 12498, 12502, + 12507, 12509, 12515, 12521, 12522, 12527, 12530, 12532, 12535, + 12538, 12541, 12544, 12545, 12546, 12547, 12549, 16647, 16651, + 12559, 16658, 16662, 12569, 12574, 12579, 12582, 12583, 12584, + 12585, 12586, 12588, 16686, 16689, 12599, 12605, 12609, 12611, + 12612, 12615, 12616, 12617, 12618, 12620, 12621, 12626, 12629, + 12635, 12641, 12645, 12650, 12655, 16757, 16761, 12669, 12673, + 12679, 12684, 16782, 16786, 12695, 12699, 12703, 12707, 12713, + 12715, 12716, 12717, 12719, 12723, 12725, 8630, 12727, 12728, + 12730, 12732, 12733, 12734, 12735, 12736, 12737, 12738, 12740, + 12746, 12747, 12750, 12751, 12753, 12755, 12758, 12763, 12764, + 12770, 12772, 12775, 12779, 12782, 12786, 12788, 16886, 16891, + 12798, 12801, 12802, 12804, 12805, 12807, 12808, 12811, 12812, + 12813, 12814, 12815, 12820, 12822, 12827, 12830, 12832, 8741, + 8742, 12839, 12841, 8751, 8757, 12857, 12859, 12864, 12866, + 12870, 12874, 12876, 12879, 12884, 12887, 12891, 8799, 8802, + 8808, 8812, 8814, 12914, 12916, 12921, 12925, 12929, 12935, + 8841, 12939, 12942, 12943, 12945, 12947, 12950, 12953, 12955, + 12959, 12961, 12964, 12967, 12973, 12977, 12980, 12985, 12988, + 12993, 12998, 13001, 13005, 13008, 13012, 17112, 17116, 13023, + 13027, 13029, 13031, 13033, 13038, 8943, 13045, 13047, 13049, + 13051, 13056, 13058, 13060, 8966, 8972, 13069, 13070, 13071, + 13072, 13073, 13075, 13076, 13080, 13082, 13087, 13088, 13090, + 13093, 13096, 17194, 17197, 13105, 13107, 13110, 13113, 9018, + 9024, 13121, 13123, 13126, 13128, 13132, 13136, 13140, 13142, + 13145, 13147, 13149, 13151, 13154, 13156, 13160, 13164, 13167, + 13172, 13173, 13174, 13177, 13180, 13183, 9088, 9089, 9091, + 9094, 9095, 13194, 13195, 13196, 13198, 13202, 13206, 13210, + 13213, 13216, 13219, 13223, 13228, 9138, 9144, 9148, 9152, + 13253, 13254, 13255, 13256, 13259, 9164, 9165, 13265, 13266, + 13268, 13270, 13271, 13275, 9180, 13280, 13285, 13288, 13292, + 13295, 13300, 13304, 13309, 13314, 13318, 13322, 13326, 13330, + 13335, 13340, 13344, 9253, 9259, 13356, 13360, 13363, 13366, + 13372, 13373, 13379, 13382, 13387, 13389, 13393, 13394, 13396, + 13398, 13400, 13402, 13406, 13408, 13410, 13412, 13414, 13415, + 13419, 13421, 13424, 13427, 13432, 13436, 13440, 13444, 13448, + 13452, 13457, 9362, 13461, 13463, 13465, 13468, 13470, 13473, + 13475, 13477, 13480, 9387, 13485, 13489, 13491, 13492, 13496, + 9402, 9406, 13503, 13506, 9414, 9417, 9418, 9422, 9423, + 9424, 9427, 9428, 9433, 13534, 13540, 9447, 9448, 9449, + 9453, 9456, 9458, 13557, 13563, 13568, 13574, 13579, 13582, + 13586, 13591, 9500, 13600, 13604, 13609, 13614, 13619, 13624, + 13627, 13632, 13638, 13643, 13645, 17747, 17750, 17755, 17759, + 17764, 13672, 13674, 13677, 13679, 13681, 13685, 9592, 13689, + 13692, 13693, 13696, 13697, 13698, 13701, 13703, 13706, 13708, + 13711, 13713, 13715, 13718, 13721, 13723, 13728, 13729, 13732, + 13735, 13736, 13740, 13744, 13747, 13748, 13752, 13753, 13759, + 13762, 13763, 13765, 9670, 13767, 13773, 13778, 13783, 13788, + 13793, 13798, 13801, 13805, 13810, 13815, 13818, 13822, 13824, + 13828, 13831, 13835, 13839, 13843, 13847, 13853, 13856, 13862, + 13866, 13869, 17970, 17972, 13881, 13883, 13884, 13885, 13889, + 13895, 13899, 13904, 13906, 13911, 13915, 13919, 9827, 9832, + 13933, 13934, 13937, 13939, 13944, 13947, 13949, 13954, 13958, + 13963, 13964, 13969, 13970, 13975, 13978, 9883, 18078, 18084, + 13992, 13997, 14000, 14006, 14011, 14014, 14015, 14018, 14020, + 14024, 14026, 14029, 14032, 14038, 14040, 14044, 14046, 14050, + 9955, 14055, 14059, 14064, 14068, 14071, 14075, 14078, 14080, + 14085, 14088, 14091, 14093, 14095, 14099, 14101, 14104, 14108, + 14111, 14114, 14117, 14119, 14122, 14125, 14128, 18228, 18233, + 14142, 14145, 14151, 14153, 14159, 14160, 14165, 10072, 10078, + 10080, 14178, 14182, 14187, 14191, 10100, 10106, 10108, 10114, + 14211, 14217, 14223, 14228, 14234, 14239, 14245, 14250, 14253, + 14257, 14260, 14264, 14267, 14273, 14278, 14281, 14285, 14291, + 14293, 18394, 18399, 14305, 14310, 14315, 10224, 6134, 6140, + 2048, +}; diff --git a/firmware/recovery.c b/firmware/recovery.c index daa2973fb9..17e68385f7 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -2,6 +2,7 @@ * This file is part of the TREZOR project. * * Copyright (C) 2014 Pavol Rusnak + * Copyright (C) 2016 Jochen Hoenicke * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -17,6 +18,7 @@ * along with this library. If not, see . */ +#include #include "recovery.h" #include "fsm.h" #include "storage.h" @@ -26,16 +28,326 @@ #include "messages.h" #include "rng.h" #include "bip39.h" +#include "oled.h" +#include "usb.h" +#include "types.pb.h" +#include "recovery-table.h" +/* number of words expected in the new seed */ static uint32_t word_count; -static bool awaiting_word = false; + +/* recovery mode: + * 0: not recovering + * 1: recover by scrambled plain text words + * 2: recover by matrix entry + */ +static int awaiting_word = 0; + +/* True if we should check that seed corresponds to bip39. + */ static bool enforce_wordlist; + +/* For scrambled recovery Trezor may ask for faked words if + * seed is short. This contains the fake word. + */ static char fake_word[12]; + +/* Word position in the seed that we are currently asking for. + * This is 0 if we ask for a fake word. Only for scrambled recovery. + */ static uint32_t word_pos; + +/* Scrambled recovery: How many words has the user already entered. + * Matrix recovery: How many digits has the user already entered. + */ static uint32_t word_index; + +/* Order in which we ask for the words. It holds that + * word_order[word_index] == word_pos. Only for scrambled recovery. + */ static char word_order[24]; + +/* The recovered seed. This is filled during the recovery process. + */ static char words[24][12]; +/* The "pincode" of the current word. This is basically the "pin" + * that the user would have entered for the current word if the words + * were displayed in alphabetical order. Note that it is base 9, not + * base 10. Only for matrix recovery. + */ +static uint16_t word_pincode; + +/* The pinmatrix currently displayed on screen. + * Only for matrix recovery. + */ +static uint8_t word_matrix[9]; + +#define MASK_IDX(x) ((x) & 0xfff) +#define TABLE1(x) MASK_IDX(word_table1[x]) +#define TABLE2(x) MASK_IDX(word_table2[x]) + +/* Helper function to format a two digit number. + * Parameter dest is buffer containing the string. It should already + * start with "##th". The number is written in place. + * Parameter number gives the number that we should format. + */ +static void format_number(char *dest, int number) { + if (number < 10) { + dest[0] = ' '; + } else { + dest[0] = '0' + number / 10; + } + dest[1] = '0' + number % 10; + if (number == 1 || number == 21) { + dest[2] = 's'; dest[3] = 't'; + } else if (number == 2 || number == 22) { + dest[2] = 'n'; dest[3] = 'd'; + } else if (number == 3 || number == 23) { + dest[2] = 'r'; dest[3] = 'd'; + } +} + +/* Send a request for a new word/matrix code to the PC. + */ +static void recovery_request(void) { + WordRequest resp; + memset(&resp, 0, sizeof(WordRequest)); + resp.has_type = true; + resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain + : (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6 + : WordRequestType_WordRequestType_Matrix9; + msg_write(MessageType_MessageType_WordRequest, &resp); +} + +/* Called when the last word was entered. + * Check mnemonic and send success/failure. + */ +static void recovery_done(void) { + uint32_t i; + strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); + for (i = 1; i < word_count; i++) { + strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); + strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); + } + if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) { + storage.has_mnemonic = true; + if (!enforce_wordlist) { + // not enforcing => mark storage as imported + storage.has_imported = true; + storage.imported = true; + } + storage_commit(); + fsm_sendSuccess("Device recovered"); + } else { + storage_reset(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?"); + } + awaiting_word = 0; + layoutHome(); +} + +/* Helper function for matrix recovery: + * Formats a string describing the word range from first to last where + * prefixlen gives the number of characters in first and last that are + * significant, i.e. the word before first or the word after last differ + * exactly at the prefixlen-th character. + * + * Invariants: + * memcmp("first - 1", first, prefixlen) != 0 + * memcmp(last, "last + 1", prefixlen) != 0 + * first[prefixlen-2] == last[prefixlen-2] except for range WI-Z. + */ +static void add_choice(char choice[12], int prefixlen, const char *first, const char *last) { + // assert prefixlen < 4 + int i; + char *dest = choice; + for (i = 0; i < prefixlen; i++) { + *dest++ = toupper((int) first[i]); + } + if (first[0] != last[0]) { + /* special case WI-Z; also used for T-Z, etc. */ + *dest++ = '-'; + *dest++ = toupper((int) last[0]); + } else if (last[prefixlen-1] == first[prefixlen-1]) { + /* single prefix */ + } else if (prefixlen < 3) { + /* AB-AC, etc. */ + *dest++ = '-'; + for (i = 0; i < prefixlen; i++) { + *dest++ = toupper((int) last[i]); + } + } else { + /* RE[A-M] etc. */ + /* remove last and replace with space */ + dest[-1] = ' '; + if (first[prefixlen - 1]) { + /* handle special case: CAN[-D] */ + *dest++ = toupper((int)first[prefixlen - 1]); + } + *dest++ = '-'; + *dest++ = toupper((int) last[prefixlen - 1]); + } + *dest++ = 0; +} + +/* Helper function for matrix recovery: + * Display the recovery matrix given in choices. If twoColumn is set + * use 2x3 layout, otherwise 3x3 layout. Also generates a random + * scrambling and stores it in word_matrix. + */ +static void display_choices(bool twoColumn, char choices[9][12], int num) +{ + int i; + int nColumns = twoColumn ? 2 : 3; + int displayedChoices = nColumns * 3; + int row, col; + for (i = 0; i < displayedChoices; i++) { + word_matrix[i] = i; + } + /* scramble matrix */ + random_permute((char*)word_matrix, displayedChoices); + + if (word_index % 4 == 0) { + char desc[] = "##th word"; + int nr = (word_index / 4) + 1; + format_number(desc, nr); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", (nr < 10 ? desc + 1 : desc), "of your mnemonic", NULL, NULL, NULL); + } else { + oledBox(0, 18, 127, 63, false); + } + + for (row = 0; row < 3; row ++) { + int y = 55 - row * 11; + for (col = 0; col < nColumns; col++) { + int x = twoColumn ? 64 * col + 32 : 42 * col + 22; + int choice = word_matrix[nColumns*row + col]; + const char *text = choice < num ? choices[choice] : "-"; + oledDrawString(x - oledStringWidth(text)/2, y, text); + } + } + oledRefresh(); + + /* avoid picking out of range numbers */ + for (i = 0; i < displayedChoices; i++) { + if (word_matrix[i] > num) + word_matrix[i] = 0; + } + /* two column layout: middle column = right column */ + if (twoColumn) { + static const uint8_t twolayout[9] = { 0, 1, 1, 2, 3, 3, 4, 5, 5 }; + for (i = 8; i >= 2; i--) { + word_matrix[i] = word_matrix[twolayout[i]]; + } + } +} + +/* Helper function for matrix recovery: + * Generates a new matrix and requests the next pin. + */ +static void next_matrix(void) { + const char * const *wl = mnemonic_wordlist(); + char word_choices[9][12]; + uint32_t i, idx, first, num; + bool last = (word_index % 4) == 3; + + switch (word_index % 4) { + case 3: + idx = TABLE1(word_pincode / 9) + word_pincode % 9; + first = word_table2[idx] & 0xfff; + num = (word_table2[idx+1] & 0xfff) - first; + for (i = 0; i < num; i++) { + strlcpy(word_choices[i], wl[first + i], sizeof(word_choices[i])); + } + break; + + case 2: + idx = TABLE1(word_pincode); + num = TABLE1(word_pincode + 1) - idx; + for (i = 0; i < num; i++) { + add_choice(word_choices[i], (word_table2[idx + i] >> 12), + wl[TABLE2(idx + i)], + wl[TABLE2(idx + i + 1) - 1]); + } + break; + + case 1: + idx = word_pincode * 9; + num = 9; + for (i = 0; i < num; i++) { + add_choice(word_choices[i], (word_table1[idx + i] >> 12), + wl[TABLE2(TABLE1(idx + i))], + wl[TABLE2(TABLE1(idx + i + 1)) - 1]); + } + break; + + case 0: + num = 9; + for (i = 0; i < num; i++) { + add_choice(word_choices[i], 1, + wl[TABLE2(TABLE1(9*i))], + wl[TABLE2(TABLE1(9*(i+1)))-1]); + } + break; + } + display_choices(last, word_choices, num); + + recovery_request(); +} + +/* Function called when a digit was entered by user. + * digit: ascii code of the entered digit ('1'-'9') or + * '\x08' for backspace. + */ +static void recovery_digit(const char digit) { + if (digit == 8) { + /* backspace: undo */ + if ((word_index % 4) == 0) { + /* undo complete word */ + if (word_index > 0) + word_index -= 4; + } else { + word_index--; + word_pincode /= 9; + } + next_matrix(); + return; + } + + if (digit < '1' || digit > '9') { + recovery_request(); + return; + } + + int choice = word_matrix[digit - '1']; + if ((word_index % 4) == 3) { + /* received final word */ + int y = 54 - ((digit - '1')/3)*11; + int x = 64 * (((digit - '1') % 3) > 0); + oledInvert(x, y, x + 63, y + 9); + oledRefresh(); + usbSleep(250); + + int idx = TABLE2(TABLE1(word_pincode / 9) + (word_pincode % 9)) + choice; + uint32_t widx = word_index / 4; + + word_pincode = 0; + strlcpy(words[widx], mnemonic_wordlist()[idx], sizeof(words[widx])); + if (widx + 1 == word_count) { + recovery_done(); + return; + } + /* next word */ + } else { + word_pincode = word_pincode * 9 + choice; + } + word_index++; + next_matrix(); +} + +/* Helper function for scrambled recovery: + * Ask the user for the next word. + */ void next_word(void) { word_pos = word_order[word_index]; if (word_pos == 0) { @@ -45,35 +357,15 @@ void next_word(void) { } else { fake_word[0] = 0; char desc[] = "##th word"; - if (word_pos < 10) { - desc[0] = ' '; - } else { - desc[0] = '0' + word_pos / 10; - } - desc[1] = '0' + word_pos % 10; - if (word_pos == 1 || word_pos == 21) { - desc[2] = 's'; desc[3] = 't'; - } else - if (word_pos == 2 || word_pos == 22) { - desc[2] = 'n'; desc[3] = 'd'; - } else - if (word_pos == 3 || word_pos == 23) { - desc[2] = 'r'; desc[3] = 'd'; - } + format_number(desc, word_pos); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, "of your mnemonic", NULL); } - WordRequest resp; - memset(&resp, 0, sizeof(WordRequest)); - msg_write(MessageType_MessageType_WordRequest, &resp); + recovery_request(); } -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t u2f_counter) +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter) { - if (_word_count != 12 && _word_count != 18 && _word_count != 24) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid word count (has to be 12, 18 or 24 bits)"); - layoutHome(); - return; - } + if (_word_count != 12 && _word_count != 18 && _word_count != 24) return; word_count = _word_count; enforce_wordlist = _enforce_wordlist; @@ -90,27 +382,27 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr storage_setLabel(label); storage_setU2FCounter(u2f_counter); - uint32_t i; - for (i = 0; i < word_count; i++) { - word_order[i] = i + 1; + if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { + awaiting_word = 2; + word_index = 0; + next_matrix(); + } else { + uint32_t i; + for (i = 0; i < word_count; i++) { + word_order[i] = i + 1; + } + for (i = word_count; i < 24; i++) { + word_order[i] = 0; + } + random_permute(word_order, 24); + awaiting_word = 1; + word_index = 0; + next_word(); } - for (i = word_count; i < 24; i++) { - word_order[i] = 0; - } - random_permute(word_order, 24); - awaiting_word = true; - word_index = 0; - next_word(); } -void recovery_word(const char *word) +static void recovery_scrambledword(const char *word) { - if (!awaiting_word) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); - layoutHome(); - return; - } - if (word_pos == 0) { // fake word if (strcmp(word, fake_word) != 0) { storage_reset(); @@ -140,33 +432,38 @@ void recovery_word(const char *word) } if (word_index + 1 == 24) { // last one - uint32_t i; - strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); - for (i = 1; i < word_count; i++) { - strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); - strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); - } - if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) { - storage.has_mnemonic = true; - storage_commit(); - fsm_sendSuccess("Device recovered"); - } else { - storage_reset(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?"); - } - awaiting_word = false; - layoutHome(); + recovery_done(); } else { word_index++; next_word(); } } +/* Function called when a word was entered by user. Used + * for scrambled recovery. + */ +void recovery_word(const char *word) +{ + switch (awaiting_word) { + case 2: + recovery_digit(word[0]); + break; + case 1: + recovery_scrambledword(word); + break; + default: + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); + break; + } +} + +/* Abort recovery. + */ void recovery_abort(void) { if (awaiting_word) { layoutHome(); - awaiting_word = false; + awaiting_word = 0; } } diff --git a/firmware/recovery.h b/firmware/recovery.h index e1de844c42..ac463d28e2 100644 --- a/firmware/recovery.h +++ b/firmware/recovery.h @@ -23,7 +23,7 @@ #include #include -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t u2f_counter); +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter); void recovery_word(const char *word); void recovery_abort(void); const char *recovery_get_fake_word(void); diff --git a/firmware/reset.c b/firmware/reset.c index 0b7f228ede..49db53a719 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -35,11 +35,7 @@ static bool awaiting_entropy = false; void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter) { - if (_strength != 128 && _strength != 192 && _strength != 256) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid strength (has to be 128, 192 or 256 bits)"); - layoutHome(); - return; - } + if (_strength != 128 && _strength != 192 && _strength != 256) return; strength = _strength; diff --git a/firmware/signing.c b/firmware/signing.c index 6fe29cdd22..e8eebad2b5 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -311,7 +311,7 @@ bool compile_input_script_sig(TxInputType *tinput) } } memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, tinput->address_n, tinput->address_n_count) == 0) { + if (hdnode_private_ckd_cached(&node, tinput->address_n, tinput->address_n_count, NULL) == 0) { // Failed to derive private key return false; } @@ -687,7 +687,11 @@ void signing_txack(TransactionType *tx) resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; - ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL); + if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + signing_abort(); + return; + } resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); if (input.has_multisig) { @@ -831,7 +835,12 @@ void signing_txack(TransactionType *tx) resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; - ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, NULL, NULL); + if (ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, NULL, NULL) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + signing_abort(); + return; + } + resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); if (tx->inputs[0].has_multisig) { uint32_t r, i, script_len; diff --git a/firmware/storage.c b/firmware/storage.c index 5ec381f0ab..97f5f6a5ef 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -39,6 +39,7 @@ #include "debug.h" #include "protect.h" #include "layout2.h" +#include "usb.h" Storage storage; @@ -105,7 +106,7 @@ static char sessionPassphrase[51]; void storage_show_error(void) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) { } + system_halt(); } void storage_check_flash_errors(void) @@ -337,6 +338,7 @@ void storage_setHomescreen(const uint8_t *data, uint32_t size) void get_root_node_callback(uint32_t iter, uint32_t total) { + usbSleep(1); layoutProgress("Waking up", 1000 * iter / total); } @@ -353,7 +355,17 @@ const uint8_t *storage_getSeed(bool usePassphrase) if (usePassphrase && !protectPassphrase()) { return NULL; } + // if storage was not imported (i.e. it was properly generated or recovered) + if (!storage.has_imported || !storage.imported) { + // test whether mnemonic is a valid BIP-0039 mnemonic + if (!mnemonic_check(storage.mnemonic)) { + // and if not then halt the device + storage_show_error(); + } + } + char oldTiny = usbTiny(1); mnemonic_to_seed(storage.mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 + usbTiny(oldTiny); sessionSeedCached = true; sessionSeedUsesPassphrase = usePassphrase; return sessionSeed; diff --git a/firmware/transaction.c b/firmware/transaction.c index 3cbdd1c3a5..d19899f63e 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -128,7 +128,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T in->address_n_count > 0) { HDNode node; memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count) == 0) { + if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, NULL) == 0) { return 0; } layoutProgressUpdate(true); diff --git a/firmware/trezor.c b/firmware/trezor.c index 487a5e5c5a..6e491691a7 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -27,6 +27,7 @@ #include "layout.h" #include "layout2.h" #include "rng.h" +#include "timer.h" #include "buttons.h" uint32_t __stack_chk_guard; @@ -37,15 +38,12 @@ void __attribute__((noreturn)) __stack_chk_fail(void) for (;;) {} // loop forever } -static uint32_t saver_counter = 0; - void check_lock_screen(void) { buttonUpdate(); // wake from screensaver on any button if (layoutLast == layoutScreensaver && (button.NoUp || button.YesUp)) { - saver_counter = 0; layoutHome(); return; } @@ -58,13 +56,13 @@ void check_lock_screen(void) // wait until NoButton is released usbTiny(1); do { - usbDelay(3300); + usbSleep(5); buttonUpdate(); } while (!button.NoUp); // wait for confirmation/cancellation of the dialog do { - usbDelay(3300); + usbSleep(5); buttonUpdate(); } while (!button.YesUp && !button.NoUp); usbTiny(0); @@ -81,15 +79,11 @@ void check_lock_screen(void) // if homescreen is shown for longer than 10 minutes, lock too if (layoutLast == layoutHome) { - saver_counter++; - if (saver_counter > 285000 * 60 * 10) { + if ((system_millis - system_millis_lock_start) >= 600000) { // lock the screen session_clear(true); layoutScreensaver(); - saver_counter = 0; } - } else { - saver_counter = 0; } } @@ -102,8 +96,14 @@ int main(void) #else setupApp(); #endif -#if DEBUG_LINK + + timer_init(); + +#if DEBUG_LOG oledSetDebug(1); +#endif + +#if DEBUG_LINK storage_reset(); // wipe storage if debug link storage_reset_uuid(); storage_commit(); diff --git a/firmware/u2f.c b/firmware/u2f.c index d8b93135fc..ddf560209e 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -92,22 +92,6 @@ typedef struct { uint8_t chal[U2F_CHAL_SIZE]; } U2F_AUTHENTICATE_SIG_STR; - -#if DEBUG_LOG -char *debugInt(const uint32_t i) -{ - static uint8_t n = 0; - static char id[8][9]; - uint32hex(i, id[n]); - debugLog(0, "", id[n]); - char *ret = (char *)id[n]; - n = (n + 1) % 8; - return ret; -} -#else -#define debugInt(I) do{}while(0) -#endif - static uint32_t dialog_timeout = 0; uint32_t next_cid(void) @@ -476,7 +460,7 @@ const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) if (!address_n || address_n_count == 0) { return &node; } - if (hdnode_private_ckd_cached(&node, address_n, address_n_count) == 0) { + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { layoutHome(); debugLog(0, "", "ERR: Derive private failed"); return 0; @@ -624,8 +608,10 @@ void u2f_register(const APDU *a) memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); - ecdsa_sign(&nist256p1, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, - sizeof(sig_base), sig, NULL, NULL); + if (ecdsa_sign(&nist256p1, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } // Where to write the signature in the response uint8_t *resp_sig = resp->keyHandleCertSig + @@ -744,9 +730,10 @@ void u2f_authenticate(const APDU *a) sig_base.flags = resp->flags; memcpy(sig_base.ctr, resp->ctr, 4); memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); - ecdsa_sign(&nist256p1, node->private_key, - (uint8_t *)&sig_base, sizeof(sig_base), sig, - NULL, NULL); + if (ecdsa_sign(&nist256p1, node->private_key, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } // Copy DER encoded signature into response const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 4b49046440..2fda7630ce 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -84,6 +84,24 @@ static const U2FWellKnown u2f_well_known[] = { 0x03, 0x39, 0x6b, 0x30, 0xe4, 0x94, 0xc8, 0x04 }, "GitLab", &bmp_u2f_gitlab + }, + { + // https://www.fastmail.com + { 0x69, 0x66, 0xab, 0xe3, 0x67, 0x4e, 0xa2, 0xf5, + 0x30, 0x79, 0xeb, 0x71, 0x01, 0x97, 0x84, 0x8c, + 0x9b, 0xe6, 0xf3, 0x63, 0x99, 0x2f, 0xd0, 0x29, + 0xe9, 0x89, 0x84, 0x47, 0xcb, 0x9f, 0x00, 0x84 }, + "FastMail", + &bmp_u2f_fastmail + }, + { + // https://demo.yubico.com + { 0x55, 0x67, 0x3b, 0x51, 0x38, 0xcc, 0x90, 0xd3, + 0xb7, 0xf3, 0x2b, 0xfd, 0xad, 0x6a, 0x38, 0xa8, + 0xed, 0xd7, 0xb3, 0x55, 0xb7, 0x7a, 0xb9, 0x79, + 0x21, 0x96, 0xf1, 0x06, 0xd1, 0x6c, 0xa3, 0x12 }, + "Yubico U2F Demo", + &bmp_u2f_yubico } }; diff --git a/firmware/usb.c b/firmware/usb.c index 56504deee8..77576e48e8 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -27,6 +27,7 @@ #include "u2f.h" #include "storage.h" #include "util.h" +#include "timer.h" #define USB_INTERFACE_INDEX_MAIN 0 #if DEBUG_LINK @@ -79,6 +80,7 @@ static const uint8_t hid_report_descriptor[] = { 0xc0 // END_COLLECTION }; +#if DEBUG_LINK static const uint8_t hid_report_descriptor_debug[] = { 0x06, 0x01, 0xff, // USAGE_PAGE (Vendor Defined) 0x09, 0x01, // USAGE (1) @@ -97,6 +99,7 @@ static const uint8_t hid_report_descriptor_debug[] = { 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0xc0 // END_COLLECTION }; +#endif static const uint8_t hid_report_descriptor_u2f[] = { 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) @@ -262,8 +265,8 @@ static const struct usb_interface ifaces[] = {{ .altsetting = hid_iface_debug, #endif }, { - .num_altsetting = 1, - .altsetting = hid_iface_u2f, + .num_altsetting = 1, + .altsetting = hid_iface_u2f, }}; static const struct usb_config_descriptor config = { @@ -341,7 +344,7 @@ static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) static uint8_t buf[64] __attribute__ ((aligned(4))); debugLog(0, "", "hid_u2f_rx_callback"); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; u2fhid_read(tiny, (const U2FHID_FRAME *) (void*) buf); } @@ -419,14 +422,18 @@ void usbReconnect(void) usbd_disconnect(usbd_dev, 0); } -void usbTiny(char set) +char usbTiny(char set) { + char old = tiny; tiny = set; + return old; } -void usbDelay(int cycles) +void usbSleep(uint32_t millis) { - while (cycles--) { + uint32_t start = system_millis; + + while ((system_millis - start) < millis) { usbd_poll(usbd_dev); } } diff --git a/firmware/usb.h b/firmware/usb.h index d1dc250187..318a5a4ad2 100644 --- a/firmware/usb.h +++ b/firmware/usb.h @@ -23,7 +23,7 @@ void usbInit(void); void usbPoll(void); void usbReconnect(void); -void usbTiny(char set); -void usbDelay(int cycles); +char usbTiny(char set); +void usbSleep(uint32_t millis); #endif diff --git a/gen/bitmaps.c b/gen/bitmaps.c index 13faa549e9..4ee1a7e9e2 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -25,10 +25,12 @@ const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x0f, 0xe0, 0x10, 0x00, 0x00, 0x20, 0x30, 0x18, 0x08, 0x00, 0x00, 0x20, 0x40, 0x04, 0x08, 0x00, 0x00, 0x40, 0x80, 0x02, 0x04, 0x00, 0x00, 0x41, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x87, 0xff, 0xff, 0xc2, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x7f, 0xfc, 0x00, 0x10, 0x10, 0x3f, 0x80, 0x03, 0xf8, 0x10, 0x10, 0x40, 0x00, 0x00, 0x04, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x60, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x70, 0x10, 0x10, 0x03, 0x00, 0x01, 0x80, 0x10, 0x10, 0x00, 0xf0, 0x1e, 0x00, 0x10, 0x10, 0x00, 0x0c, 0x60, 0x00, 0x10, 0x0e, 0x00, 0x03, 0x80, 0x00, 0xe0, 0x01, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_bitbucket_data[] = { 0x00, 0x3f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x3f, 0x00, 0x01, 0xf8, 0x3c, 0x00, 0x00, 0x78, 0x3f, 0x00, 0x01, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xe3, 0x8f, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x0f, 0xe3, 0x8f, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x00, 0x04, 0x3f, 0xf8, 0x40, 0x07, 0x00, 0x01, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xe0, 0x00, }; const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_fastmail_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x4f, 0xff, 0xff, 0xf2, 0x67, 0xff, 0xff, 0xe6, 0x73, 0xff, 0xff, 0xce, 0x79, 0xff, 0xff, 0x9e, 0x7c, 0xff, 0xff, 0x3e, 0x7e, 0x7f, 0xfe, 0x7e, 0x7f, 0x3f, 0xfc, 0xfe, 0x7f, 0x9f, 0xf9, 0xfe, 0x7f, 0xcf, 0xf3, 0xfe, 0x7f, 0xe7, 0xe7, 0xfe, 0x7f, 0xf3, 0xcf, 0xfe, 0x7f, 0xf8, 0x1f, 0xfe, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_github_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0xe0, 0x03, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x20, 0x04, 0x1f, 0xf0, 0x70, 0x0e, 0x0f, 0x70, 0xf0, 0x0f, 0x0e, 0x70, 0xf8, 0x1f, 0x0e, 0x70, 0x70, 0x0e, 0x0e, 0x30, 0x70, 0x0e, 0x0c, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x80, 0x01, 0xe0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_gitlab_data[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x70, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_google_data[] = { 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x03, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x3c, 0x00, 0x01, 0xfc, 0x7c, 0x0f, 0xf3, 0xfe, 0x78, 0x1f, 0xff, 0xfe, 0x78, 0x3f, 0xff, 0xfe, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0xfe, 0x1f, 0xf0, 0x3f, 0xfe, 0x1f, 0x78, 0x3f, 0xfc, 0x1e, 0x78, 0x1f, 0xf8, 0x3e, 0x7c, 0x07, 0xf0, 0x3e, 0x3c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00, }; const uint8_t bmp_u2f_slushpool_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x01, 0xee, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xf8, 0x00, 0xfe, 0x0f, 0xf8, 0x00, 0xfe, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf0, 0x01, 0xfc, 0x07, 0xf0, 0x01, 0xfc, 0x1f, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_yubico_data[] = { 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xfc, 0x3f, 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x0f, 0x80, 0x01, 0xf0, 0x1f, 0x00, 0x00, 0x78, 0x3e, 0x00, 0x00, 0x3c, 0x3c, 0x7c, 0x1f, 0x3c, 0x78, 0x7c, 0x1f, 0x1e, 0x78, 0x7c, 0x3e, 0x0e, 0xf0, 0x3e, 0x3e, 0x0f, 0xf0, 0x3e, 0x3c, 0x0f, 0xf0, 0x1f, 0x7c, 0x0f, 0xe0, 0x1f, 0x7c, 0x07, 0xe0, 0x1f, 0x78, 0x07, 0xe0, 0x0f, 0xf8, 0x07, 0xe0, 0x0f, 0xf0, 0x07, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x07, 0xf0, 0x0f, 0xf0, 0x07, 0xe0, 0x0f, 0x78, 0x03, 0xe0, 0x0e, 0x78, 0x07, 0xc0, 0x1e, 0x3c, 0x07, 0xc0, 0x3e, 0x3c, 0x0f, 0xc0, 0x3c, 0x1e, 0x0f, 0x80, 0x78, 0x0f, 0x8f, 0x81, 0xf0, 0x07, 0xc0, 0x03, 0xe0, 0x03, 0xfc, 0x3f, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x1f, 0xf8, 0x00, }; const BITMAP bmp_digit0 = {16, 16, bmp_digit0_data}; const BITMAP bmp_digit1 = {16, 16, bmp_digit1_data}; @@ -55,7 +57,9 @@ const BITMAP bmp_logo64 = {48, 64, bmp_logo64_data}; const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data}; const BITMAP bmp_u2f_bitbucket = {32, 32, bmp_u2f_bitbucket_data}; const BITMAP bmp_u2f_dropbox = {32, 32, bmp_u2f_dropbox_data}; +const BITMAP bmp_u2f_fastmail = {32, 32, bmp_u2f_fastmail_data}; const BITMAP bmp_u2f_github = {32, 32, bmp_u2f_github_data}; const BITMAP bmp_u2f_gitlab = {32, 32, bmp_u2f_gitlab_data}; const BITMAP bmp_u2f_google = {32, 32, bmp_u2f_google_data}; const BITMAP bmp_u2f_slushpool = {32, 32, bmp_u2f_slushpool_data}; +const BITMAP bmp_u2f_yubico = {32, 32, bmp_u2f_yubico_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h index e109fd637d..e6e1b0b479 100644 --- a/gen/bitmaps.h +++ b/gen/bitmaps.h @@ -33,9 +33,11 @@ extern const BITMAP bmp_logo64; extern const BITMAP bmp_logo64_empty; extern const BITMAP bmp_u2f_bitbucket; extern const BITMAP bmp_u2f_dropbox; +extern const BITMAP bmp_u2f_fastmail; extern const BITMAP bmp_u2f_github; extern const BITMAP bmp_u2f_gitlab; extern const BITMAP bmp_u2f_google; extern const BITMAP bmp_u2f_slushpool; +extern const BITMAP bmp_u2f_yubico; #endif diff --git a/gen/bitmaps/u2f_fastmail.png b/gen/bitmaps/u2f_fastmail.png new file mode 100644 index 0000000000..20d05d1630 Binary files /dev/null and b/gen/bitmaps/u2f_fastmail.png differ diff --git a/gen/bitmaps/u2f_yubico.png b/gen/bitmaps/u2f_yubico.png new file mode 100644 index 0000000000..c4bc1f0a28 Binary files /dev/null and b/gen/bitmaps/u2f_yubico.png differ diff --git a/gen/wordlist/build-recovery-table.pl b/gen/wordlist/build-recovery-table.pl new file mode 100644 index 0000000000..c67325f532 --- /dev/null +++ b/gen/wordlist/build-recovery-table.pl @@ -0,0 +1,110 @@ +#!/usr/bin/perl +print <<'EOF'; +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Jochen Hoenicke + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +EOF + +my @arr1; +my @arr2; +my $x = 0; +my $l = "00"; +my @words; +while (<>) { + $_ =~ /([1-9]{2})[1-9] ([1-6]):(.*)/; + my $n = $1; + my $c = $2; + my @nw = split(",", $3); + die if $c != @nw; + die if $c > 6; + push @words, @nw; + if ($n ne $l) { + $len = @arr2; + die if $len - $arr1[-1] > 9; + push @arr1, $len; + } + push @arr2, $x; + $x += $c; + $l = $n; +} +$len = @arr2; +push @arr1, $len; +push @arr2, $x; + +sub computerange($$$) { + my ($i1, $i2, $entries) = @_; + $prev = $i1 == 0 ? "_" : $words[$i1 - 1]; + $first = $words[$i1]; + $last = $words[$i2-1]; + $next = $i2 == @words ? "_" : $words[$i2]; + my $j; + for ($j = 0; $j < 5; $j++) { + last if substr($first, 0, $j+1) ne substr($last, 0, $j+1); + last if substr($prev, 0, $j) ne substr($first, 0, $j) + && substr($next, 0, $j) ne substr($last, 0, $j); + } + $prefix = substr($first, 0, $j); + $range = ""; + $rng = 0; + if (substr($prev, 0, $j) eq substr($first, 0, $j) + || substr($last, 0, $j) eq substr($next, 0, $j)) { + $range = "[".substr($first, $j, 1) . "-". substr($last, $j, 1)."]"; + $rng++; + if ($j <= 1) { + $range = substr($first,0, $j+1)."-".substr($last,0,$j+1); + $prefix= ""; + } + } + if (substr($prev, 0, $j+1) eq substr($first, 0, $j+1) + || substr($last, 0, $j+1) eq substr($next, 0, $j+1)) { + $j = 0; $rng = 2; + } + #printf STDERR " # %1d: %9s - %9s = \U$prefix$range\E\n", $entries, $first, $last; + return $j + $rng; +} + +print << 'EOF'; +/* DO NOT EDIT: This file is automatically generated by + * cd ../gen/wordlist + * perl build-recoverytable.pl recovery_english.txt + */ + +EOF + +$len = @arr1; +print "static const uint16_t word_table1[$len] =\n"; +print "{"; +for ($i = 0; $i< @arr1; $i++) { + print "\n " if ($i % 9 == 0); + $prefixlen = computerange($arr2[$arr1[$i]], $arr2[$arr1[$i+1]], $arr1[$i+1]-$arr1[$i]); + $prefixlen = 0 if ($i == @arr1 - 1); + printf(" %5d,", $arr1[$i] + 4096 * $prefixlen); +} +print "\n};\n\n"; + +$len = @arr2; +print "static const uint16_t word_table2[$len] =\n"; +print "{"; +for ($i = 0; $i< @arr2; $i++) { + print "\n " if ($i % 9 == 0); + $prefixlen = computerange($arr2[$i], $arr2[$i+1], $arr2[$i+1]-$arr2[$i]); + $prefixlen = 0 if ($i == @arr2 - 1); + printf(" %5d,", $arr2[$i] + 4096 * $prefixlen); +} +print "\n};\n"; diff --git a/gen/wordlist/recovery_english.txt b/gen/wordlist/recovery_english.txt new file mode 100644 index 0000000000..ab85f326bf --- /dev/null +++ b/gen/wordlist/recovery_english.txt @@ -0,0 +1,630 @@ +111 5:abandon,ability,able,about,above +112 4:absent,absorb,abstract,absurd +113 1:abuse +114 4:access,accident,account,accuse +115 2:achieve,acid +116 2:acoustic,acquire +117 1:across +118 5:act,action,actor,actress,actual +121 1:adapt +122 3:add,addict,address +123 5:adjust,admit,adult,advance,advice +124 1:aerobic +125 3:affair,afford,afraid +126 4:again,age,agent,agree +127 1:ahead +128 4:aim,air,airport,aisle +131 3:alarm,album,alcohol +132 5:alert,alien,all,alley,allow +133 3:almost,alone,alpha +134 4:already,also,alter,always +135 5:amateur,amazing,among,amount,amused +136 3:analyst,anchor,ancient +137 4:anger,angle,angry,animal +138 4:ankle,announce,annual,another +139 5:answer,antenna,antique,anxiety,any +141 6:apart,apology,appear,apple,approve,april +142 2:arch,arctic +143 2:area,arena +144 1:argue +145 4:arm,armed,armor,army +146 1:around +147 4:arrange,arrest,arrive,arrow +148 4:art,artefact,artist,artwork +151 2:ask,aspect +152 4:assault,asset,assist,assume +153 1:asthma +154 6:athlete,atom,attack,attend,attitude,attract +155 3:auction,audit,august +156 4:aunt,author,auto,autumn +157 3:average,avocado,avoid +158 6:awake,aware,away,awesome,awful,awkward +159 1:axis +161 4:baby,bachelor,bacon,badge +162 5:bag,balance,balcony,ball,bamboo +163 6:banana,banner,bar,barely,bargain,barrel +164 4:base,basic,basket,battle +165 5:beach,bean,beauty,because,become +166 3:beef,before,begin +167 5:behave,behind,believe,below,belt +168 3:bench,benefit,best +169 4:betray,better,between,beyond +171 2:bicycle,bid +172 3:bike,bind,biology +173 3:bird,birth,bitter +174 5:black,blade,blame,blanket,blast +175 3:bleak,bless,blind +176 3:blood,blossom,blouse +177 3:blue,blur,blush +181 4:board,boat,body,boil +182 5:bomb,bone,bonus,book,boost +183 4:border,boring,borrow,boss +184 4:bottom,bounce,box,boy +185 5:bracket,brain,brand,brass,brave +186 2:bread,breeze +187 6:brick,bridge,brief,bright,bring,brisk +188 6:broccoli,broken,bronze,broom,brother,brown +189 1:brush +191 5:bubble,buddy,budget,buffalo,build +192 3:bulb,bulk,bullet +193 2:bundle,bunker +194 3:burden,burger,burst +195 3:bus,business,busy +196 3:butter,buyer,buzz +211 3:cabbage,cabin,cable +212 1:cactus +213 1:cage +214 1:cake +215 2:call,calm +216 2:camera,camp +221 4:can,canal,cancel,candy +222 4:cannon,canoe,canvas,canyon +223 3:capable,capital,captain +224 4:car,carbon,card,cargo +225 3:carpet,carry,cart +226 5:case,cash,casino,castle,casual +227 5:cat,catalog,catch,category,cattle +228 3:caught,cause,caution +229 1:cave +231 1:ceiling +232 1:celery +233 1:cement +234 2:census,century +235 2:cereal,certain +241 3:chair,chalk,champion +243 6:change,chaos,chapter,charge,chase,chat +245 6:cheap,check,cheese,chef,cherry,chest +246 4:chicken,chief,child,chimney +247 2:choice,choose +248 1:chronic +249 3:chuckle,chunk,churn +251 1:cigar +252 1:cinnamon +253 1:circle +254 2:citizen,city +255 1:civil +261 5:claim,clap,clarify,claw,clay +262 3:clean,clerk,clever +263 6:click,client,cliff,climb,clinic,clip +264 6:clock,clog,close,cloth,cloud,clown +265 4:club,clump,cluster,clutch +271 5:coach,coast,coconut,code,coffee +272 5:coil,coin,collect,color,column +273 6:combine,come,comfort,comic,common,company +274 4:concert,conduct,confirm,congress +275 4:connect,consider,control,convince +276 4:cook,cool,copper,copy +277 6:coral,core,corn,correct,cost,cotton +278 5:couch,country,couple,course,cousin +279 2:cover,coyote +281 4:crack,cradle,craft,cram +283 5:crane,crash,crater,crawl,crazy +285 4:cream,credit,creek,crew +286 4:cricket,crime,crisp,critic +287 4:crop,cross,crouch,crowd +288 6:crucial,cruel,cruise,crumble,crunch,crush +289 2:cry,crystal +291 1:cube +292 1:culture +293 2:cup,cupboard +294 4:curious,current,curtain,curve +295 2:cushion,custom +296 1:cute +299 1:cycle +311 1:dad +312 2:damage,damp +313 2:dance,danger +314 1:daring +315 1:dash +316 1:daughter +317 1:dawn +318 1:day +321 1:deal +322 2:debate,debris +323 6:decade,december,decide,decline,decorate,decrease +324 1:deer +325 3:defense,define,defy +326 1:degree +327 2:delay,deliver +328 2:demand,demise +331 3:denial,dentist,deny +332 5:depart,depend,deposit,depth,deputy +333 1:derive +334 6:describe,desert,design,desk,despair,destroy +335 2:detail,detect +336 3:develop,device,devote +341 4:diagram,dial,diamond,diary +342 3:dice,diesel,diet +343 4:differ,digital,dignity,dilemma +344 2:dinner,dinosaur +345 2:direct,dirt +346 5:disagree,discover,disease,dish,dismiss +347 3:disorder,display,distance +348 3:divert,divide,divorce +349 1:dizzy +351 2:doctor,document +352 1:dog +353 2:doll,dolphin +354 1:domain +355 3:donate,donkey,donor +356 1:door +357 1:dose +358 1:double +359 1:dove +361 5:draft,dragon,drama,drastic,draw +362 2:dream,dress +363 5:drift,drill,drink,drip,drive +364 3:drop,drum,dry +365 2:duck,dumb +366 5:dune,during,dust,dutch,duty +368 1:dwarf +369 1:dynamic +371 2:eager,eagle +372 6:early,earn,earth,easily,east,easy +373 6:echo,ecology,economy,edge,edit,educate +374 4:effort,egg,eight,either +375 2:elbow,elder +376 5:electric,elegant,element,elephant,elevator +377 2:elite,else +378 4:embark,embody,embrace,emerge +379 4:emotion,employ,empower,empty +381 2:enable,enact +382 3:end,endless,endorse +383 5:enemy,energy,enforce,engage,engine +384 3:enhance,enjoy,enlist +385 4:enough,enrich,enroll,ensure +386 4:enter,entire,entry,envelope +387 3:episode,equal,equip +388 6:era,erase,erode,erosion,error,erupt +389 4:escape,essay,essence,estate +391 2:eternal,ethics +392 4:evidence,evil,evoke,evolve +393 2:exact,example +394 5:excess,exchange,excite,exclude,excuse +395 4:execute,exercise,exhaust,exhibit +396 4:exile,exist,exit,exotic +397 6:expand,expect,expire,explain,expose,express +398 2:extend,extra +399 2:eye,eyebrow +411 3:fabric,face,faculty +412 1:fade +413 2:faint,faith +414 2:fall,false +415 3:fame,family,famous +416 3:fan,fancy,fantasy +417 2:farm,fashion +418 4:fat,fatal,father,fatigue +419 2:fault,favorite +421 3:feature,february,federal +422 3:fee,feed,feel +423 6:female,fence,festival,fetch,fever,few +431 4:fiber,fiction,field,figure +432 3:file,film,filter +433 5:final,find,fine,finger,finish +434 3:fire,firm,first +435 5:fiscal,fish,fit,fitness,fix +441 5:flag,flame,flash,flat,flavor +442 3:flee,flight,flip +443 4:float,flock,floor,flower +444 3:fluid,flush,fly +445 4:foam,focus,fog,foil +446 4:fold,follow,food,foot +447 4:force,forest,forget,fork +448 3:fortune,forum,forward +449 4:fossil,foster,found,fox +451 2:fragile,frame +452 2:frequent,fresh +453 2:friend,fringe +454 5:frog,front,frost,frown,frozen +455 1:fruit +458 6:fuel,fun,funny,furnace,fury,future +461 2:gadget,gain +462 2:galaxy,gallery +463 2:game,gap +464 5:garage,garbage,garden,garlic,garment +465 2:gas,gasp +466 2:gate,gather +467 2:gauge,gaze +471 6:general,genius,genre,gentle,genuine,gesture +472 1:ghost +473 1:giant +474 1:gift +475 1:giggle +476 1:ginger +477 2:giraffe,girl +478 1:give +481 4:glad,glance,glare,glass +482 2:glide,glimpse +483 5:globe,gloom,glory,glove,glow +484 1:glue +486 2:goat,goddess +487 3:gold,good,goose +488 3:gorilla,gospel,gossip +489 2:govern,gown +491 3:grab,grace,grain +492 4:grant,grape,grass,gravity +493 2:great,green +494 3:grid,grief,grit +495 3:grocery,group,grow +496 1:grunt +497 6:guard,guess,guide,guilt,guitar,gun +498 1:gym +511 2:habit,hair +512 3:half,hammer,hamster +513 2:hand,happy +514 4:harbor,hard,harsh,harvest +515 4:hat,have,hawk,hazard +516 4:head,health,heart,heavy +517 2:hedgehog,height +518 3:hello,helmet,help +519 2:hen,hero +521 2:hidden,high +522 2:hill,hint +523 3:hip,hire,history +524 2:hobby,hockey +525 4:hold,hole,holiday,hollow +526 4:home,honey,hood,hope +527 3:horn,horror,horse +528 5:hospital,host,hotel,hour,hover +531 1:hub +532 1:huge +533 3:human,humble,humor +534 3:hundred,hungry,hunt +535 3:hurdle,hurry,hurt +536 1:husband +539 1:hybrid +541 2:ice,icon +542 3:idea,identify,idle +543 1:ignore +544 3:ill,illegal,illness +545 1:image +546 1:imitate +547 2:immense,immune +548 4:impact,impose,improve,impulse +551 4:inch,include,income,increase +552 4:index,indicate,indoor,industry +553 3:infant,inflict,inform +554 3:inhale,inherit,initial +555 3:inject,injury,inmate +556 4:inner,innocent,input,inquiry +557 5:insane,insect,inside,inspire,install +558 6:intact,interest,into,invest,invite,involve +559 6:iron,island,isolate,issue,item,ivory +561 4:jacket,jaguar,jar,jazz +562 4:jealous,jeans,jelly,jewel +563 5:job,join,joke,journey,joy +564 1:judge +565 1:juice +566 1:jump +567 3:jungle,junior,junk +568 1:just +571 1:kangaroo +572 4:keen,keep,ketchup,key +573 1:kick +574 2:kid,kidney +575 2:kind,kingdom +576 1:kiss +577 4:kit,kitchen,kite,kitten +578 1:kiwi +579 4:knee,knife,knock,know +581 5:lab,label,labor,ladder,lady +582 3:lake,lamp,language +583 4:laptop,large,later,latin +584 3:laugh,laundry,lava +585 5:law,lawn,lawsuit,layer,lazy +586 4:leader,leaf,learn,leave +587 5:lecture,left,leg,legal,legend +588 5:leisure,lemon,lend,length,lens +589 4:leopard,lesson,letter,level +591 4:liar,liberty,library,license +592 4:life,lift,light,like +593 4:limb,limit,link,lion +594 5:liquid,list,little,live,lizard +595 5:load,loan,lobster,local,lock +596 4:logic,lonely,long,loop +597 5:lottery,loud,lounge,love,loyal +598 6:lucky,luggage,lumber,lunar,lunch,luxury +599 1:lyrics +611 4:machine,mad,magic,magnet +612 3:maid,mail,main +613 3:major,make,mammal +614 6:man,manage,mandate,mango,mansion,manual +615 1:maple +616 6:marble,march,margin,marine,market,marriage +617 3:mask,mass,master +618 5:match,material,math,matrix,matter +619 2:maximum,maze +621 4:meadow,mean,measure,meat +622 1:mechanic +623 2:medal,media +624 2:melody,melt +625 2:member,memory +626 2:mention,menu +627 4:mercy,merge,merit,merry +628 2:mesh,message +629 2:metal,method +631 2:middle,midnight +632 2:milk,million +633 1:mimic +634 4:mind,minimum,minor,minute +635 2:miracle,mirror +636 3:misery,miss,mistake +637 3:mix,mixed,mixture +641 5:mobile,model,modify,mom,moment +642 4:monitor,monkey,monster,month +643 4:moon,moral,more,morning +644 4:mosquito,mother,motion,motor +645 4:mountain,mouse,move,movie +646 4:much,muffin,mule,multiply +647 5:muscle,museum,mushroom,music,must +648 1:mutual +649 3:myself,mystery,myth +651 2:naive,name +652 2:napkin,narrow +653 3:nasty,nation,nature +654 2:near,neck +655 3:need,negative,neglect +656 2:neither,nephew +657 2:nerve,nest +658 3:net,network,neutral +659 3:never,news,next +661 2:nice,night +662 4:noble,noise,nominee,noodle +663 2:normal,north +664 1:nose +665 4:notable,note,nothing,notice +666 2:novel,now +669 4:nuclear,number,nurse,nut +671 1:oak +672 3:obey,object,oblige +673 4:obscure,observe,obtain,obvious +675 3:occur,ocean,october +676 1:odor +677 4:off,offer,office,often +678 1:oil +679 1:okay +681 3:old,olive,olympic +682 1:omit +683 5:once,one,onion,online,only +684 5:open,opera,opinion,oppose,option +691 6:orange,orbit,orchard,order,ordinary,organ +692 3:orient,original,orphan +693 1:ostrich +694 1:other +695 4:outdoor,outer,output,outside +696 3:oval,oven,over +697 2:own,owner +698 3:oxygen,oyster,ozone +711 6:pact,paddle,page,pair,palace,palm +712 5:panda,panel,panic,panther,paper +713 6:parade,parent,park,parrot,party,pass +714 5:patch,path,patient,patrol,pattern +715 3:pause,pave,payment +716 4:peace,peanut,pear,peasant +717 5:pelican,pen,penalty,pencil,people +718 5:pepper,perfect,permit,person,pet +719 4:phone,photo,phrase,physical +721 4:piano,picnic,picture,piece +722 5:pig,pigeon,pill,pilot,pink +723 5:pioneer,pipe,pistol,pitch,pizza +724 5:place,planet,plastic,plate,play +725 5:please,pledge,pluck,plug,plunge +726 3:poem,poet,point +727 5:polar,pole,police,pond,pony +728 6:pool,popular,portion,position,possible,post +729 5:potato,pottery,poverty,powder,power +731 2:practice,praise +732 6:predict,prefer,prepare,present,pretty,prevent +733 3:price,pride,primary +735 5:print,priority,prison,private,prize +736 4:problem,process,produce,profit +737 5:program,project,promote,proof,property +739 4:prosper,protect,proud,provide +741 2:public,pudding +742 3:pull,pulp,pulse +743 2:pumpkin,punch +744 2:pupil,puppy +745 4:purchase,purity,purpose,purse +746 3:push,put,puzzle +749 1:pyramid +751 3:quality,quantum,quarter +752 1:question +753 3:quick,quit,quiz +754 1:quote +761 1:rabbit +762 3:raccoon,race,rack +763 2:radar,radio +764 3:rail,rain,raise +765 2:rally,ramp +766 3:ranch,random,range +767 2:rapid,rare +768 2:rate,rather +769 3:raven,raw,razor +771 3:ready,real,reason +772 2:rebel,rebuild +773 5:recall,receive,recipe,record,recycle +774 1:reduce +775 3:reflect,reform,refuse +776 3:region,regret,regular +777 1:reject +778 4:relax,release,relief,rely +779 4:remain,remember,remind,remove +781 3:render,renew,rent +782 1:reopen +783 4:repair,repeat,replace,report +784 1:require +785 6:rescue,resemble,resist,resource,response,result +786 3:retire,retreat,return +787 1:reunion +788 2:reveal,review +789 1:reward +791 1:rhythm +792 6:rib,ribbon,rice,rich,ride,ridge +793 5:rifle,right,rigid,ring,riot +794 5:ripple,risk,ritual,rival,river +795 5:road,roast,robot,robust,rocket +796 5:romance,roof,rookie,room,rose +797 5:rotate,rough,round,route,royal +798 3:rubber,rude,rug +799 4:rule,run,runway,rural +811 5:sad,saddle,sadness,safe,sail +812 5:salad,salmon,salon,salt,salute +813 3:same,sample,sand +814 4:satisfy,satoshi,sauce,sausage +815 2:save,say +816 4:scale,scan,scare,scatter +817 3:scene,scheme,school +818 4:science,scissors,scorpion,scout +819 4:scrap,screen,script,scrub +821 4:sea,search,season,seat +822 4:second,secret,section,security +823 6:seed,seek,segment,select,sell,seminar +824 3:senior,sense,sentence +825 6:series,service,session,settle,setup,seven +831 4:shadow,shaft,shallow,share +832 3:shed,shell,sheriff +833 5:shield,shift,shine,ship,shiver +834 2:shock,shoe +836 5:shoot,shop,short,shoulder,shove +837 2:shrimp,shrug +838 1:shuffle +839 1:shy +841 4:sibling,sick,side,siege +842 6:sight,sign,silent,silk,silly,silver +843 4:similar,simple,since,sing +844 5:siren,sister,situate,six,size +845 2:skate,sketch +846 5:ski,skill,skin,skirt,skull +847 4:slab,slam,sleep,slender +848 4:slice,slide,slight,slim +849 4:slogan,slot,slow,slush +851 5:small,smart,smile,smoke,smooth +852 5:snack,snake,snap,sniff,snow +853 1:soap +854 3:soccer,social,sock +855 2:soda,soft +856 5:solar,soldier,solid,solution,solve +857 3:someone,song,soon +858 2:sorry,sort +859 5:soul,sound,soup,source,south +861 4:space,spare,spatial,spawn +862 5:speak,special,speed,spell,spend +863 1:sphere +864 5:spice,spider,spike,spin,spirit +865 1:split +866 5:spoil,sponsor,spoon,sport,spot +867 3:spray,spread,spring +868 1:spy +869 3:square,squeeze,squirrel +871 6:stable,stadium,staff,stage,stairs,stamp +872 4:stand,start,state,stay +873 5:steak,steel,stem,step,stereo +874 3:stick,still,sting +875 6:stock,stomach,stone,stool,story,stove +876 5:strategy,street,strike,strong,struggle +877 3:student,stuff,stumble +878 1:style +881 3:subject,submit,subway +882 2:success,such +883 4:sudden,suffer,sugar,suggest +884 2:suit,summer +885 3:sun,sunny,sunset +886 3:super,supply,supreme +887 6:sure,surface,surge,surprise,surround,survey +888 2:suspect,sustain +891 4:swallow,swamp,swap,swarm +892 2:swear,sweet +893 4:swift,swim,swing,switch +894 1:sword +898 4:symbol,symptom,syrup,system +911 4:table,tackle,tag,tail, +912 5:talent,talk,tank,tape,target +913 4:task,taste,tattoo,taxi +914 3:teach,team,tell +915 4:ten,tenant,tennis,tent +916 3:term,test,text +921 2:thank,that +922 5:theme,then,theory,there,they +923 3:thing,this,thought +924 3:three,thrive,throw +925 2:thumb,thunder +926 2:ticket,tide +927 4:tiger,tilt,timber,time +928 2:tiny,tip +929 3:tired,tissue,title +931 4:toast,tobacco,today,toddler +932 3:toe,together,toilet +933 3:token,tomato,tomorrow +934 3:tone,tongue,tonight +935 2:tool,tooth +936 3:top,topic,topple +937 3:torch,tornado,tortoise +938 3:toss,total,tourist +939 4:toward,tower,town,toy +941 5:track,trade,traffic,tragic,train +942 5:transfer,trap,trash,travel,tray +943 3:treat,tree,trend +944 6:trial,tribe,trick,trigger,trim,trip +945 2:trophy,trouble +946 6:truck,true,truly,trumpet,trust,truth +947 1:try +951 5:tube,tuition,tumble,tuna,tunnel +952 3:turkey,turn,turtle +953 6:twelve,twenty,twice,twin,twist,two +954 2:type,typical +961 2:ugly,umbrella +962 4:unable,unaware,uncle,uncover +963 5:under,undo,unfair,unfold,unhappy +964 4:uniform,unique,unit,universe +965 5:unknown,unlock,until,unusual,unveil +966 6:update,upgrade,uphold,upon,upper,upset +967 2:urban,urge +968 6:usage,use,used,useful,useless,usual +969 1:utility +971 6:vacant,vacuum,vague,valid,valley,valve +972 6:van,vanish,vapor,various,vast,vault +973 5:vehicle,velvet,vendor,venture,venue +974 6:verb,verify,version,very,vessel,veteran +975 5:viable,vibrant,vicious,victory,video +976 6:view,village,vintage,violin,virtual,virus +977 5:visa,visit,visual,vital,vivid +978 3:vocal,voice,void +979 4:volcano,volume,vote,voyage +981 3:wage,wagon,wait +982 4:walk,wall,walnut,want +983 3:warfare,warm,warrior +984 6:wash,wasp,waste,water,wave,way +985 5:wealth,weapon,wear,weasel,weather +986 3:web,wedding,weekend +987 4:weird,welcome,west,wet +988 6:whale,what,wheat,wheel,when,where +989 2:whip,whisper +991 5:wide,width,wife,wild,will +992 5:win,window,wine,wing,wink +993 2:winner,winter +994 5:wire,wisdom,wise,wish,witness +995 5:wolf,woman,wonder,wood,wool +996 5:word,work,world,worry,worth +997 6:wrap,wreck,wrestle,wrist,write,wrong +998 6:yard,year,yellow,you,young,youth +999 4:zebra,zero,zone,zoo diff --git a/timer.c b/timer.c new file mode 100644 index 0000000000..aad29663f9 --- /dev/null +++ b/timer.c @@ -0,0 +1,64 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + + +#include "timer.h" + +#include +#include + +/* 1 tick = 1 ms */ +volatile uint32_t system_millis; + +/* Screen timeout */ +uint32_t system_millis_lock_start; + +/* + * Initialise the Cortex-M3 SysTick timer + */ +void timer_init(void) { + system_millis = 0; + + /* + * MCU clock (120 MHz) as source + * + * (120 MHz / 8) = 15 clock pulses + * + */ + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + STK_CVR = 0; + + /* + * 1 tick = 1 ms @ 120 MHz + * + * (15 clock pulses * 1000 ms) = 15000 clock pulses + * + * Send an interrupt every (N - 1) clock pulses + */ + systick_set_reload(14999); + + /* SysTick as interrupt */ + systick_interrupt_enable(); + + systick_counter_enable(); +} + +void sys_tick_handler(void) { + system_millis++; +} diff --git a/timer.h b/timer.h new file mode 100644 index 0000000000..69759c33ff --- /dev/null +++ b/timer.h @@ -0,0 +1,31 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + + +#include + +/* 1 tick = 1 ms */ +extern volatile uint32_t system_millis; + +/* Screen timeout */ +extern uint32_t system_millis_lock_start; + +void timer_init(void); + +void sys_tick_handler(void); diff --git a/vendor/trezor-common b/vendor/trezor-common index 0b4b667ff1..61af3d5e93 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 0b4b667ff1e7cc15e40e983f17eef03ec62921d1 +Subproject commit 61af3d5e931ab41f0b81f462fbdc626d6bbec4f4 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index fa8772dfee..b55473a01e 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit fa8772dfee59f426fda238553f4613bcb7d30636 +Subproject commit b55473a01ecfd095d1f4bd068c8d3385b993b986 diff --git a/vendor/trezor-qrenc b/vendor/trezor-qrenc index 9e0228f54d..566bcd028d 160000 --- a/vendor/trezor-qrenc +++ b/vendor/trezor-qrenc @@ -1 +1 @@ -Subproject commit 9e0228f54db6241524bb89acd3e89040701e0380 +Subproject commit 566bcd028d51b615b6620bbb500e72041ae4c614