mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-23 06:48:16 +00:00
Merge master into segwit
This commit is contained in:
commit
8e84a6716c
@ -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
|
||||
|
1
Makefile
1
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
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
297
firmware/fsm.c
297
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
|
||||
);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
112
firmware/recovery-table.h
Normal 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,
|
||||
};
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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};
|
||||
|
@ -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
|
||||
|
BIN
gen/bitmaps/u2f_fastmail.png
Normal file
BIN
gen/bitmaps/u2f_fastmail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 226 B |
BIN
gen/bitmaps/u2f_yubico.png
Normal file
BIN
gen/bitmaps/u2f_yubico.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 253 B |
110
gen/wordlist/build-recovery-table.pl
Normal file
110
gen/wordlist/build-recovery-table.pl
Normal 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";
|
630
gen/wordlist/recovery_english.txt
Normal file
630
gen/wordlist/recovery_english.txt
Normal 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
64
timer.c
Normal 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
31
timer.h
Normal 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);
|
2
vendor/trezor-common
vendored
2
vendor/trezor-common
vendored
@ -1 +1 @@
|
||||
Subproject commit 0b4b667ff1e7cc15e40e983f17eef03ec62921d1
|
||||
Subproject commit 61af3d5e931ab41f0b81f462fbdc626d6bbec4f4
|
2
vendor/trezor-crypto
vendored
2
vendor/trezor-crypto
vendored
@ -1 +1 @@
|
||||
Subproject commit fa8772dfee59f426fda238553f4613bcb7d30636
|
||||
Subproject commit b55473a01ecfd095d1f4bd068c8d3385b993b986
|
2
vendor/trezor-qrenc
vendored
2
vendor/trezor-qrenc
vendored
@ -1 +1 @@
|
||||
Subproject commit 9e0228f54db6241524bb89acd3e89040701e0380
|
||||
Subproject commit 566bcd028d51b615b6620bbb500e72041ae4c614
|
Loading…
Reference in New Issue
Block a user