1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-23 14:58:09 +00:00

Merge master into segwit

This commit is contained in:
Jochen Hoenicke 2017-01-06 16:53:05 +01:00
commit 8e84a6716c
35 changed files with 1588 additions and 328 deletions

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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();
}
}

View File

@ -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

View File

@ -21,14 +21,17 @@
#define __DEBUG_H__
#include "trezor.h"
#include <stdint.h>
#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

View File

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

View File

@ -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)

View File

@ -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;

View File

@ -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
};

View File

@ -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

View File

@ -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

112
firmware/recovery-table.h Normal file
View File

@ -0,0 +1,112 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/* 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,
};

View File

@ -2,6 +2,7 @@
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
* Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#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;
}
}

View File

@ -23,7 +23,7 @@
#include <stdint.h>
#include <stdbool.h>
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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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
}
};

View File

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

View File

@ -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

View File

@ -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};

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

BIN
gen/bitmaps/u2f_yubico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

View File

@ -0,0 +1,110 @@
#!/usr/bin/perl
print <<'EOF';
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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";

View File

@ -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

64
timer.c Normal file
View File

@ -0,0 +1,64 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2016 Saleem Rashid <trezor@saleemrashid.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "timer.h"
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/cm3/systick.h>
/* 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++;
}

31
timer.h Normal file
View File

@ -0,0 +1,31 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2016 Saleem Rashid <trezor@saleemrashid.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
/* 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);

@ -1 +1 @@
Subproject commit 0b4b667ff1e7cc15e40e983f17eef03ec62921d1
Subproject commit 61af3d5e931ab41f0b81f462fbdc626d6bbec4f4

@ -1 +1 @@
Subproject commit fa8772dfee59f426fda238553f4613bcb7d30636
Subproject commit b55473a01ecfd095d1f4bd068c8d3385b993b986

2
vendor/trezor-qrenc vendored

@ -1 +1 @@
Subproject commit 9e0228f54db6241524bb89acd3e89040701e0380
Subproject commit 566bcd028d51b615b6620bbb500e72041ae4c614