Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions main/amalgamated.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ void __wrap_abort(void);
#include "./assets.c"
#include "./attestation/attestation.c"
#include "./bcur.c"
#include "./bip39.c"
#ifdef CONFIG_BT_ENABLED
#include "./ble/ble.c"
#endif // CONFIG_BT_ENABLED
Expand Down
2 changes: 1 addition & 1 deletion main/bcur.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ bool bcur_parse_bip39(
}
size_t num_words = 0;
cberr = cbor_value_get_array_length(&mapItem, &num_words);
if (cberr != CborNoError || (num_words != 12 && num_words != 24) || !cbor_value_is_container(&mapItem)) {
if (cberr != CborNoError || !jade_bip39_word_count_valid(num_words) || !cbor_value_is_container(&mapItem)) {
return false;
}
CborValue arrayItem;
Expand Down
57 changes: 57 additions & 0 deletions main/bip39.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#ifndef AMALGAMATED_BUILD
#include "bip39.h"
#include "jade_wally_verify.h"

#include <wally_bip39.h>

size_t jade_bip39_entropy_len_from_word_count(const size_t nwords)
{
switch (nwords) {
case 12:
return BIP39_ENTROPY_LEN_128;
case 15:
return BIP39_ENTROPY_LEN_160;
case 18:
return BIP39_ENTROPY_LEN_192;
case 21:
return BIP39_ENTROPY_LEN_224;
case 24:
return BIP39_ENTROPY_LEN_256;
default:
return 0;
}
}

size_t jade_bip39_word_count_from_entropy_len(const size_t entropy_len)
{
switch (entropy_len) {
case BIP39_ENTROPY_LEN_128:
return 12;
case BIP39_ENTROPY_LEN_160:
return 15;
case BIP39_ENTROPY_LEN_192:
return 18;
case BIP39_ENTROPY_LEN_224:
return 21;
case BIP39_ENTROPY_LEN_256:
return 24;
default:
return 0;
}
}

bool jade_bip39_word_count_valid(const size_t nwords) { return jade_bip39_entropy_len_from_word_count(nwords) != 0; }

bool jade_bip39_mnemonic_validate(const char* mnemonic)
{
if (!mnemonic) {
return false;
}

uint8_t entropy[BIP39_ENTROPY_LEN_256];
size_t entropy_len = 0;
const int wret = bip39_mnemonic_to_bytes(NULL, mnemonic, entropy, sizeof(entropy), &entropy_len);
JADE_WALLY_VERIFY(wally_bzero(entropy, sizeof(entropy)));
return wret == WALLY_OK && jade_bip39_word_count_from_entropy_len(entropy_len) != 0;
}
#endif // AMALGAMATED_BUILD
21 changes: 21 additions & 0 deletions main/bip39.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef JADE_BIP39_H_
#define JADE_BIP39_H_

#include <stdbool.h>
#include <stddef.h>

// Jade supports the standard BIP39 English mnemonic lengths.
#define MNEMONIC_MAXWORDS 24

// The longest valid words in the English wordlist are 8 characters.
#define MNEMONIC_MAX_WORD_LEN 8

// 24 8-character words + 23 spaces + NUL = 216 bytes.
#define MNEMONIC_BUFLEN 216

size_t jade_bip39_entropy_len_from_word_count(size_t nwords);
size_t jade_bip39_word_count_from_entropy_len(size_t entropy_len);
bool jade_bip39_word_count_valid(size_t nwords);
bool jade_bip39_mnemonic_validate(const char* mnemonic);

#endif /* JADE_BIP39_H_ */
8 changes: 8 additions & 0 deletions main/button_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ typedef enum {

BTN_NEW_MNEMONIC,
BTN_NEW_MNEMONIC_12,
BTN_NEW_MNEMONIC_15,
BTN_NEW_MNEMONIC_18,
BTN_NEW_MNEMONIC_21,
BTN_NEW_MNEMONIC_24,
BTN_NEW_MNEMONIC_MORE,

BTN_MNEMONIC_PREV,
BTN_MNEMONIC_NEXT,
Expand All @@ -70,7 +74,11 @@ typedef enum {

BTN_RESTORE_MNEMONIC,
BTN_RESTORE_MNEMONIC_12,
BTN_RESTORE_MNEMONIC_15,
BTN_RESTORE_MNEMONIC_18,
BTN_RESTORE_MNEMONIC_21,
BTN_RESTORE_MNEMONIC_24,
BTN_RESTORE_MNEMONIC_MORE,
BTN_RESTORE_MNEMONIC_QR,

BTN_MNEMONIC_FINAL_WORD_EXISTING,
Expand Down
22 changes: 10 additions & 12 deletions main/keychain.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef AMALGAMATED_BUILD
#include "keychain.h"
#include "aes.h"
#include "bip39.h"
#include "jade_assert.h"
#include "jade_wally_verify.h"
#include "random.h"
Expand Down Expand Up @@ -194,8 +195,7 @@ void keychain_cache_mnemonic_entropy(const char* mnemonic)
JADE_WALLY_VERIFY(
bip39_mnemonic_to_bytes(NULL, mnemonic, mnemonic_entropy, sizeof(mnemonic_entropy), &mnemonic_entropy_len));

// Only 12 or 24 word mnemonics are supported
JADE_ASSERT(mnemonic_entropy_len == BIP39_ENTROPY_LEN_128 || mnemonic_entropy_len == BIP39_ENTROPY_LEN_256);
JADE_ASSERT(jade_bip39_word_count_from_entropy_len(mnemonic_entropy_len));
}

// Clear the network type restriction
Expand Down Expand Up @@ -270,14 +270,13 @@ void keychain_get_new_mnemonic(char** mnemonic, const size_t nwords)
{
JADE_INIT_OUT_PPTR(mnemonic);

// Support 12-word and 24-word mnemonics only
JADE_ASSERT(nwords == 12 || nwords == 24);
JADE_ASSERT(jade_bip39_word_count_valid(nwords));

// Large enough for 12 and 24 word mnemonic
// Large enough for any standard BIP39 mnemonic.
uint8_t entropy[BIP39_ENTROPY_LEN_256];
SENSITIVE_PUSH(entropy, sizeof(entropy));

const size_t entropy_len = nwords == 12 ? BIP39_ENTROPY_LEN_128 : BIP39_ENTROPY_LEN_256;
const size_t entropy_len = jade_bip39_entropy_len_from_word_count(nwords);
get_random(entropy, entropy_len);
const int wret = bip39_mnemonic_from_bytes(NULL, entropy, entropy_len, mnemonic);
SENSITIVE_POP(entropy);
Expand Down Expand Up @@ -328,8 +327,8 @@ bool keychain_derive_from_mnemonic(const char* mnemonic, const char* passphrase,
}
}

// Mnemonic must be valid
if (bip39_mnemonic_validate(NULL, mnemonic) != WALLY_OK) {
// Mnemonic must have a valid checksum and a standard BIP39 word count.
if (!jade_bip39_mnemonic_validate(mnemonic)) {
JADE_LOGE("Invalid mnemonic");
return false;
}
Expand Down Expand Up @@ -557,8 +556,7 @@ bool keychain_store(const uint8_t* aeskey, const size_t aeslen)
// 1. Get serialised data to encrypt/persist
if (mnemonic_entropy_len) {
// Use mnemonic entropy
// Only 12 or 24 word mnemonics are supported
JADE_ASSERT(mnemonic_entropy_len == BIP39_ENTROPY_LEN_128 || mnemonic_entropy_len == BIP39_ENTROPY_LEN_256);
JADE_ASSERT(jade_bip39_word_count_from_entropy_len(mnemonic_entropy_len));
JADE_ASSERT(mnemonic_entropy_len <= sizeof(mnemonic_entropy));
JADE_ASSERT(mnemonic_entropy_len < sizeof(serialized));
p_serialized_data = mnemonic_entropy;
Expand Down Expand Up @@ -613,8 +611,8 @@ bool keychain_load(const uint8_t* aeskey, const size_t aeslen)
}

// 2. Cache mnemonic entropy or deserialise keychain
if (serialized_data_len == BIP39_ENTROPY_LEN_128 || serialized_data_len == BIP39_ENTROPY_LEN_256) {
// Write mnemonic entropy - only 12 or 24 word mnemonics are supported
if (jade_bip39_word_count_from_entropy_len(serialized_data_len)) {
// Write mnemonic entropy.
memcpy(mnemonic_entropy, serialized, serialized_data_len);
mnemonic_entropy_len = serialized_data_len;
} else if (serialized_data_len == SERIALIZED_KEY_LEN) {
Expand Down
Loading