diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f088dc9c..f7866af1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,8 +9,7 @@ set(DBB-FIRMWARE-SOURCES aes.c - sharedsecret.c - aescbcb64.c + cipher.c base58.c base64.c pbkdf2.c diff --git a/src/aescbcb64.c b/src/aescbcb64.c deleted file mode 100644 index db584492..00000000 --- a/src/aescbcb64.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - - The MIT License (MIT) - - Copyright (c) 2015-2018 Douglas J. Bakkum - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#include -#include -#include - -#include "aescbcb64.h" -#include "hmac.h" -#include "commander.h" -#include "sharedsecret.h" -#include "memory.h" -#include "base64.h" -#include "aes.h" -#include "sha2.h" -#include "random.h" -#include "flags.h" -#include "utils.h" - -// Must free() returned value -static uint8_t *aescbcb64_init_and_encrypt(const unsigned char *in, int inlen, - int *out_len, - const uint8_t *key) -{ - int pads; - int inpadlen = inlen + N_BLOCK - inlen % N_BLOCK; - unsigned char inpad[inpadlen]; - unsigned char enc[inpadlen]; - unsigned char iv[N_BLOCK]; - uint8_t *enc_cat = malloc(sizeof(uint8_t) * (inpadlen + - N_BLOCK)); // concatenating [ iv0 | enc ] - *out_len = inpadlen + N_BLOCK; - - aes_context ctx[1]; - - // Set cipher key - memset(ctx, 0, sizeof(ctx)); - aes_set_key(key, 32, ctx); - - // PKCS7 padding - memcpy(inpad, in, inlen); - for (pads = 0; pads < N_BLOCK - inlen % N_BLOCK; pads++ ) { - inpad[inlen + pads] = (N_BLOCK - inlen % N_BLOCK); - } - - // Make a random initialization vector - if (random_bytes((uint8_t *)iv, N_BLOCK, 0) == DBB_ERROR) { - commander_fill_report(cmd_str(CMD_random), NULL, DBB_ERR_MEM_ATAES); - utils_zero(inpad, inpadlen); - utils_zero(ctx, sizeof(ctx)); - return NULL; - } - memcpy(enc_cat, iv, N_BLOCK); - - // CBC encrypt multiple blocks - aes_cbc_encrypt(inpad, enc, inpadlen / N_BLOCK, iv, ctx); - memcpy(enc_cat + N_BLOCK, enc, inpadlen); - - utils_zero(inpad, inpadlen); - utils_zero(ctx, sizeof(ctx)); - return enc_cat; -} - - -// Must free() returned value (allocated inside base64() function) -char *aescbcb64_encrypt(const unsigned char *in, int inlen, int *out_b64len, - const uint8_t *key) -{ - int out_len; - uint8_t *enc_cat = aescbcb64_init_and_encrypt(in, inlen, &out_len, key); - // base64 encoding - char *b64; - b64 = base64(enc_cat, out_len, out_b64len); - free(enc_cat); - return b64; -} - -// Encrypts a given constant char array of length inlen using the AES algorithm with CBC mode, -// appends its SHA256 HMAC and base64 encodes the result. -// -// Must free() returned value -char *aescbcb64_hmac_encrypt(const unsigned char *in, int inlen, int *out_b64len, - const uint8_t *shared_secret) -{ - uint8_t encryption_key[SHA256_DIGEST_LENGTH]; - uint8_t authentication_key[SHA256_DIGEST_LENGTH]; - - sharedsecret_derive_keys(shared_secret, encryption_key, authentication_key); - - int encrypt_len; - uint8_t *encrypted = aescbcb64_init_and_encrypt(in, - inlen, - &encrypt_len, - encryption_key); - uint8_t hmac[SHA256_DIGEST_LENGTH]; - hmac_sha256(authentication_key, SHA256_DIGEST_LENGTH, encrypted, encrypt_len, hmac); - - uint8_t authenticated_encrypted_msg[encrypt_len + SHA256_DIGEST_LENGTH]; - memcpy(authenticated_encrypted_msg, encrypted, encrypt_len); - memcpy(authenticated_encrypted_msg + encrypt_len, hmac, SHA256_DIGEST_LENGTH); - - free(encrypted); - utils_zero(encryption_key, sizeof(encryption_key)); - utils_zero(authentication_key, sizeof(authentication_key)); - char *b64 = base64(authenticated_encrypted_msg, encrypt_len + SHA256_DIGEST_LENGTH, - out_b64len); - return b64; -} - -char *aescbcb64_init_and_decrypt(uint8_t *ub64, int ub64len, int *decrypt_len, - const uint8_t *key) -{ - *decrypt_len = 0; - - // Set cipher key - aes_context ctx[1]; - memset(ctx, 0, sizeof(ctx)); - aes_set_key(key, 32, ctx); - - unsigned char dec_pad[ub64len - N_BLOCK]; - aes_cbc_decrypt(ub64 + N_BLOCK, dec_pad, ub64len / N_BLOCK - 1, ub64, ctx); - - // Strip PKCS7 padding - int padlen = dec_pad[ub64len - N_BLOCK - 1]; - if (ub64len - N_BLOCK - padlen <= 0) { - utils_zero(dec_pad, sizeof(dec_pad)); - utils_zero(ctx, sizeof(ctx)); - return NULL; - } - char *dec = malloc(ub64len - N_BLOCK - padlen + 1); // +1 for null termination - if (!dec) { - utils_zero(dec_pad, sizeof(dec_pad)); - utils_zero(ctx, sizeof(ctx)); - return NULL; - } - memcpy(dec, dec_pad, ub64len - N_BLOCK - padlen); - dec[ub64len - N_BLOCK - padlen] = '\0'; - *decrypt_len = ub64len - N_BLOCK - padlen + 1; - utils_zero(dec_pad, sizeof(dec_pad)); - utils_zero(ctx, sizeof(ctx)); - return dec; -} - -// Must free() returned value -char *aescbcb64_decrypt(const unsigned char *in, int inlen, int *decrypt_len, - const uint8_t *key) -{ - if (!in || inlen == 0) { - return NULL; - } - - // Unbase64 - int ub64len; - unsigned char *ub64 = unbase64((const char *)in, inlen, &ub64len); - if (!ub64) { - return NULL; - } - if ((ub64len % N_BLOCK) || ub64len < N_BLOCK) { - free(ub64); - return NULL; - } - - char *ret = aescbcb64_init_and_decrypt(ub64, ub64len, decrypt_len, key); - memset(ub64, 0, ub64len); - free(ub64); - return ret; -} - - diff --git a/src/aescbcb64.h b/src/aescbcb64.h deleted file mode 100644 index d31c0c60..00000000 --- a/src/aescbcb64.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - - The MIT License (MIT) - - Copyright (c) 2015-2018 Douglas J. Bakkum - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#ifndef _AESCBCB64_H_ -#define _AESCBCB64_H_ - - -char *aescbcb64_hmac_encrypt(const unsigned char *in, int inlen, - int *out_b64len, const uint8_t *shared_secret); - -char *aescbcb64_init_and_decrypt(uint8_t *ub64, int ub64len, int *decrypt_len, - const uint8_t *key); - -char *aescbcb64_encrypt(const unsigned char *in, int inlen, - int *out_b64len, const uint8_t *key); - -char *aescbcb64_decrypt(const unsigned char *in, int inlen, - int *decrypt_len, const uint8_t *key); - -#endif diff --git a/src/ataes132.c b/src/ataes132.c index 69ab9727..99a70732 100644 --- a/src/ataes132.c +++ b/src/ataes132.c @@ -69,14 +69,32 @@ static void ataes_calculate_crc(uint8_t length, const uint8_t *data, uint8_t *cr static int random_seeded = 0; -__extension__ static uint8_t ataes_eeprom_simulation[] = {[0 ... 0x0FFF] = 0xFF}; +__extension__ static uint8_t ataes_eeprom_simulation[] = {[0 ... (ATAES_EEPROM_LEN - 1)] = 0xFF}; + + +uint8_t *ataes_eeprom_simulation_report(void) +{ + return ataes_eeprom_simulation; +} + + +void ataes_eeprom_simulation_clear(void) +{ + memset(ataes_eeprom_simulation, 0xFF, sizeof(ataes_eeprom_simulation)); +} + + +void ataes_eeprom_simulation_write(const uint8_t *data, uint16_t start, uint16_t len) +{ + memcpy(ataes_eeprom_simulation + start, data, len); +} #else static uint8_t ataes_eeprom_write(uint32_t u32_start_address, uint16_t u16_length, - uint8_t *p_wr_buffer) + const uint8_t *p_wr_buffer) { switch (board_com_report_ataes_mode()) { case BOARD_COM_ATAES_MODE_SPI: { @@ -90,7 +108,9 @@ static uint8_t ataes_eeprom_write(uint32_t u32_start_address, uint16_t u16_lengt return board_com_spi_write(BOARD_COM_SPI_DEV_ATAES, spi_cmd, sizeof(spi_cmd)); } case BOARD_COM_ATAES_MODE_TWI: { - return board_com_twi_write(u32_start_address, p_wr_buffer, u16_length); + uint8_t twi_buf[u16_length]; + memcpy(twi_buf, p_wr_buffer, u16_length); + return board_com_twi_write(u32_start_address, twi_buf, u16_length); } default: { return 1; @@ -274,7 +294,7 @@ int ataes_process(uint8_t const *command, uint16_t cmd_len, // Pass NULL to read only or write only int ataes_eeprom(uint16_t LEN, uint32_t ADDR, uint8_t *userdata_read, - uint8_t *userdata_write) + const uint8_t *userdata_write) { #ifdef TESTING if (userdata_write != NULL) { diff --git a/src/ataes132.h b/src/ataes132.h index e67e95a4..bf19c438 100644 --- a/src/ataes132.h +++ b/src/ataes132.h @@ -36,11 +36,18 @@ #define ATAES_CMD_RAND 0x02 #define ATAES_CMD_LOCK 0x0D - +#ifdef TESTING +#define ATAES_EEPROM_LEN 0x1000 +#define ATAES_EEPROM_ZONE_LEN 0x100 +#define ATAES_EEPROM_ZONE_NUM (ATAES_EEPROM_LEN / ATAES_EEPROM_ZONE_LEN) +uint8_t *ataes_eeprom_simulation_report(void); +void ataes_eeprom_simulation_clear(void); +void ataes_eeprom_simulation_write(const uint8_t *data, uint16_t start, uint16_t len); +#endif int ataes_process(uint8_t const *command, uint16_t cmd_len, uint8_t *response_block, uint16_t response_len); int ataes_eeprom(uint16_t LEN, uint32_t ADDR, uint8_t *userdata_read, - uint8_t *userdata_write); + const uint8_t *userdata_write); #endif diff --git a/src/board_com.c b/src/board_com.c index d8b28305..cfda67f0 100644 --- a/src/board_com.c +++ b/src/board_com.c @@ -164,3 +164,8 @@ void board_com_init(void) } +void board_com_deinit(void) +{ + spi_disable(SPI); + twi_disable_master_mode(BOARD_COM_ATAES_TWI); +} diff --git a/src/board_com.h b/src/board_com.h index 4fa357e1..db5b2db0 100644 --- a/src/board_com.h +++ b/src/board_com.h @@ -104,6 +104,7 @@ uint8_t board_com_spi_write_read(BOARD_COM_SPI_DEV d, uint8_t *ins, uint32_t ins uint8_t *reply, uint32_t reply_len); uint8_t board_com_spi_write(BOARD_COM_SPI_DEV d, uint8_t *cmd, uint32_t len); void board_com_init(void); +void board_com_deinit(void); #endif diff --git a/src/cipher.c b/src/cipher.c new file mode 100644 index 00000000..9b529f45 --- /dev/null +++ b/src/cipher.c @@ -0,0 +1,272 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015-2018 Douglas J. Bakkum + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + +*/ + + +#include +#include +#include + +#include "commander.h" +#include "memory.h" +#include "base64.h" +#include "random.h" +#include "flags.h" +#include "utils.h" +#include "hmac.h" +#include "sha2.h" +#include "aes.h" +#include "cipher.h" + + +static void cipher_derive_hmac_keys(const uint8_t *secret, + uint8_t *encryption_key, + uint8_t *authentication_key) +{ + uint8_t hash[SHA512_DIGEST_LENGTH]; + sha512_Raw(secret, SHA256_DIGEST_LENGTH, hash); + + int KEY_SIZE = SHA512_DIGEST_LENGTH / 2; + + memcpy(encryption_key, hash, KEY_SIZE); + memcpy(authentication_key, hash + KEY_SIZE, KEY_SIZE); + + utils_zero(hash, SHA512_DIGEST_LENGTH); +} + + +// Must free() returned value +static uint8_t *cipher_aes_encrypt(const unsigned char *in, int inlen, + int *out_len, const uint8_t *key) +{ + int pads; + int inpadlen = inlen + N_BLOCK - inlen % N_BLOCK; + unsigned char inpad[inpadlen]; + unsigned char enc[inpadlen]; + unsigned char iv[N_BLOCK]; + uint8_t *enc_cat = malloc(sizeof(uint8_t) * (inpadlen + + N_BLOCK)); // concatenating [ iv0 | enc ] + + aes_context ctx[1]; + + // Set cipher key + memset(ctx, 0, sizeof(ctx)); + aes_set_key(key, 32, ctx); + + // PKCS7 padding + memcpy(inpad, in, inlen); + for (pads = 0; pads < N_BLOCK - inlen % N_BLOCK; pads++ ) { + inpad[inlen + pads] = (N_BLOCK - inlen % N_BLOCK); + } + + // Make a random initialization vector + if (random_bytes((uint8_t *)iv, N_BLOCK, 0) == DBB_ERROR) { + commander_fill_report(cmd_str(CMD_random), NULL, DBB_ERR_MEM_ATAES); + *out_len = 0; + utils_zero(inpad, inpadlen); + utils_zero(ctx, sizeof(ctx)); + return NULL; + } + memcpy(enc_cat, iv, N_BLOCK); + + // CBC encrypt multiple blocks + aes_cbc_encrypt(inpad, enc, inpadlen / N_BLOCK, iv, ctx); + memcpy(enc_cat + N_BLOCK, enc, inpadlen); + *out_len = inpadlen + N_BLOCK; + + utils_zero(inpad, inpadlen); + utils_zero(ctx, sizeof(ctx)); + return enc_cat; +} + + +// Encrypts a given constant char array of length inlen using the AES algorithm with CBC mode +// and base64 encodes the result. +// +// Must free() returned value (allocated inside base64() function) +char *cipher_aes_b64_encrypt(const unsigned char *in, int inlen, int *outb64len, + const uint8_t *key) +{ + int outlen; + uint8_t *encrypt = cipher_aes_encrypt(in, inlen, &outlen, key); + char *b64; + b64 = base64(encrypt, outlen, outb64len); + free(encrypt); + return b64; +} + + +// Encrypts a given constant char array of length inlen using the AES algorithm with CBC mode, +// appends its SHA256 HMAC and base64 encodes the result. +// +// Must free() returned value +char *cipher_aes_b64_hmac_encrypt(const unsigned char *in, int inlen, int *outb64len, + const uint8_t *secret) +{ + int outlen; + uint8_t *hmac_encrypt = cipher_aes_hmac_encrypt(in, inlen, &outlen, secret); + char *b64 = base64(hmac_encrypt, outlen, outb64len); + free(hmac_encrypt); + return b64; +} + + +// Encrypts a given constant char array of length inlen using the AES algorithm with CBC mode +// and appends its SHA256 HMAC. +// +// Must free() returned value +uint8_t *cipher_aes_hmac_encrypt(const unsigned char *in, int inlen, int *outlen, + const uint8_t *secret) +{ + int encrypt_len; + uint8_t hmac[SHA256_DIGEST_LENGTH]; + uint8_t encryption_key[SHA256_DIGEST_LENGTH]; + uint8_t authentication_key[SHA256_DIGEST_LENGTH]; + + *outlen = 0; + + cipher_derive_hmac_keys(secret, encryption_key, authentication_key); + + uint8_t *encrypted = cipher_aes_encrypt(in, + inlen, + &encrypt_len, + encryption_key); + + if (encrypted == NULL) { + return NULL; + } + + hmac_sha256(authentication_key, SHA256_DIGEST_LENGTH, encrypted, encrypt_len, hmac); + + *outlen = encrypt_len + SHA256_DIGEST_LENGTH; + uint8_t *encrypted_r = realloc(encrypted, *outlen); + if (encrypted_r == NULL) { + free(encrypted); + return NULL; + } + encrypted = encrypted_r; + + memcpy(encrypted + encrypt_len, hmac, SHA256_DIGEST_LENGTH); + utils_zero(encryption_key, sizeof(encryption_key)); + utils_zero(authentication_key, sizeof(authentication_key)); + + return encrypted; +} + + +static char *cipher_aes_decrypt(const uint8_t *in, int inlen, int *outlen, + const uint8_t *key) +{ + *outlen = 0; + + // Set cipher key + aes_context ctx[1]; + memset(ctx, 0, sizeof(ctx)); + aes_set_key(key, 32, ctx); + + unsigned char dec_pad[inlen - N_BLOCK]; + uint8_t iv[N_BLOCK]; + memcpy(iv, in, N_BLOCK); + aes_cbc_decrypt(in + N_BLOCK, dec_pad, inlen / N_BLOCK - 1, iv, ctx); + + // Strip PKCS7 padding + int padlen = dec_pad[inlen - N_BLOCK - 1]; + if (inlen - N_BLOCK - padlen <= 0) { + utils_zero(dec_pad, sizeof(dec_pad)); + utils_zero(ctx, sizeof(ctx)); + return NULL; + } + char *dec = malloc(inlen - N_BLOCK - padlen + 1); // +1 for null termination + if (!dec) { + utils_zero(dec_pad, sizeof(dec_pad)); + utils_zero(ctx, sizeof(ctx)); + return NULL; + } + memcpy(dec, dec_pad, inlen - N_BLOCK - padlen); + dec[inlen - N_BLOCK - padlen] = '\0'; + *outlen = inlen - N_BLOCK - padlen + 1; + utils_zero(dec_pad, sizeof(dec_pad)); + utils_zero(ctx, sizeof(ctx)); + return dec; +} + + +char *cipher_aes_hmac_decrypt(const uint8_t *in, int inlen, + int *outlen, const uint8_t *key) +{ + uint8_t hmac[SHA256_DIGEST_LENGTH]; + uint8_t encryption_key[SHA256_DIGEST_LENGTH]; + uint8_t authentication_key[SHA256_DIGEST_LENGTH]; + + *outlen = 0; + + if ((size_t)inlen < sizeof(hmac)) { + return NULL; + } + + cipher_derive_hmac_keys(key, encryption_key, authentication_key); + hmac_sha256(authentication_key, MEM_PAGE_LEN, in, inlen - sizeof(hmac), hmac); + + if (!MEMEQ(hmac, in + inlen - sizeof(hmac), sizeof(hmac))) { + utils_zero(encryption_key, sizeof(encryption_key)); + utils_zero(authentication_key, sizeof(authentication_key)); + return NULL; + } + + char *ret = cipher_aes_decrypt(in, inlen - sizeof(hmac), outlen, encryption_key); + + utils_zero(encryption_key, sizeof(encryption_key)); + utils_zero(authentication_key, sizeof(authentication_key)); + return ret; +} + + +// Must free() returned value +char *cipher_aes_b64_decrypt(const unsigned char *in, int inlen, int *outlen, + const uint8_t *key) +{ + *outlen = 0; + + if (!in || inlen == 0) { + return NULL; + } + + // Unbase64 + int ub64len; + unsigned char *ub64 = unbase64((const char *)in, inlen, &ub64len); + if (!ub64) { + return NULL; + } + if ((ub64len % N_BLOCK) || ub64len < N_BLOCK) { + memset(ub64, 0, ub64len); + free(ub64); + return NULL; + } + + char *ret = cipher_aes_decrypt(ub64, ub64len, outlen, key); + memset(ub64, 0, ub64len); + free(ub64); + return ret; +} diff --git a/src/sharedsecret.c b/src/cipher.h similarity index 61% rename from src/sharedsecret.c rename to src/cipher.h index ce95fea3..c6590403 100644 --- a/src/sharedsecret.c +++ b/src/cipher.h @@ -24,24 +24,28 @@ */ + +#ifndef _CIPHER_H_ +#define _CIPHER_H_ + + #include -#include "sha2.h" -#include "utils.h" -#include "sharedsecret.h" -void sharedsecret_derive_keys(const uint8_t *shared_secret, uint8_t *encryption_key, - uint8_t *authentication_key) -{ - uint8_t encryption_and_authentication_key[SHA512_DIGEST_LENGTH]; - sha512_Raw(shared_secret, SHA256_DIGEST_LENGTH, encryption_and_authentication_key); +char *cipher_aes_b64_hmac_encrypt(const unsigned char *in, int inlen, + int *out_b64len, const uint8_t *secret); + +uint8_t *cipher_aes_hmac_encrypt(const unsigned char *in, int inlen, + int *out_b64len, const uint8_t *secret); - int KEY_SIZE = SHA512_DIGEST_LENGTH / 2; +char *cipher_aes_b64_encrypt(const unsigned char *in, int inlen, + int *out_b64len, const uint8_t *key); - memcpy(encryption_key, encryption_and_authentication_key, KEY_SIZE); - memcpy(authentication_key, encryption_and_authentication_key + KEY_SIZE, KEY_SIZE); +char *cipher_aes_b64_decrypt(const unsigned char *in, int inlen, + int *outlen, const uint8_t *key); - utils_zero(encryption_and_authentication_key, SHA512_DIGEST_LENGTH); -} +char *cipher_aes_hmac_decrypt(const uint8_t *in, int inlen, + int *outlen, const uint8_t *key); +#endif diff --git a/src/commander.c b/src/commander.c index 8af88348..cfb1b798 100644 --- a/src/commander.c +++ b/src/commander.c @@ -41,7 +41,7 @@ #include "flags.h" #include "sha2.h" #include "aes.h" -#include "aescbcb64.h" +#include "cipher.h" #include "hmac.h" #include "led.h" #include "ecc.h" @@ -546,6 +546,7 @@ static void commander_process_seed(yajl_val json_node) uint8_t number[MEM_PAGE_LEN]; if (random_bytes(number, sizeof(number), 1) == DBB_ERROR) { commander_fill_report(cmd_str(CMD_seed), NULL, DBB_ERR_MEM_ATAES); + utils_zero(entropy_b, sizeof(entropy_b)); return; } for (i = 0; i < MEM_PAGE_LEN; i++) { @@ -560,6 +561,8 @@ static void commander_process_seed(yajl_val json_node) if (ret == DBB_OK) { if (commander_process_backup_create(key, filename, attr_str(ATTR_all)) != DBB_OK) { memory_erase_hww_seed(); + utils_zero(entropy_b, sizeof(entropy_b)); + utils_zero(entropy_c, sizeof(entropy_c)); return; } } @@ -611,6 +614,14 @@ static void commander_process_seed(yajl_val json_node) } snprintf(entropy_c, sizeof(entropy_c), "%s", backup_hex); ret = wallet_create(key, entropy_c); + if (ret == DBB_OK) { + if (commander_process_backup_check(key, filename, attr_str(ATTR_HWW)) != DBB_OK) { + memory_erase_hww_seed(); + utils_zero(backup_hex, strlens(backup_hex)); + utils_zero(entropy_c, sizeof(entropy_c)); + return; + } + } } } utils_zero(backup_hex, strlens(backup_hex)); @@ -709,9 +720,9 @@ static void commander_process_random(yajl_val json_node) snprintf(echo_number, sizeof(echo_number), "{\"random\":\"%s\"}", utils_uint8_to_hex(number, sizeof(number))); - encoded_report = aescbcb64_hmac_encrypt((unsigned char *) echo_number, - strlens(echo_number), - &encrypt_len, memory_report_aeskey(TFA_SHARED_SECRET)); + encoded_report = cipher_aes_b64_hmac_encrypt((unsigned char *) echo_number, + strlens(echo_number), &encrypt_len, + memory_report_aeskey(TFA_SHARED_SECRET)); if (encoded_report) { commander_fill_report(cmd_str(CMD_echo), encoded_report, DBB_OK); @@ -751,7 +762,7 @@ static void commander_process_xpub(yajl_val json_node) commander_fill_report(cmd_str(CMD_xpub), xpub, DBB_OK); int encrypt_len; - char *encoded_report = aescbcb64_hmac_encrypt((unsigned char *) xpub, strlens(xpub), + char *encoded_report = cipher_aes_b64_hmac_encrypt((unsigned char *) xpub, strlens(xpub), &encrypt_len, memory_report_aeskey(TFA_SHARED_SECRET)); if (encoded_report) { @@ -770,7 +781,7 @@ static void commander_process_xpub(yajl_val json_node) static uint8_t commander_bootloader_unlocked(void) { uint8_t sig[FLASH_SIG_LEN]; - flash_read_sig_area(sig, FLASH_SIG_START, FLASH_SIG_LEN); + flash_wrapper_read_sig_area(sig, FLASH_SIG_START, FLASH_SIG_LEN); return sig[FLASH_BOOT_LOCK_BYTE]; } @@ -813,7 +824,7 @@ static void commander_process_device(yajl_val json_node) char u2f_hijack_enabled[6] = {0}; uint32_t serial[4] = {0}; - flash_read_unique_id(serial, 4); + flash_wrapper_read_unique_id(serial, 4); if (wallet_is_locked()) { snprintf(lock, sizeof(lock), "%s", attr_str(ATTR_true)); @@ -856,10 +867,9 @@ static void commander_process_device(yajl_val json_node) int tfa_len; - char *tfa = aescbcb64_hmac_encrypt((const unsigned char *)VERIFYPASS_CRYPT_TEST, - strlens(VERIFYPASS_CRYPT_TEST), - &tfa_len, - memory_report_aeskey(TFA_SHARED_SECRET)); + char *tfa = cipher_aes_b64_hmac_encrypt((const unsigned char *)VERIFYPASS_CRYPT_TEST, + strlens(VERIFYPASS_CRYPT_TEST), &tfa_len, + memory_report_aeskey(TFA_SHARED_SECRET)); if (!tfa) { commander_clear_report(); commander_fill_report(cmd_str(CMD_device), NULL, DBB_ERR_MEM_ENCRYPT); @@ -970,7 +980,7 @@ static void commander_process_bootloader(yajl_val json_node) } uint8_t sig[FLASH_SIG_LEN]; - flash_read_sig_area(sig, FLASH_SIG_START, FLASH_SIG_LEN); + flash_wrapper_read_sig_area(sig, FLASH_SIG_START, FLASH_SIG_LEN); if (STREQ(value, attr_str(ATTR_lock))) { sig[FLASH_BOOT_LOCK_BYTE] = 0; @@ -981,11 +991,11 @@ static void commander_process_bootloader(yajl_val json_node) return; } - if (flash_erase_page(FLASH_SIG_START, IFLASH_ERASE_PAGES_8) != FLASH_RC_OK) { + if (flash_wrapper_erase_page(FLASH_SIG_START, IFLASH_ERASE_PAGES_8) != FLASH_RC_OK) { goto err; } - if (flash_write(FLASH_SIG_START, sig, FLASH_SIG_LEN, 0) != FLASH_RC_OK) { + if (flash_wrapper_write(FLASH_SIG_START, sig, FLASH_SIG_LEN, 0) != FLASH_RC_OK) { goto err; } @@ -1287,7 +1297,7 @@ static int commander_echo_command(yajl_val json_node) } int length; - char *encoded_report = aescbcb64_hmac_encrypt((unsigned char *) json_report, + char *encoded_report = cipher_aes_b64_hmac_encrypt((unsigned char *) json_report, strlens(json_report), &length, memory_report_aeskey(TFA_SHARED_SECRET)); commander_clear_report(); if (encoded_report) { @@ -1415,10 +1425,9 @@ static void commander_parse(char *command) } exit: - encoded_report = aescbcb64_encrypt((unsigned char *)json_report, - strlens(json_report), - &encrypt_len, - memory_active_key_get()); + encoded_report = cipher_aes_b64_encrypt((unsigned char *)json_report, + strlens(json_report), &encrypt_len, + memory_active_key_get()); commander_clear_report(); if (encoded_report) { @@ -1442,13 +1451,11 @@ static uint8_t commander_find_active_key(const char *encrypted_command) key_std = memory_report_aeskey(PASSWORD_STAND); key_hdn = memory_report_aeskey(PASSWORD_HIDDEN); - cmd_std = aescbcb64_decrypt((const unsigned char *)encrypted_command, - strlens(encrypted_command), - &len_std, key_std); + cmd_std = cipher_aes_b64_decrypt((const unsigned char *)encrypted_command, + strlens(encrypted_command), &len_std, key_std); - cmd_hdn = aescbcb64_decrypt((const unsigned char *)encrypted_command, - strlens(encrypted_command), - &len_hdn, key_hdn); + cmd_hdn = cipher_aes_b64_decrypt((const unsigned char *)encrypted_command, + strlens(encrypted_command), &len_hdn, key_hdn); if (strlens(cmd_std)) { if (BRACED(cmd_std)) { @@ -1492,10 +1499,9 @@ static char *commander_decrypt(const char *encrypted_command) size_t json_object_len = 0; if (commander_find_active_key(encrypted_command) == DBB_OK) { - command = aescbcb64_decrypt((const unsigned char *)encrypted_command, - strlens(encrypted_command), - &command_len, - memory_active_key_get()); + command = cipher_aes_b64_decrypt((const unsigned char *)encrypted_command, + strlens(encrypted_command), &command_len, + memory_active_key_get()); } err_count = memory_report_access_err_count(); diff --git a/src/firmware.c b/src/firmware.c index 25dbe86e..90b0056f 100644 --- a/src/firmware.c +++ b/src/firmware.c @@ -47,7 +47,9 @@ uint32_t __stack_chk_guard = 0; extern void __attribute__((noreturn)) __stack_chk_fail(void); void __attribute__((noreturn)) __stack_chk_fail(void) { + memory_clear(); udc_stop(); + board_com_deinit(); while (1) { led_toggle(); delay_ms(300); @@ -63,7 +65,9 @@ void SysTick_Handler(void) void HardFault_Handler(void) { + memory_clear(); udc_stop(); + board_com_deinit(); while (1) { led_toggle(); delay_ms(500); @@ -73,7 +77,9 @@ void HardFault_Handler(void) void MemManage_Handler(void) { + memory_clear(); udc_stop(); + board_com_deinit(); while (1) { led_toggle(); delay_ms(1000); diff --git a/src/flash.c b/src/flash.c index d073ff54..1e20bb65 100644 --- a/src/flash.c +++ b/src/flash.c @@ -26,29 +26,55 @@ #include "flash.h" -#ifdef TESTING +#include "utils.h" +#ifndef TESTING +#include "mcu.h" +#else +__extension__ static uint8_t flash_usersig_simulation[] = {[0 ... FLASH_USERSIG_SIZE - 1] = 0xFF}; +__extension__ static uint8_t flash_sig_area_simulation[] = {[0 ... FLASH_SIG_LEN - 1] = 0xFF}; +#endif -__extension__ static uint8_t flash_user_signature_simulation[] = {[0 ... FLASH_USERSIG_SIZE - 1] = 0xFF}; -__extension__ static uint8_t flash_sig_area_simulation[] = {[0 ... FLASH_SIG_LEN - 1] = 0xFF}; +#ifdef TESTING +void HardFault_Handler(void) +{ + exit(1); +} +void MemManage_Handler(void) +{ + exit(2); +} +#endif -uint8_t flash_read_unique_id(uint32_t *serial, uint32_t len) + +uint8_t flash_wrapper_read_unique_id(uint32_t *serial, uint32_t len) { +#ifdef TESTING memset(serial, 1, sizeof(uint32_t) * len); return 0; // success +#else + return flash_read_unique_id(serial, len); +#endif } -uint32_t flash_erase_user_signature(void) +uint32_t flash_wrapper_erase_usersig(void) { - memset(flash_user_signature_simulation, 0xFF, FLASH_USERSIG_SIZE); +#ifdef TESTING + memset(flash_usersig_simulation, 0xFF, FLASH_USERSIG_SIZE); +#else + if (flash_erase_user_signature()) { + HardFault_Handler(); + } +#endif return 0; // success } -uint32_t flash_write_user_signature(const void *p_buffer, uint32_t ul_size) +uint32_t flash_wrapper_write_usersig(const void *p_buffer, uint32_t ul_size) { +#ifdef TESTING uint32_t i; uint8_t buf[ul_size * sizeof(uint32_t)]; if (ul_size * sizeof(uint32_t) != FLASH_USERSIG_SIZE) { @@ -57,24 +83,37 @@ uint32_t flash_write_user_signature(const void *p_buffer, uint32_t ul_size) memcpy(buf, p_buffer, FLASH_USERSIG_SIZE); for (i = 0; i < FLASH_USERSIG_SIZE; i++) { // bare-metal write can only change bits to 0b - flash_user_signature_simulation[i] &= buf[i]; + flash_usersig_simulation[i] &= buf[i]; + } +#else + if (flash_write_user_signature(p_buffer, ul_size)) { + HardFault_Handler(); } +#endif return 0; // success } -uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size) +uint32_t flash_wrapper_read_usersig(uint32_t *p_data, uint32_t ul_size) { +#ifdef TESTING if (ul_size * sizeof(uint32_t) > FLASH_USERSIG_SIZE) { return 1; // error } - memcpy(p_data, flash_user_signature_simulation, ul_size * sizeof(uint32_t)); + memcpy(p_data, flash_usersig_simulation, ul_size * sizeof(uint32_t)); +#else + if (flash_read_user_signature(p_data, ul_size)) { + utils_zero(p_data, ul_size); + HardFault_Handler(); + }; +#endif return 0; // success } -uint32_t flash_erase_page(uint32_t ul_address, uint8_t uc_page_num) +uint32_t flash_wrapper_erase_page(uint32_t ul_address, uint8_t uc_page_num) { +#ifdef TESTING if (ul_address != FLASH_SIG_START) { return !FLASH_RC_OK; } @@ -82,17 +121,23 @@ uint32_t flash_erase_page(uint32_t ul_address, uint8_t uc_page_num) return !FLASH_RC_OK; } memset(flash_sig_area_simulation, 0xFF, FLASH_SIG_LEN); +#else + if (flash_erase_page(ul_address, uc_page_num) != FLASH_RC_OK) { + HardFault_Handler(); + }; +#endif return FLASH_RC_OK; // success } -uint32_t flash_write(uint32_t ul_address, const void *p_buffer, - uint32_t ul_size, uint32_t ul_erase_flag) +uint32_t flash_wrapper_write(uint32_t ul_address, void *p_buffer, + uint32_t ul_size, uint32_t ul_erase_flag) { +#ifdef TESTING uint32_t i; uint8_t buf[FLASH_SIG_LEN]; if (ul_erase_flag) { - flash_erase_page(FLASH_SIG_START, IFLASH_ERASE_PAGES_8); + flash_wrapper_erase_page(FLASH_SIG_START, IFLASH_ERASE_PAGES_8); } if (ul_address != FLASH_SIG_START) { return !FLASH_RC_OK; @@ -105,12 +150,17 @@ uint32_t flash_write(uint32_t ul_address, const void *p_buffer, // bare-metal write can only change bits to 0b flash_sig_area_simulation[i] &= buf[i]; } +#else + if (flash_write(ul_address, p_buffer, ul_size, ul_erase_flag) != FLASH_RC_OK) { + utils_zero(p_buffer, ul_size); + HardFault_Handler(); + } +#endif return FLASH_RC_OK; // success } -#endif -void flash_read_sig_area(uint8_t *sig, uint32_t ul_address, uint32_t len) +void flash_wrapper_read_sig_area(uint8_t *sig, uint32_t ul_address, uint32_t len) { #ifdef TESTING (void) ul_address; diff --git a/src/flash.h b/src/flash.h index 761cc514..d635f8a7 100644 --- a/src/flash.h +++ b/src/flash.h @@ -57,6 +57,9 @@ #define FLASH_USERSIG_START (0x00400000u) #define FLASH_USERSIG_SIZE (0x200u) #define FLASH_USERSIG_RN_LEN (0x20u) +#define FLASH_USERSIG_RN_START (0x00u) +#define FLASH_USERSIG_FLAG_LEN (0x20u) +#define FLASH_USERSIG_FLAG_START (FLASH_USERSIG_RN_START + FLASH_USERSIG_RN_LEN) #define FLASH_SIG_START (IFLASH0_ADDR + FLASH_BOOT_LEN) #define FLASH_SIG_LEN (FLASH_ERASE_SIZE) #define FLASH_APP_START (IFLASH0_ADDR + FLASH_BOOT_LEN + FLASH_SIG_LEN) @@ -96,24 +99,18 @@ static inline uint32_t mpu_region_size(uint32_t size) #ifdef TESTING -static void HardFault_Handler(void) -{ - exit(1); -} -static void MemManage_Handler(void) -{ - exit(2); -} - -uint8_t flash_read_unique_id(uint32_t *serial, uint32_t len); -uint32_t flash_erase_user_signature(void); -uint32_t flash_write_user_signature(const void *p_buffer, uint32_t ul_size); -uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size); -uint32_t flash_erase_page(uint32_t ul_address, uint8_t uc_page_num); -uint32_t flash_write(uint32_t ul_address, const void *p_buffer, - uint32_t ul_size, uint32_t ul_erase_flag); +void HardFault_Handler(void); +void MemManage_Handler(void); #endif -void flash_read_sig_area(uint8_t *sig, uint32_t ul_address, uint32_t len); +uint8_t flash_wrapper_read_unique_id(uint32_t *serial, uint32_t len); +uint32_t flash_wrapper_erase_usersig(void); +uint32_t flash_wrapper_write_usersig(const void *p_buffer, uint32_t ul_size); +uint32_t flash_wrapper_read_usersig(uint32_t *p_data, uint32_t ul_size); +uint32_t flash_wrapper_erase_page(uint32_t ul_address, uint8_t uc_page_num); +uint32_t flash_wrapper_write(uint32_t ul_address, void *p_buffer, + uint32_t ul_size, uint32_t ul_erase_flag); +void flash_wrapper_read_sig_area(uint8_t *sig, uint32_t ul_address, + uint32_t len); #endif diff --git a/src/memory.c b/src/memory.c index 956548d5..5ef7ab63 100644 --- a/src/memory.c +++ b/src/memory.c @@ -31,7 +31,7 @@ #include "commander.h" #include "ataes132.h" -#include "aescbcb64.h" +#include "cipher.h" #include "memory.h" #include "random.h" #include "utils.h" @@ -43,18 +43,65 @@ #include "drivers/config/mcu.h" -#if (MEM_PAGE_LEN != SHA256_DIGEST_LENGTH) +#if ((MEM_PAGE_LEN != SHA256_DIGEST_LENGTH) || (MEM_PAGE_LEN * 2 != SHA512_DIGEST_LENGTH)) #error "Incompatible macro values" #endif -static uint8_t MEM_unlocked = DEFAULT_unlocked; -static uint8_t MEM_erased = DEFAULT_erased; -static uint8_t MEM_setup = DEFAULT_setup; -static uint32_t MEM_ext_flags = DEFAULT_ext_flags; -static uint32_t MEM_u2f_count = DEFAULT_u2f_count; +// 16 consecutive user zones: 0x0000 to 0x0FFF +// Each zone contains 0x0100 bytes; read/write cannot cross zone boundaries +#define MEM_ERASED_ADDR 0x0000// (uint8_t) Zone 0 reserved for flags +#define MEM_SETUP_ADDR 0x0002// (uint8_t) +#define MEM_ACCESS_ERR_ADDR 0x0004// (uint16_t) +#define MEM_PIN_ERR_ADDR 0x0006// (uint16_t) +#define MEM_UNLOCKED_ADDR 0x0008// (uint8_t) +#define MEM_EXT_FLAGS_ADDR 0x000A// (uint32_t) 32 possible extension flags +#define MEM_U2F_COUNT_ADDR 0x0010// (uint32_t) +#define MEM_MEMORY_MAP_VERSION_ADDR 0x0014// (uint32_t) +#if (FLASH_USERSIG_FLAG_LEN < (MEM_MEMORY_MAP_VERSION_ADDR + 4) || FLASH_USERSIG_FLAG_LEN >= 0x0100) +#error "Incorrect macro value for memory map" +#endif +#define MEM_MAP_ADDRS /*V0*/ /*V1*/ /* Memory map version */\ +X(MEM_NAME_ADDR_IDX, 0x0100, 0x0180)\ +X(MEM_MASTER_BIP32_ADDR_IDX, 0x0200, 0x0280)\ +X(MEM_MASTER_BIP32_CHAIN_ADDR_IDX, 0x0300, 0x0380)\ +X(MEM_AESKEY_STAND_ADDR_IDX, 0x0400, 0x0480)\ +X(MEM_AESKEY_SHARED_SECRET_ADDR_IDX, 0x0500, 0x0580)\ +X(MEM_AESKEY_HIDDEN_ADDR_IDX, 0x0800, 0x0880)\ +X(MEM_MASTER_ENTROPY_ADDR_IDX, 0x0900, 0x0980)\ +X(MEM_MASTER_U2F_ADDR_IDX, 0x0A00, 0x0A80)\ +X(MEM_HIDDEN_BIP32_ADDR_IDX, 0x0B00, 0x0C80)\ +X(MEM_HIDDEN_BIP32_CHAIN_ADDR_IDX, 0x0B80, 0x0D80) +#define X(a, b, c) a, +enum MEM_MAPPING_ENUM { MEM_MAP_ADDRS }; +#undef X +#define X(a, b, c) b, +uint16_t MEM_ADDR_V0[] = { MEM_MAP_ADDRS }; +#undef X +#define X(a, b, c) c, +uint16_t MEM_ADDR_V1[] = { MEM_MAP_ADDRS }; +#undef X +// Number of calls to memory_eeprom to store encrypted data. +// Each call can read and/or write up to 32 bytes at a time. +// For MEM_MAP_V0, 4 calls required. For MEM_MAP_V1, 3 calls +// required but still use 4 calls in order to keep the code +// cleaner, pad with 0xFFs: +// [16-byte IV | 32-byte cipher | 16-byte AES pad | 32-byte hmac | 32-bytes 0xFF] +#define MEM_NUM_CRYPT_EEPROM_WRITES 4 +// Version settings +#define MEM_MAP_V0 MEM_DEFAULT_memory_map_version +#define MEM_MAP_V1 0x00000001 +#define ACTIVE_memory_map_version MEM_MAP_V1 + + +static uint8_t MEM_unlocked = MEM_DEFAULT_unlocked; +static uint8_t MEM_erased = MEM_DEFAULT_erased; +static uint8_t MEM_setup = MEM_DEFAULT_setup; +static uint32_t MEM_ext_flags = MEM_DEFAULT_ext_flags; +static uint32_t MEM_u2f_count = MEM_DEFAULT_u2f_count; static uint16_t MEM_pin_err = DBB_ACCESS_INITIALIZE; static uint16_t MEM_access_err = DBB_ACCESS_INITIALIZE; +static uint32_t MEM_memory_map_version = MEM_DEFAULT_memory_map_version; __extension__ static uint8_t MEM_active_key[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; __extension__ static uint8_t MEM_user_entropy[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; @@ -74,124 +121,154 @@ __extension__ const uint16_t MEM_PAGE_ERASE_2X[] = {[0 ... MEM_PAGE_LEN - 1] = 0 __extension__ const uint8_t MEM_PAGE_ERASE_FE[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFE}; -static uint8_t memory_eeprom(uint8_t *write_b, uint8_t *read_b, const int32_t addr, - const uint16_t len) +static void memory_eeprom(const uint8_t *write_b, uint8_t *read_b, int32_t addr, + uint16_t len) { // read current memory if (ataes_eeprom(len, addr, read_b, NULL) != DBB_OK) { - commander_fill_report(cmd_str(CMD_ataes), NULL, DBB_ERR_MEM_ATAES); - return DBB_ERROR; - } - if (write_b) { + HardFault_Handler(); + } else if (write_b) { // skip writing if memory does not change if (read_b) { if (MEMEQ(read_b, write_b, len)) { - return DBB_OK; + return; // success } } if (ataes_eeprom(len, addr, read_b, write_b) != DBB_OK) { - commander_fill_report(cmd_str(CMD_ataes), NULL, DBB_ERR_MEM_ATAES); - return DBB_ERROR; - } - if (read_b) { + HardFault_Handler(); + } else if (read_b) { if (MEMEQ(write_b, read_b, len)) { - return DBB_OK; + return; // success } else { // error if (len > 2) { memcpy(read_b, MEM_PAGE_ERASE, len); } - return DBB_ERROR; + HardFault_Handler(); } } } - return DBB_OK; + return; } // Encrypted storage // `write_b` and `read_b` must be length `MEM_PAGE_LEN` static uint8_t memory_eeprom_crypt(const uint8_t *write_b, uint8_t *read_b, - const int32_t addr) + uint8_t map_addr, uint32_t map_version) { - int enc_len, dec_len; - char *enc, *dec, enc_r[MEM_PAGE_LEN * 4 + 1] = {0}; + int enc_len, dec_len, i; + char *enc, *dec, enc_r[MEM_PAGE_LEN * MEM_NUM_CRYPT_EEPROM_WRITES + 1] = {0}; static uint8_t mempass[MEM_PAGE_LEN]; + int32_t addr; // Encrypt data saved to memory using an AES key obfuscated by the // bootloader bytes. memset(mempass, 0, sizeof(mempass)); - uint8_t rn[FLASH_USERSIG_RN_LEN] = {0}; + uint8_t usersig[FLASH_USERSIG_SIZE]; #ifndef TESTING sha256_Raw((uint8_t *)(FLASH_BOOT_START), FLASH_BOOT_LEN, mempass); #endif - flash_read_user_signature((uint32_t *)rn, FLASH_USERSIG_RN_LEN / sizeof(uint32_t)); - if (!MEMEQ(rn, MEM_PAGE_ERASE, FLASH_USERSIG_RN_LEN)) { - hmac_sha256(mempass, MEM_PAGE_LEN, rn, FLASH_USERSIG_RN_LEN, mempass); + flash_wrapper_read_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + if (!MEMEQ(usersig + FLASH_USERSIG_RN_START, MEM_PAGE_ERASE, FLASH_USERSIG_RN_LEN)) { + hmac_sha256(mempass, MEM_PAGE_LEN, usersig + FLASH_USERSIG_RN_START, FLASH_USERSIG_RN_LEN, + mempass); } sha256_Raw(mempass, MEM_PAGE_LEN, mempass); - sha256_Raw((const uint8_t *)(utils_uint8_to_hex(mempass, MEM_PAGE_LEN)), MEM_PAGE_LEN * 2, - mempass); - sha256_Raw(mempass, MEM_PAGE_LEN, mempass); + switch (map_version) { + case MEM_MAP_V0: + addr = MEM_ADDR_V0[map_addr]; + sha256_Raw((const uint8_t *)(utils_uint8_to_hex(mempass, MEM_PAGE_LEN)), MEM_PAGE_LEN * 2, + mempass); + sha256_Raw(mempass, MEM_PAGE_LEN, mempass); + utils_clear_buffers(); // clean up mempass hex + break; + case MEM_MAP_V1: + addr = MEM_ADDR_V1[map_addr]; + break; + default: + goto err; + } if (write_b) { - char enc_w[MEM_PAGE_LEN * 4 + 1] = {0}; - enc = aescbcb64_encrypt((unsigned char *)utils_uint8_to_hex(write_b, MEM_PAGE_LEN), - MEM_PAGE_LEN * 2, &enc_len, mempass); - if (!enc) { - goto err; - } - snprintf(enc_w, sizeof(enc_w), "%.*s", enc_len, enc); - free(enc); - if (memory_eeprom((uint8_t *)enc_w, (uint8_t *)enc_r, addr, - MEM_PAGE_LEN) == DBB_ERROR) { - goto err; - } - if (memory_eeprom((uint8_t *)enc_w + MEM_PAGE_LEN, (uint8_t *)enc_r + MEM_PAGE_LEN, - addr + MEM_PAGE_LEN, MEM_PAGE_LEN) == DBB_ERROR) { - goto err; + char enc_w[MEM_PAGE_LEN * MEM_NUM_CRYPT_EEPROM_WRITES + 1]; + memset(enc_w, 0xFF, sizeof(enc_w)); + enc_w[MEM_PAGE_LEN * MEM_NUM_CRYPT_EEPROM_WRITES] = '\0'; + switch (map_version) { + case MEM_MAP_V0: + enc = cipher_aes_b64_encrypt((unsigned char *)utils_uint8_to_hex(write_b, MEM_PAGE_LEN), + MEM_PAGE_LEN * 2, &enc_len, mempass); + utils_clear_buffers(); // clean up hex write_b + if (!enc) { + goto err; + } + snprintf(enc_w, sizeof(enc_w), "%.*s", enc_len, enc); + utils_zero(enc, enc_len); + free(enc); + break; + case MEM_MAP_V1: + enc = (char *)cipher_aes_hmac_encrypt((const unsigned char *)write_b, MEM_PAGE_LEN, + &enc_len, mempass); + if (!enc) { + goto err; + } + if (sizeof(enc_w) < (size_t)enc_len) { + utils_zero(enc, enc_len); + free(enc); + goto err; + } + memcpy(enc_w, enc, enc_len); + utils_zero(enc, enc_len); + free(enc); + break; + default: + goto err; } - if (memory_eeprom((uint8_t *)enc_w + MEM_PAGE_LEN * 2, - (uint8_t *)enc_r + MEM_PAGE_LEN * 2, addr + MEM_PAGE_LEN * 2, - MEM_PAGE_LEN) == DBB_ERROR) { - goto err; + for (i = 0; i < MEM_NUM_CRYPT_EEPROM_WRITES; i++) { + memory_eeprom((uint8_t *)enc_w + MEM_PAGE_LEN * i, + (uint8_t *)enc_r + MEM_PAGE_LEN * i, addr + MEM_PAGE_LEN * i, + MEM_PAGE_LEN); } - if (memory_eeprom((uint8_t *)enc_w + MEM_PAGE_LEN * 3, - (uint8_t *)enc_r + MEM_PAGE_LEN * 3, addr + MEM_PAGE_LEN * 3, - MEM_PAGE_LEN) == DBB_ERROR) { - goto err; + } else if (read_b) { + for (i = 0; i < MEM_NUM_CRYPT_EEPROM_WRITES; i++) { + memory_eeprom(NULL, (uint8_t *)enc_r + MEM_PAGE_LEN * i, addr + MEM_PAGE_LEN * i, + MEM_PAGE_LEN); } } else { - if (memory_eeprom(NULL, (uint8_t *)enc_r, addr, MEM_PAGE_LEN) == DBB_ERROR) { - goto err; - } - if (memory_eeprom(NULL, (uint8_t *)enc_r + MEM_PAGE_LEN, addr + MEM_PAGE_LEN, - MEM_PAGE_LEN) == DBB_ERROR) { - goto err; - } - if (memory_eeprom(NULL, (uint8_t *)enc_r + MEM_PAGE_LEN * 2, addr + MEM_PAGE_LEN * 2, - MEM_PAGE_LEN) == DBB_ERROR) { - goto err; - } - if (memory_eeprom(NULL, (uint8_t *)enc_r + MEM_PAGE_LEN * 3, addr + MEM_PAGE_LEN * 3, - MEM_PAGE_LEN) == DBB_ERROR) { - goto err; - } + goto err; } - dec = aescbcb64_decrypt((unsigned char *)enc_r, MEM_PAGE_LEN * 4, &dec_len, - mempass); - if (!dec) { - goto err; + switch (map_version) { + case MEM_MAP_V0: + dec = cipher_aes_b64_decrypt((unsigned char *)enc_r, + MEM_PAGE_LEN * MEM_NUM_CRYPT_EEPROM_WRITES, + &dec_len, mempass); + if (!dec) { + goto err; + } + memcpy(dec, utils_hex_to_uint8(dec), MEM_PAGE_LEN); + utils_clear_buffers(); // clean up dec in utils_buffer + break; + case MEM_MAP_V1: + // Encrypted length is length of cipher + IV + padding + hmac + enc_len = MEM_PAGE_LEN + N_BLOCK + (N_BLOCK - (MEM_PAGE_LEN % N_BLOCK)) + + SHA256_DIGEST_LENGTH; + dec = cipher_aes_hmac_decrypt((unsigned char *)enc_r, enc_len, &dec_len, mempass); + if (!dec) { + goto err; + } + break; + default: + goto err; } + if (read_b) { - memcpy(read_b, utils_hex_to_uint8(dec), MEM_PAGE_LEN); + memcpy(read_b, dec, MEM_PAGE_LEN); } + utils_zero(dec, dec_len); free(dec); - utils_zero(mempass, MEM_PAGE_LEN); - utils_clear_buffers(); return DBB_OK; err: if (read_b) { @@ -199,24 +276,68 @@ static uint8_t memory_eeprom_crypt(const uint8_t *write_b, uint8_t *read_b, hmac_sha256(mempass, MEM_PAGE_LEN, read_b, MEM_PAGE_LEN, read_b); } utils_zero(mempass, MEM_PAGE_LEN); - utils_clear_buffers(); return DBB_ERROR; } +static void memory_byte_flag(uint8_t *write_b, uint8_t *read_b, + int32_t addr, uint8_t byte_len) +{ + memory_eeprom(write_b, read_b, addr, byte_len); + if (MEM_memory_map_version != MEM_DEFAULT_memory_map_version) { + uint8_t usersig[FLASH_USERSIG_SIZE]; + if (flash_wrapper_read_usersig((uint32_t *)usersig, + FLASH_USERSIG_SIZE / sizeof(uint32_t))) { + utils_zero(usersig, sizeof(usersig)); + goto err; + } + if (write_b) { + if (!MEMEQ(usersig + FLASH_USERSIG_FLAG_START + addr, write_b, byte_len)) { + memcpy(usersig + FLASH_USERSIG_FLAG_START + addr, write_b, byte_len); + flash_wrapper_erase_usersig(); + flash_wrapper_write_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + } + } + if (!MEMEQ(usersig + FLASH_USERSIG_FLAG_START + addr, read_b, byte_len)) { + utils_zero(usersig, sizeof(usersig)); + goto err; + } + utils_zero(usersig, sizeof(usersig)); + } + return; +err: + memory_reset_hww(); +} + + static void memory_write_setup(uint8_t setup) { - memory_eeprom(&setup, &MEM_setup, MEM_SETUP_ADDR, 1); + memory_byte_flag(&setup, &MEM_setup, MEM_SETUP_ADDR, sizeof(MEM_setup)); } static uint8_t memory_read_setup(void) { - memory_eeprom(NULL, &MEM_setup, MEM_SETUP_ADDR, 1); + memory_byte_flag(NULL, &MEM_setup, MEM_SETUP_ADDR, sizeof(MEM_setup)); return MEM_setup; } +void memory_write_memory_map_version(uint32_t v) +{ + memory_byte_flag((uint8_t *)&v, (uint8_t *)&MEM_memory_map_version, + MEM_MEMORY_MAP_VERSION_ADDR, sizeof(MEM_memory_map_version)); +} + + +static uint32_t memory_read_memory_map_version(void) +{ + memory_byte_flag(NULL, (uint8_t *)&MEM_memory_map_version, MEM_MEMORY_MAP_VERSION_ADDR, + sizeof(MEM_memory_map_version)); + return MEM_memory_map_version; +} + + static void memory_scramble_default_aeskeys(void) { uint8_t number[32] = {0}; @@ -234,12 +355,12 @@ static void memory_scramble_rn(void) uint8_t usersig[FLASH_USERSIG_SIZE]; uint8_t number[FLASH_USERSIG_RN_LEN] = {0}; random_bytes(number, FLASH_USERSIG_RN_LEN, 0); - flash_read_user_signature((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + flash_wrapper_read_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); for (i = 0; i < FLASH_USERSIG_RN_LEN; i++) { - usersig[i] ^= number[i]; + usersig[i + FLASH_USERSIG_RN_START] ^= number[i]; } - flash_erase_user_signature(); - flash_write_user_signature((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + flash_wrapper_erase_usersig(); + flash_wrapper_write_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); } @@ -256,13 +377,15 @@ void memory_setup(void) HardFault_Handler(); } uint32_t c = 0x00000000; + memory_write_memory_map_version(ACTIVE_memory_map_version); memory_reset_hww(); memory_reset_u2f(); - memory_eeprom((uint8_t *)&c, (uint8_t *)&MEM_u2f_count, MEM_U2F_COUNT_ADDR, 4); + memory_u2f_count_set(c); memory_write_setup(0x00); } else { + memory_update_memory_map(); memory_read_ext_flags(); - memory_eeprom(NULL, &MEM_erased, MEM_ERASED_ADDR, 1); + memory_read_erased(); memory_master_u2f(NULL);// Load cache so that U2F speed is fast enough memory_read_access_err_count();// Load cache memory_u2f_count_read(); @@ -271,6 +394,97 @@ void memory_setup(void) } +void memory_update_memory_map(void) +{ + // Future mappings can be updated sequentially through memory map versions. + // This is useful, for example, if a firmware upgrade that updated a mapping was skipped. + switch (memory_read_memory_map_version()) { + case MEM_DEFAULT_memory_map_version: { + // Remap ECC and AES key memory + { + uint8_t a, i, mem0[MEM_PAGE_LEN], mem1[MEM_PAGE_LEN], ret0, ret1; + uint16_t addr_idx; + uint16_t addr_idxs[] = { + MEM_MASTER_ENTROPY_ADDR_IDX, + MEM_MASTER_BIP32_ADDR_IDX, + MEM_MASTER_BIP32_CHAIN_ADDR_IDX, + MEM_HIDDEN_BIP32_ADDR_IDX, + MEM_HIDDEN_BIP32_CHAIN_ADDR_IDX, + MEM_AESKEY_STAND_ADDR_IDX, + MEM_AESKEY_SHARED_SECRET_ADDR_IDX, + MEM_AESKEY_HIDDEN_ADDR_IDX, + MEM_MASTER_U2F_ADDR_IDX, + }; + memset(mem0, 0xFF, sizeof(mem0)); + memset(mem1, 0xFF, sizeof(mem1)); + for (a = 0; a < sizeof(addr_idxs) / sizeof(uint16_t); a++) { + addr_idx = addr_idxs[a]; + while (1) { + ret0 = memory_eeprom_crypt(NULL, mem0, addr_idx, MEM_MAP_V0); + ret1 = memory_eeprom_crypt(NULL, mem1, addr_idx, MEM_MAP_V1); + if (ret0 == DBB_OK && ret1 != DBB_OK) { + // Copy memory; `continue` to verify the value was copied correctly + memory_eeprom_crypt(mem0, mem1, addr_idx, MEM_MAP_V1); + continue; + } + if (ret0 == DBB_OK && ret1 == DBB_OK) { + if (MEMEQ(mem0, mem1, MEM_PAGE_LEN)) { + // Set the old memory location to chip default 0xFF + for (i = 0; i < MEM_NUM_CRYPT_EEPROM_WRITES; i++) { + memory_eeprom(MEM_PAGE_ERASE, NULL, MEM_ADDR_V0[addr_idx] + MEM_PAGE_LEN * i, + MEM_PAGE_LEN); + } + } else { + // Unexpected outcome; erase old memory location; set new memory location to chip default 0xFF + memory_eeprom_crypt(MEM_PAGE_ERASE, mem0, addr_idx, MEM_MAP_V0); + for (i = 0; i < MEM_NUM_CRYPT_EEPROM_WRITES; i++) { + memory_eeprom(MEM_PAGE_ERASE, NULL, MEM_ADDR_V1[addr_idx] + MEM_PAGE_LEN * i, + MEM_PAGE_LEN); + } + } + continue; + } + if (ret0 != DBB_OK && ret1 == DBB_OK) { + // Remap completed + break; + } + if (ret0 != DBB_OK && ret1 != DBB_OK) { + // Unexpected condition; erase old memory location + memory_eeprom_crypt(MEM_PAGE_ERASE, mem0, addr_idx, MEM_MAP_V0); + continue; + } + } + } + } + // Remap device name + { + uint8_t name[MEM_PAGE_LEN]; + memory_eeprom(NULL, name, MEM_ADDR_V0[MEM_NAME_ADDR_IDX], MEM_PAGE_LEN); + memory_eeprom_crypt(name, NULL, MEM_NAME_ADDR_IDX, MEM_MAP_V1); + memory_eeprom(MEM_PAGE_ERASE, NULL, MEM_ADDR_V0[MEM_NAME_ADDR_IDX], MEM_PAGE_LEN); + } + // Copy settings flags to FLASH + { + uint8_t usersig[FLASH_USERSIG_SIZE]; + uint8_t flags[FLASH_USERSIG_FLAG_LEN]; + memory_eeprom(NULL, flags, 0, sizeof(flags)); + flash_wrapper_read_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + memcpy(usersig + FLASH_USERSIG_FLAG_START, flags, sizeof(flags)); + flash_wrapper_erase_usersig(); + flash_wrapper_write_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + } + // Update map version + memory_write_memory_map_version(MEM_MAP_V1); + /* FALLTHROUGH */ + } + case ACTIVE_memory_map_version: + break; + default: + commander_force_reset(); + } +} + + void memory_erase_hww_seed(void) { memory_master_hww_entropy(MEM_PAGE_ERASE); @@ -281,7 +495,6 @@ void memory_erase_hww_seed(void) memory_random_password(PASSWORD_HIDDEN); } - void memory_reset_hww(void) { uint8_t u2f[MEM_PAGE_LEN]; @@ -293,9 +506,9 @@ void memory_reset_hww(void) memory_random_password(PASSWORD_HIDDEN); memory_erase_hww_seed(); memory_name(DEVICE_DEFAULT_NAME); - memory_write_erased(DEFAULT_erased); - memory_write_unlocked(DEFAULT_unlocked); - memory_write_ext_flags(DEFAULT_ext_flags); + memory_write_erased(MEM_DEFAULT_erased); + memory_write_unlocked(MEM_DEFAULT_unlocked); + memory_write_ext_flags(MEM_DEFAULT_ext_flags); memory_access_err_count(DBB_ACCESS_INITIALIZE); memory_pin_err_count(DBB_ACCESS_INITIALIZE); utils_zero(u2f, sizeof(u2f)); @@ -336,12 +549,14 @@ void memory_clear(void) uint8_t *memory_name(const char *name) { - uint8_t name_b[MEM_PAGE_LEN] = {0}; + char name_capped_len[MEM_PAGE_LEN]; if (strlens(name)) { - snprintf((char *)name_b, MEM_PAGE_LEN, "%s", name); - memory_eeprom(name_b, MEM_name, MEM_NAME_ADDR, MEM_PAGE_LEN); + memset(name_capped_len, 0, sizeof(name_capped_len)); + snprintf(name_capped_len, MEM_PAGE_LEN, "%s", name); + memory_eeprom_crypt((const uint8_t *)name_capped_len, MEM_name, MEM_NAME_ADDR_IDX, + MEM_memory_map_version); } else { - memory_eeprom(NULL, MEM_name, MEM_NAME_ADDR, MEM_PAGE_LEN); + memory_eeprom_crypt(NULL, MEM_name, MEM_NAME_ADDR_IDX, MEM_memory_map_version); } return MEM_name; } @@ -349,52 +564,60 @@ uint8_t *memory_name(const char *name) uint8_t *memory_hidden_hww(const uint8_t *master) { - memory_eeprom_crypt(NULL, MEM_hidden_hww, MEM_HIDDEN_BIP32_ADDR); + memory_eeprom_crypt(NULL, MEM_hidden_hww, MEM_HIDDEN_BIP32_ADDR_IDX, + MEM_memory_map_version); if ((master == NULL) && MEMEQ(MEM_hidden_hww, MEM_PAGE_ERASE, 32)) { // Backward compatible with firmware <=2.2.3 return memory_master_hww_chaincode(NULL); } - memory_eeprom_crypt(master, MEM_hidden_hww, MEM_HIDDEN_BIP32_ADDR); + memory_eeprom_crypt(master, MEM_hidden_hww, MEM_HIDDEN_BIP32_ADDR_IDX, + MEM_memory_map_version); return MEM_hidden_hww; } uint8_t *memory_hidden_hww_chaincode(const uint8_t *chain) { - memory_eeprom_crypt(NULL, MEM_hidden_hww_chain, MEM_HIDDEN_BIP32_CHAIN_ADDR); + memory_eeprom_crypt(NULL, MEM_hidden_hww_chain, MEM_HIDDEN_BIP32_CHAIN_ADDR_IDX, + MEM_memory_map_version); if ((chain == NULL) && MEMEQ(MEM_hidden_hww_chain, MEM_PAGE_ERASE, 32)) { // Backward compatible with firmware <=2.2.3 return memory_master_hww(NULL); } - memory_eeprom_crypt(chain, MEM_hidden_hww_chain, MEM_HIDDEN_BIP32_CHAIN_ADDR); + memory_eeprom_crypt(chain, MEM_hidden_hww_chain, MEM_HIDDEN_BIP32_CHAIN_ADDR_IDX, + MEM_memory_map_version); return MEM_hidden_hww_chain; } uint8_t *memory_master_hww(const uint8_t *master) { - memory_eeprom_crypt(master, MEM_master_hww, MEM_MASTER_BIP32_ADDR); + memory_eeprom_crypt(master, MEM_master_hww, MEM_MASTER_BIP32_ADDR_IDX, + MEM_memory_map_version); return MEM_master_hww; } uint8_t *memory_master_hww_chaincode(const uint8_t *chain) { - memory_eeprom_crypt(chain, MEM_master_hww_chain, MEM_MASTER_BIP32_CHAIN_ADDR); + memory_eeprom_crypt(chain, MEM_master_hww_chain, MEM_MASTER_BIP32_CHAIN_ADDR_IDX, + MEM_memory_map_version); return MEM_master_hww_chain; } uint8_t *memory_master_hww_entropy(const uint8_t *master_entropy) { - memory_eeprom_crypt(master_entropy, MEM_master_hww_entropy, MEM_MASTER_ENTROPY_ADDR); + memory_eeprom_crypt(master_entropy, MEM_master_hww_entropy, MEM_MASTER_ENTROPY_ADDR_IDX, + MEM_memory_map_version); return MEM_master_hww_entropy; } uint8_t *memory_master_u2f(const uint8_t *master_u2f) { - memory_eeprom_crypt(master_u2f, MEM_master_u2f, MEM_MASTER_U2F_ADDR); + memory_eeprom_crypt(master_u2f, MEM_master_u2f, MEM_MASTER_U2F_ADDR_IDX, + MEM_memory_map_version); return MEM_master_u2f; } @@ -421,7 +644,7 @@ uint8_t *memory_active_key_get(void) uint8_t memory_write_tfa_shared_secret(const uint8_t *secret) { int ret = memory_eeprom_crypt(secret, MEM_aeskey_verify, - MEM_AESKEY_SHARED_SECRET_ADDR) - DBB_OK; + MEM_AESKEY_SHARED_SECRET_ADDR_IDX, MEM_memory_map_version) - DBB_OK; if (ret) { return DBB_ERR_MEM_ATAES; } else { @@ -455,9 +678,11 @@ uint8_t memory_write_aeskey(const char *password, int len, PASSWORD_ID id) } ret |= memory_eeprom_crypt(MEM_aeskey_stand, MEM_aeskey_stand, - MEM_AESKEY_STAND_ADDR) - DBB_OK; + MEM_AESKEY_STAND_ADDR_IDX, MEM_memory_map_version) - DBB_OK; ret |= memory_eeprom_crypt(MEM_aeskey_hidden, MEM_aeskey_hidden, - MEM_AESKEY_HIDDEN_ADDR) - DBB_OK; + MEM_AESKEY_HIDDEN_ADDR_IDX, MEM_memory_map_version) - DBB_OK; + ret |= memory_eeprom_crypt(MEM_aeskey_verify, MEM_aeskey_verify, + MEM_AESKEY_SHARED_SECRET_ADDR_IDX, MEM_memory_map_version) - DBB_OK; utils_zero(password_b, MEM_PAGE_LEN); @@ -473,9 +698,12 @@ void memory_read_aeskeys(void) { static uint8_t read = 0; if (!read) { - memory_eeprom_crypt(NULL, MEM_aeskey_stand, MEM_AESKEY_STAND_ADDR); - memory_eeprom_crypt(NULL, MEM_aeskey_hidden, MEM_AESKEY_HIDDEN_ADDR); - memory_eeprom_crypt(NULL, MEM_aeskey_verify, MEM_AESKEY_SHARED_SECRET_ADDR); + memory_eeprom_crypt(NULL, MEM_aeskey_stand, MEM_AESKEY_STAND_ADDR_IDX, + MEM_memory_map_version); + memory_eeprom_crypt(NULL, MEM_aeskey_hidden, MEM_AESKEY_HIDDEN_ADDR_IDX, + MEM_memory_map_version); + memory_eeprom_crypt(NULL, MEM_aeskey_verify, MEM_AESKEY_SHARED_SECRET_ADDR_IDX, + MEM_memory_map_version); sha256_Raw(MEM_aeskey_stand, MEM_PAGE_LEN, MEM_user_entropy); read++; } @@ -511,22 +739,22 @@ uint8_t memory_report_setup(void) void memory_write_unlocked(uint8_t u) { - memory_eeprom(&u, &MEM_unlocked, MEM_UNLOCKED_ADDR, 1); + memory_byte_flag(&u, &MEM_unlocked, MEM_UNLOCKED_ADDR, sizeof(MEM_unlocked)); } uint8_t memory_read_unlocked(void) { - memory_eeprom(NULL, &MEM_unlocked, MEM_UNLOCKED_ADDR, 1); + memory_byte_flag(NULL, &MEM_unlocked, MEM_UNLOCKED_ADDR, sizeof(MEM_unlocked)); return MEM_unlocked; } void memory_write_erased(uint8_t erased) { - memory_eeprom(&erased, &MEM_erased, MEM_ERASED_ADDR, 1); + memory_byte_flag(&erased, &MEM_erased, MEM_ERASED_ADDR, sizeof(MEM_erased)); } uint8_t memory_read_erased(void) { - memory_eeprom(NULL, &MEM_erased, MEM_ERASED_ADDR, 1); + memory_byte_flag(NULL, &MEM_erased, MEM_ERASED_ADDR, sizeof(MEM_erased)); return MEM_erased; } uint8_t memory_report_erased(void) @@ -539,7 +767,8 @@ uint16_t memory_access_err_count(const uint8_t access) { uint16_t err_count = 0xF0F0; if (access == DBB_ACCESS_ITERATE) { - memory_eeprom(NULL, (uint8_t *)&MEM_access_err, MEM_ACCESS_ERR_ADDR, 2); + memory_byte_flag(NULL, (uint8_t *)&MEM_access_err, MEM_ACCESS_ERR_ADDR, + sizeof(MEM_access_err)); err_count = MEM_access_err + 1; } else if (access == DBB_ACCESS_INITIALIZE) { err_count = 0; @@ -551,13 +780,15 @@ uint16_t memory_access_err_count(const uint8_t access) if (err_count >= COMMANDER_MAX_ATTEMPTS) { commander_force_reset(); } else { - memory_eeprom((uint8_t *)&err_count, (uint8_t *)&MEM_access_err, MEM_ACCESS_ERR_ADDR, 2); + memory_byte_flag((uint8_t *)&err_count, (uint8_t *)&MEM_access_err, + MEM_ACCESS_ERR_ADDR, sizeof(MEM_access_err)); } return err_count; } uint16_t memory_read_access_err_count(void) { - memory_eeprom(NULL, (uint8_t *)&MEM_access_err, MEM_ACCESS_ERR_ADDR, 2); + memory_byte_flag(NULL, (uint8_t *)&MEM_access_err, MEM_ACCESS_ERR_ADDR, + sizeof(MEM_access_err)); return MEM_access_err; } uint16_t memory_report_access_err_count(void) @@ -570,7 +801,7 @@ uint16_t memory_pin_err_count(const uint8_t access) { uint16_t err_count = 0xF0F0; if (access == DBB_ACCESS_ITERATE) { - memory_eeprom(NULL, (uint8_t *)&MEM_pin_err, MEM_PIN_ERR_ADDR, 2); + memory_byte_flag(NULL, (uint8_t *)&MEM_pin_err, MEM_PIN_ERR_ADDR, sizeof(MEM_pin_err)); err_count = MEM_pin_err + 1; } else if (access == DBB_ACCESS_INITIALIZE) { err_count = 0; @@ -582,13 +813,14 @@ uint16_t memory_pin_err_count(const uint8_t access) if (err_count >= COMMANDER_MAX_ATTEMPTS) { commander_force_reset(); } else { - memory_eeprom((uint8_t *)&err_count, (uint8_t *)&MEM_pin_err, MEM_PIN_ERR_ADDR, 2); + memory_byte_flag((uint8_t *)&err_count, (uint8_t *)&MEM_pin_err, MEM_PIN_ERR_ADDR, + sizeof(MEM_pin_err)); } return err_count; } uint16_t memory_read_pin_err_count(void) { - memory_eeprom(NULL, (uint8_t *)&MEM_pin_err, MEM_PIN_ERR_ADDR, 2); + memory_byte_flag(NULL, (uint8_t *)&MEM_pin_err, MEM_PIN_ERR_ADDR, sizeof(MEM_pin_err)); return MEM_pin_err; } @@ -598,27 +830,31 @@ uint32_t memory_u2f_count_iter(void) uint32_t c; memory_u2f_count_read(); c = MEM_u2f_count + 1; - memory_eeprom((uint8_t *)&c, (uint8_t *)&MEM_u2f_count, MEM_U2F_COUNT_ADDR, 4); + memory_eeprom((uint8_t *)&c, (uint8_t *)&MEM_u2f_count, MEM_U2F_COUNT_ADDR, + sizeof(MEM_u2f_count)); return MEM_u2f_count; } void memory_u2f_count_set(uint32_t c) { - memory_eeprom((uint8_t *)&c, (uint8_t *)&MEM_u2f_count, MEM_U2F_COUNT_ADDR, 4); + memory_eeprom((uint8_t *)&c, (uint8_t *)&MEM_u2f_count, MEM_U2F_COUNT_ADDR, + sizeof(MEM_u2f_count)); } uint32_t memory_u2f_count_read(void) { - memory_eeprom(NULL, (uint8_t *)&MEM_u2f_count, MEM_U2F_COUNT_ADDR, 4); + memory_eeprom(NULL, (uint8_t *)&MEM_u2f_count, MEM_U2F_COUNT_ADDR, sizeof(MEM_u2f_count)); return MEM_u2f_count; } void memory_write_ext_flags(uint32_t flags) { - memory_eeprom((uint8_t *)&flags, (uint8_t *)&MEM_ext_flags, MEM_EXT_FLAGS_ADDR, 4); + memory_byte_flag((uint8_t *)&flags, (uint8_t *)&MEM_ext_flags, MEM_EXT_FLAGS_ADDR, + sizeof(MEM_ext_flags)); } uint32_t memory_read_ext_flags(void) { - memory_eeprom(NULL, (uint8_t *)&MEM_ext_flags, MEM_EXT_FLAGS_ADDR, 4); + memory_byte_flag(NULL, (uint8_t *)&MEM_ext_flags, MEM_EXT_FLAGS_ADDR, + sizeof(MEM_ext_flags)); return MEM_ext_flags; } uint32_t memory_report_ext_flags(void) diff --git a/src/memory.h b/src/memory.h index d658dd58..c54dd402 100644 --- a/src/memory.h +++ b/src/memory.h @@ -31,43 +31,15 @@ #include #define MEM_PAGE_LEN 32 - -// User Zones: 0x0000 to 0x0FFF -// Do NOT change address locations. -// Otherwise problems will occur after a firmware update. -#define MEM_ERASED_ADDR 0x0000// (uint8_t) Zone 0 -#define MEM_SETUP_ADDR 0x0002// (uint8_t) -#define MEM_ACCESS_ERR_ADDR 0x0004// (uint16_t) -#define MEM_PIN_ERR_ADDR 0x0006// (uint16_t) -#define MEM_UNLOCKED_ADDR 0x0008// (uint8_t) -#define MEM_EXT_FLAGS_ADDR 0x000A// (uint32_t) 32 possible extension flags -#define MEM_U2F_COUNT_ADDR 0x0010// (uint32_t) -#define MEM_NAME_ADDR 0x0100// (32 bytes) Zone 1 -#define MEM_MASTER_BIP32_ADDR 0x0200 -#define MEM_MASTER_BIP32_CHAIN_ADDR 0x0300 -#define MEM_AESKEY_STAND_ADDR 0x0400 -#define MEM_AESKEY_SHARED_SECRET_ADDR 0x0500 -#define MEM_AESKEY_Z6_ADDR 0x0600// Zone 6 reserved first 32*4 bytes -#define MEM_AESKEY_Z7_ADDR 0x0700// Zone 7 reserved -#define MEM_AESKEY_HIDDEN_ADDR 0x0800 -#define MEM_MASTER_ENTROPY_ADDR 0x0900 -#define MEM_MASTER_U2F_ADDR 0x0A00 -#define MEM_HIDDEN_BIP32_ADDR 0x0B00 -#define MEM_HIDDEN_BIP32_CHAIN_ADDR 0x0B80 - - -// Extension flags -#define MEM_EXT_MASK_U2F 0x00000001// Mask of bit to enable (1) or disable (0) U2F functions -// Will override and disable U2F_HIJACK bit when disabled -#define MEM_EXT_MASK_U2F_HIJACK 0x00000002// Mask of bit to enable (1) or disable (0) U2F_HIJACK interface - - +#define MEM_EXT_MASK_U2F 0x00000001 // Mask of bit to enable (1) or disable (0) U2F functions; will override and disable U2F_HIJACK bit when disabled +#define MEM_EXT_MASK_U2F_HIJACK 0x00000002 // Mask of bit to enable (1) or disable (0) U2F_HIJACK interface // Default settings -#define DEFAULT_unlocked 0xFF -#define DEFAULT_erased 0xFF -#define DEFAULT_setup 0xFF -#define DEFAULT_u2f_count 0xFFFFFFFF -#define DEFAULT_ext_flags 0xFFFFFFFF// U2F and U2F_hijack enabled by default +#define MEM_DEFAULT_unlocked 0xFF +#define MEM_DEFAULT_erased 0xFF +#define MEM_DEFAULT_setup 0xFF +#define MEM_DEFAULT_u2f_count 0xFFFFFFFF +#define MEM_DEFAULT_ext_flags 0xFFFFFFFF// U2F and U2F_hijack enabled by default +#define MEM_DEFAULT_memory_map_version 0xFFFFFFFF typedef enum PASSWORD_ID { @@ -78,7 +50,9 @@ typedef enum PASSWORD_ID { } PASSWORD_ID; +void memory_write_memory_map_version(uint32_t v); void memory_setup(void); +void memory_update_memory_map(void); void memory_reset_u2f(void); void memory_reset_hww(void); void memory_erase_hww_seed(void); diff --git a/src/random.c b/src/random.c index 55172202..1a0e835b 100644 --- a/src/random.c +++ b/src/random.c @@ -72,7 +72,7 @@ int random_bytes(uint8_t *buf, uint32_t len, uint8_t update_seed) memset(buf, 0, len); // Add entropy from second chip (MCU UID) - flash_read_unique_id(serial, 4); + flash_wrapper_read_unique_id(serial, 4); sha256_Raw((uint8_t *)serial, sizeof(serial), entropy); for (i = 0; i < MIN(len, MEM_PAGE_LEN); i++) { buf[i] ^= entropy[i]; @@ -90,13 +90,13 @@ int random_bytes(uint8_t *buf, uint32_t len, uint8_t update_seed) buf[i] ^= entropy[i]; } // Add entropy from the random number stored in the MCU's 'user signature' memory area - flash_read_user_signature((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + flash_wrapper_read_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); sha256_Raw(usersig, FLASH_USERSIG_SIZE, entropy); for (i = 0; i < MIN(len, MEM_PAGE_LEN); i++) { buf[i] ^= entropy[i]; } for (i = 0; i < MAX(FLASH_USERSIG_RN_LEN, MEM_PAGE_LEN); i++) { - usersig[i % FLASH_USERSIG_RN_LEN] = entropy[i % MEM_PAGE_LEN]; + usersig[(i + FLASH_USERSIG_RN_START) % FLASH_USERSIG_SIZE] = entropy[i % MEM_PAGE_LEN]; } // Add entropy from ataes RNG const uint8_t ataes_cmd[] = {ATAES_CMD_RAND, 0x02, 0x00, 0x00, 0x00, 0x00}; // Pseudo RNG @@ -114,8 +114,9 @@ int random_bytes(uint8_t *buf, uint32_t len, uint8_t update_seed) buf[(n + i)] ^= entropy[i]; } } else { - flash_erase_user_signature(); - flash_write_user_signature((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + flash_wrapper_erase_usersig(); + flash_wrapper_write_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + utils_zero(usersig, FLASH_USERSIG_SIZE); HardFault_Handler(); return DBB_ERROR; } diff --git a/src/sharedsecret.h b/src/sharedsecret.h deleted file mode 100644 index f01479b2..00000000 --- a/src/sharedsecret.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - - The MIT License (MIT) - - Copyright (c) 2015-2018 Douglas J. Bakkum - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#ifndef _SHAREDSECRET_H_ -#define _SHAREDSECRET_H_ - -void sharedsecret_derive_keys(const uint8_t *shared_secret, uint8_t *encryption_key, - uint8_t *authentication_key); - -#endif diff --git a/src/startup.c b/src/startup.c index 5b3ced12..438f13f3 100644 --- a/src/startup.c +++ b/src/startup.c @@ -47,6 +47,7 @@ extern void __attribute__((noreturn)) __stack_chk_fail(void); void __attribute__((noreturn)) __stack_chk_fail(void) { udc_stop(); + board_com_deinit(); while (1) { led_toggle(); delay_ms(300); @@ -63,6 +64,7 @@ void SysTick_Handler(void) void HardFault_Handler(void) { udc_stop(); + board_com_deinit(); while (1) { led_toggle(); delay_ms(500); @@ -73,6 +75,7 @@ void HardFault_Handler(void) void MemManage_Handler(void) { udc_stop(); + board_com_deinit(); while (1) { led_toggle(); delay_ms(1000); diff --git a/tests/api.h b/tests/api.h index b2bf8cf0..65048dd4 100644 --- a/tests/api.h +++ b/tests/api.h @@ -36,7 +36,7 @@ #include "u2f/u2f.h" #include "u2f_device.h" #include "commander.h" -#include "aescbcb64.h" +#include "cipher.h" #include "random.h" #include "utest.h" #include "usb.h" @@ -107,8 +107,8 @@ static void api_decrypt_report(const char *report, uint8_t *key) const char *ciphertext = YAJL_GET_STRING(yajl_tree_get(json_node, ciphertext_path, yajl_t_string)); if (ciphertext) { - dec = aescbcb64_decrypt((const unsigned char *)ciphertext, strlens(ciphertext), - &decrypt_len, key); + dec = cipher_aes_b64_decrypt((const unsigned char *)ciphertext, strlens(ciphertext), + &decrypt_len, key); if (!dec) { strcpy(decrypted_report, "/* error: Failed to decrypt. */"); goto exit; @@ -393,7 +393,8 @@ static void api_hid_send(const char *cmd) static void api_hid_send_encrypt(const char *cmd, uint8_t *key) { int enc_len; - char *enc = aescbcb64_encrypt((const unsigned char *)cmd, strlens(cmd), &enc_len, key); + char *enc = cipher_aes_b64_encrypt((const unsigned char *)cmd, strlens(cmd), &enc_len, + key); api_hid_send_len(enc, enc_len); free(enc); } @@ -505,8 +506,8 @@ static char *api_read_value_decrypt(int cmd, uint8_t *key) memset(val_dec, 0, sizeof(val_dec)); int decrypt_len; - char *dec = aescbcb64_decrypt((const unsigned char *)val, strlens(val), - &decrypt_len, key); + char *dec = cipher_aes_b64_decrypt((const unsigned char *)val, strlens(val), + &decrypt_len, key); snprintf(val_dec, HID_REPORT_SIZE, "%.*s", decrypt_len, dec); free(dec); diff --git a/tests/hmac_check.h b/tests/hmac_check.h index 13b6c186..54852bc6 100644 --- a/tests/hmac_check.h +++ b/tests/hmac_check.h @@ -31,8 +31,7 @@ #include #include "yajl/src/api/yajl_tree.h" -#include "sharedsecret.h" -#include "aescbcb64.h" +#include "cipher.h" #include "base64.h" #include "flags.h" #include "utils.h" @@ -42,38 +41,19 @@ #include "aes.h" -/** - * Performs an hmac sha256 message integrity check and returns 0 if the integrity check - * failed and 1 if it succeeded. - */ -static int check_hmac_sha256(const uint8_t *key, const uint32_t keylen, - const unsigned char *in, - const unsigned int length, const uint8_t *hmac) +static char *cipher_aes_b64_hmac_decrypt(const unsigned char *in, int inlen, + int *out_msg_len, const uint8_t *secret) { - uint8_t verify_hmac[SHA256_DIGEST_LENGTH]; - hmac_sha256(key, keylen, in, length, verify_hmac); - if (MEMEQ(hmac, verify_hmac, SHA256_DIGEST_LENGTH)) { - return 1; - } - return 0; -} - + unsigned char *ub64; + char *decrypted; + int ub64len; -static char *decrypt_and_check_hmac(const unsigned char *in, int inlen, int *out_msg_len, - const uint8_t *shared_secret, uint8_t *out_hmac) -{ - if (!in || inlen == 0) { + if (!in || inlen == 0 || !secret) { return NULL; } - uint8_t encryption_key[SHA256_DIGEST_LENGTH]; - uint8_t authentication_key[SHA256_DIGEST_LENGTH]; - - sharedsecret_derive_keys(shared_secret, encryption_key, authentication_key); - // Unbase64 - int ub64len; - unsigned char *ub64 = unbase64((const char *)in, inlen, &ub64len); + ub64 = unbase64((const char *)in, inlen, &ub64len); if (!ub64) { return NULL; } @@ -83,22 +63,10 @@ static char *decrypt_and_check_hmac(const unsigned char *in, int inlen, int *out return NULL; } - memcpy(out_hmac, ub64 + (ub64len - SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH); - int hmac_len = ub64len - SHA256_DIGEST_LENGTH; - - char *decrypted = NULL; - if (check_hmac_sha256(authentication_key, SHA256_DIGEST_LENGTH, ub64, hmac_len, - out_hmac)) { - decrypted = aescbcb64_init_and_decrypt(ub64, - ub64len - SHA256_DIGEST_LENGTH, - out_msg_len, - encryption_key); - } + decrypted = cipher_aes_hmac_decrypt(ub64, ub64len, out_msg_len, secret); memset(ub64, 0, ub64len); free(ub64); - utils_zero(encryption_key, sizeof(encryption_key)); - utils_zero(authentication_key, sizeof(authentication_key)); return decrypted; } diff --git a/tests/tests_api.c b/tests/tests_api.c index d2433cde..09ebdf70 100644 --- a/tests/tests_api.c +++ b/tests/tests_api.c @@ -38,7 +38,7 @@ #include "utils.h" #include "flags.h" #include "random.h" -#include "aescbcb64.h" +#include "cipher.h" #include "commander.h" #include "yajl/src/api/yajl_tree.h" #include "secp256k1/include/secp256k1.h" @@ -133,10 +133,9 @@ static void tests_seed_xpub_backup(void) if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_eq(xpub0, echo); free(echo); @@ -177,10 +176,9 @@ static void tests_seed_xpub_backup(void) memcpy(xpub1, api_read_value(CMD_xpub), sizeof(xpub1)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_eq(xpub0, echo); free(echo); @@ -1146,10 +1144,9 @@ static void tests_u2f(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has(echo, KEYPATH_ONE); free(echo); @@ -1193,10 +1190,9 @@ static void tests_u2f(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has(echo, KEYPATH_ONE); free(echo); @@ -1222,10 +1218,9 @@ static void tests_u2f(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has(echo, KEYPATH_ONE); free(echo); @@ -1275,10 +1270,9 @@ static void tests_u2f(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has(echo, KEYPATH_ONE); free(echo); @@ -1304,10 +1298,9 @@ static void tests_u2f(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has(echo, KEYPATH_ONE); free(echo); @@ -1334,10 +1327,9 @@ static void tests_u2f(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has(echo, KEYPATH_ONE); free(echo); @@ -1481,10 +1473,9 @@ static void tests_device(void) yajl_t_string)); u_assert_int_eq(!ciphertext, 0); int decrypt_len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; - char *dec = decrypt_and_check_hmac((const unsigned char *)ciphertext, - strlens(ciphertext), - &decrypt_len, memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *dec = cipher_aes_b64_hmac_decrypt((const unsigned char *)ciphertext, + strlens(ciphertext), + &decrypt_len, memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(dec); u_assert_str_eq(dec, VERIFYPASS_CRYPT_TEST); free(dec); @@ -2043,10 +2034,9 @@ static void tests_echo_tfa(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has(echo, cmd_str(CMD_pin)); free(echo); @@ -2059,10 +2049,9 @@ static void tests_echo_tfa(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has(echo, cmd_str(CMD_pin)); free(echo); @@ -2305,10 +2294,9 @@ static void tests_sign(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has_not(echo, cmd_str(CMD_recid)); u_assert_str_has(echo, "_meta_data_"); @@ -2358,10 +2346,9 @@ static void tests_sign(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has_not(echo, cmd_str(CMD_recid)); u_assert_str_has(echo, "_meta_data_"); @@ -2423,10 +2410,9 @@ static void tests_sign(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has_not(echo, cmd_str(CMD_recid)); u_assert_str_has(echo, "\"meta\":"); @@ -2490,10 +2476,9 @@ static void tests_sign(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has_not(echo, cmd_str(CMD_recid)); u_assert_str_has(echo, "_meta_data_"); @@ -2514,10 +2499,9 @@ static void tests_sign(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has_not(echo, cmd_str(CMD_recid)); u_assert_str_has(echo, "_meta_data_"); @@ -2534,10 +2518,9 @@ static void tests_sign(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has_not(echo, cmd_str(CMD_recid)); u_assert_str_has(echo, "_meta_data_"); @@ -2567,10 +2550,9 @@ static void tests_sign(void) ASSERT_REPORT_HAS(cmd_str(CMD_echo)); if (!TEST_LIVE_DEVICE) { int len; - uint8_t hmac[SHA256_DIGEST_LENGTH]; const char *val = api_read_value(CMD_echo); - char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len, - memory_report_aeskey(TFA_SHARED_SECRET), hmac); + char *echo = cipher_aes_b64_hmac_decrypt((const unsigned char *)val, strlens(val), &len, + memory_report_aeskey(TFA_SHARED_SECRET)); u_assert(echo); u_assert_str_has_not(echo, cmd_str(CMD_recid)); u_assert_str_has(echo, "_meta_data_"); @@ -2629,8 +2611,10 @@ static void tests_memory_setup(void) ASSERT_REPORT_HAS(flag_msg(DBB_ERR_MEM_SETUP)); } + // Run twice, first time accesses one-time factory install code + // Memory map updating tested in unit_test.c + memory_setup(); memory_setup(); - memory_setup(); // run twice api_format_send_cmd(cmd_str(CMD_password), tests_pwd, NULL); ASSERT_SUCCESS; @@ -2649,9 +2633,9 @@ static void tests_memory_setup(void) static void run_utests(void) { u_run_test(tests_memory_setup);// Keep first + u_run_test(tests_name); u_run_test(tests_u2f); u_run_test(tests_echo_tfa); - u_run_test(tests_name); u_run_test(tests_password); u_run_test(tests_random); u_run_test(tests_device); diff --git a/tests/tests_unit.c b/tests/tests_unit.c index 4b5723c2..09cf705e 100644 --- a/tests/tests_unit.c +++ b/tests/tests_unit.c @@ -33,7 +33,9 @@ #include #include "commander.h" -#include "aescbcb64.h" +#include "ataes132.h" +#include "memory.h" +#include "cipher.h" #include "wallet.h" #include "random.h" #include "base64.h" @@ -41,6 +43,7 @@ #include "base64.h" #include "pbkdf2.h" #include "flags.h" +#include "flash.h" #include "bip32.h" #include "utils.h" #include "utest.h" @@ -693,41 +696,132 @@ static void test_aes_cbc(void) static void test_aes_encrypt_decrypt_hmac(void) { const char *msg = "A test msg.\n"; - int b64_length = 0; - const uint8_t *shared_secret = - utils_hex_to_uint8("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); - char *encrypted_msg = aescbcb64_hmac_encrypt((const unsigned char *)msg, strlen(msg), - &b64_length, shared_secret); - u_assert_int_eq(b64_length, strlen(encrypted_msg)); - - int out_length = 0; - uint8_t hmac[SHA256_DIGEST_LENGTH]; - char *decrypted_msg = decrypt_and_check_hmac((const unsigned char *)encrypted_msg, - b64_length, &out_length, - shared_secret, hmac); + char *encrypted_msg, *decrypted_msg; + int ub64_length, out_length, enc_length; + uint8_t shared_secret[32]; + memcpy(shared_secret, + utils_hex_to_uint8("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + 32); + + // Test aes b64 hmac encryption + char *corrupted_encrypted_b64_msg; + unsigned char *ub64; + // Encrypt + encrypted_msg = cipher_aes_b64_hmac_encrypt((const unsigned char *)msg, strlen(msg), + &enc_length, shared_secret); + u_assert(encrypted_msg); + u_assert_int_eq(enc_length, strlen(encrypted_msg)); + // Decrypt + decrypted_msg = cipher_aes_b64_hmac_decrypt((const unsigned char *)encrypted_msg, + enc_length, &out_length, shared_secret); u_assert(decrypted_msg); u_assert_str_eq(decrypted_msg, msg); u_assert_int_eq(out_length, strlen(msg) + 1); - - int ub64_length = 0; - unsigned char *ub64 = unbase64((const char *)encrypted_msg, b64_length, &ub64_length); + free(decrypted_msg); + // Unbase 64 + ub64 = unbase64((const char *)encrypted_msg, enc_length, &ub64_length); u_assert(ub64); - + // Corrupt the hmac unsigned char corrupted_encrypted_ub64_msg[ub64_length]; memcpy(corrupted_encrypted_ub64_msg, ub64, ub64_length); - // corrupt it... corrupted_encrypted_ub64_msg[ub64_length - 1]++; - char *corrupted_encrypted_b64_msg = base64(corrupted_encrypted_ub64_msg, ub64_length, - &b64_length); - - char *corrupted_decrypted_msg = decrypt_and_check_hmac((const unsigned char *) - corrupted_encrypted_b64_msg, b64_length, &out_length, - shared_secret, hmac); - u_assert(corrupted_decrypted_msg == NULL); - free(encrypted_msg); + corrupted_encrypted_b64_msg = base64(corrupted_encrypted_ub64_msg, ub64_length, + &enc_length); + u_assert(corrupted_encrypted_b64_msg); + decrypted_msg = cipher_aes_b64_hmac_decrypt((const unsigned char *) + corrupted_encrypted_b64_msg, + enc_length, &out_length, shared_secret); + u_assert(decrypted_msg == NULL); + u_assert_int_eq(out_length, 0); + free(corrupted_encrypted_b64_msg); free(decrypted_msg); + // Corrupt the message + memcpy(corrupted_encrypted_ub64_msg, ub64, ub64_length); + corrupted_encrypted_ub64_msg[0]++; + corrupted_encrypted_b64_msg = base64(corrupted_encrypted_ub64_msg, ub64_length, + &enc_length); + u_assert(corrupted_encrypted_b64_msg); + decrypted_msg = cipher_aes_b64_hmac_decrypt((const unsigned char *) + corrupted_encrypted_b64_msg, + enc_length, &out_length, shared_secret); + u_assert(decrypted_msg == NULL); + u_assert_int_eq(out_length, 0); + free(corrupted_encrypted_b64_msg); + free(decrypted_msg); + // Verify uncorrupted works + memcpy(corrupted_encrypted_ub64_msg, ub64, ub64_length); + corrupted_encrypted_b64_msg = base64(corrupted_encrypted_ub64_msg, ub64_length, + &enc_length); + u_assert(corrupted_encrypted_b64_msg); + decrypted_msg = cipher_aes_b64_hmac_decrypt((const unsigned char *) + corrupted_encrypted_b64_msg, + enc_length, &out_length, shared_secret); + u_assert(decrypted_msg); + u_assert_str_eq(decrypted_msg, msg); + u_assert_int_eq(out_length, strlen(msg) + 1); free(corrupted_encrypted_b64_msg); + free(decrypted_msg); + free(encrypted_msg); free(ub64); + + + // Test aes hmac encryption + // Encrypt + encrypted_msg = (char *)cipher_aes_hmac_encrypt((const unsigned char *)msg, + strlen(msg), &enc_length, shared_secret); + u_assert(encrypted_msg); + u_assert(enc_length); + // Decrypt + decrypted_msg = cipher_aes_hmac_decrypt((uint8_t *)encrypted_msg, + enc_length, &out_length, shared_secret); + u_assert(decrypted_msg); + u_assert_str_eq(decrypted_msg, msg); + u_assert_int_eq(out_length, strlen(msg) + 1); + free(decrypted_msg); + // Corrupt the hmac + encrypted_msg[enc_length - 1]++; + decrypted_msg = (char *)cipher_aes_hmac_decrypt((uint8_t *)encrypted_msg, + enc_length, &out_length, shared_secret); + u_assert(decrypted_msg == NULL); + u_assert_int_eq(out_length, 0); + free(decrypted_msg); + // Fix the hmac + encrypted_msg[enc_length - 1]--; + decrypted_msg = cipher_aes_hmac_decrypt((uint8_t *)encrypted_msg, + enc_length, &out_length, shared_secret); + u_assert_str_eq(decrypted_msg, msg); + free(decrypted_msg); + // Corrupt the message + encrypted_msg[0]++; + decrypted_msg = cipher_aes_hmac_decrypt((uint8_t *)encrypted_msg, + enc_length, &out_length, shared_secret); + u_assert(decrypted_msg == NULL); + u_assert_int_eq(out_length, 0); + free(decrypted_msg); + free(encrypted_msg); + + + // Test aes b64 encryption + // Encrypt + encrypted_msg = cipher_aes_b64_encrypt((const unsigned char *)msg, strlen(msg), + &enc_length, shared_secret); + u_assert(encrypted_msg); + u_assert_int_eq(enc_length, strlen(encrypted_msg)); + // Decrypt + decrypted_msg = cipher_aes_b64_decrypt((const unsigned char *)encrypted_msg, + enc_length, &out_length, shared_secret); + u_assert(decrypted_msg); + u_assert_str_eq(decrypted_msg, msg); + u_assert_int_eq(out_length, strlen(msg) + 1); + free(decrypted_msg); + // Corrupt the message + encrypted_msg[enc_length - 1]++; + decrypted_msg = cipher_aes_b64_decrypt((const unsigned char *)encrypted_msg, + enc_length, &out_length, shared_secret); + u_assert(decrypted_msg == NULL); + u_assert_int_eq(out_length, 0); + free(decrypted_msg); + free(encrypted_msg); } @@ -1116,6 +1210,488 @@ static void test_recoverable_signature(void) } +// Array of 0xFFs, corresponding to default eeprom and flash values +__extension__ const uint8_t FF_ARRAY[] = {[0 ... (MAX(ATAES_EEPROM_LEN, FLASH_USERSIG_SIZE) - 1)] = 0xFF}; + + +// eeprom zone for byte flags containing expected values after factory install (i.e. first firmware run) +const uint8_t eeprom_factory_zone0_v1[] = { + 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + + +// eeprom values for all zones containing an example v0 memory map +const uint8_t eeprom_factory_v0[] = { + 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x4d, 0x79, 0x20, 0x42, 0x69, 0x74, 0x42, 0x6f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x4c, 0x4c, 0x69, 0x64, 0x64, 0x62, 0x4b, 0x31, 0x65, 0x32, 0x32, 0x56, 0x53, 0x2f, 0x58, 0x6d, + 0x58, 0x76, 0x36, 0x65, 0x76, 0x49, 0x50, 0x2b, 0x6f, 0x61, 0x51, 0x78, 0x34, 0x41, 0x5a, 0x36, + 0x47, 0x73, 0x49, 0x34, 0x57, 0x7a, 0x74, 0x6f, 0x70, 0x6d, 0x37, 0x45, 0x32, 0x58, 0x47, 0x76, + 0x46, 0x72, 0x71, 0x59, 0x76, 0x7a, 0x39, 0x5a, 0x73, 0x66, 0x57, 0x6c, 0x6b, 0x78, 0x2f, 0x46, + 0x54, 0x2f, 0x67, 0x2f, 0x62, 0x58, 0x55, 0x63, 0x65, 0x4b, 0x70, 0x31, 0x49, 0x72, 0x4b, 0x61, + 0x75, 0x4b, 0x32, 0x4a, 0x65, 0x79, 0x4d, 0x48, 0x57, 0x6b, 0x75, 0x34, 0x30, 0x32, 0x41, 0x38, + 0x34, 0x37, 0x33, 0x56, 0x41, 0x61, 0x4d, 0x5a, 0x58, 0x54, 0x68, 0x32, 0x66, 0x68, 0x7a, 0x31, + 0x42, 0x52, 0x37, 0x4d, 0x6f, 0x59, 0x6a, 0x58, 0x2f, 0x5a, 0x55, 0x6a, 0x54, 0x33, 0x7a, 0x2f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x76, 0x46, 0x7a, 0x73, 0x6d, 0x43, 0x63, 0x43, 0x79, 0x4e, 0x41, 0x55, 0x35, 0x50, 0x39, 0x56, + 0x39, 0x66, 0x63, 0x46, 0x37, 0x45, 0x77, 0x61, 0x6c, 0x44, 0x63, 0x70, 0x7a, 0x2f, 0x4b, 0x51, + 0x75, 0x30, 0x49, 0x5a, 0x74, 0x65, 0x68, 0x33, 0x63, 0x61, 0x2b, 0x79, 0x71, 0x48, 0x6f, 0x62, + 0x70, 0x65, 0x70, 0x2f, 0x4e, 0x74, 0x75, 0x4c, 0x78, 0x2f, 0x59, 0x74, 0x43, 0x75, 0x33, 0x73, + 0x64, 0x57, 0x73, 0x33, 0x47, 0x6c, 0x46, 0x4b, 0x49, 0x50, 0x30, 0x49, 0x66, 0x51, 0x6e, 0x50, + 0x39, 0x43, 0x53, 0x79, 0x6b, 0x78, 0x56, 0x36, 0x48, 0x72, 0x79, 0x77, 0x4b, 0x65, 0x32, 0x36, + 0x2f, 0x73, 0x37, 0x75, 0x73, 0x54, 0x78, 0x33, 0x33, 0x43, 0x70, 0x76, 0x5a, 0x70, 0x38, 0x67, + 0x62, 0x68, 0x53, 0x45, 0x4e, 0x4f, 0x33, 0x58, 0x6f, 0x59, 0x63, 0x62, 0x52, 0x33, 0x4e, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x73, 0x38, 0x67, 0x57, 0x64, 0x79, 0x64, 0x45, 0x37, 0x71, 0x4c, 0x57, 0x36, 0x7a, 0x59, 0x4a, + 0x41, 0x38, 0x6d, 0x73, 0x35, 0x31, 0x68, 0x52, 0x34, 0x76, 0x6f, 0x6a, 0x51, 0x6a, 0x4f, 0x50, + 0x54, 0x53, 0x4d, 0x42, 0x4f, 0x32, 0x39, 0x39, 0x79, 0x53, 0x6e, 0x79, 0x6c, 0x73, 0x6d, 0x6c, + 0x30, 0x65, 0x69, 0x76, 0x4b, 0x47, 0x6c, 0x66, 0x6f, 0x5a, 0x2b, 0x43, 0x50, 0x68, 0x47, 0x31, + 0x59, 0x4a, 0x55, 0x65, 0x43, 0x4e, 0x47, 0x34, 0x72, 0x57, 0x45, 0x36, 0x59, 0x65, 0x66, 0x73, + 0x48, 0x72, 0x6a, 0x5a, 0x30, 0x42, 0x58, 0x46, 0x4e, 0x77, 0x37, 0x6b, 0x52, 0x6a, 0x71, 0x64, + 0x67, 0x2b, 0x61, 0x59, 0x6b, 0x6e, 0x42, 0x32, 0x78, 0x6d, 0x51, 0x57, 0x33, 0x76, 0x44, 0x65, + 0x6b, 0x4a, 0x53, 0x65, 0x4b, 0x62, 0x62, 0x2b, 0x68, 0x67, 0x4e, 0x4d, 0x64, 0x4a, 0x61, 0x53, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x66, 0x4c, 0x39, 0x48, 0x50, 0x78, 0x76, 0x70, 0x72, 0x69, 0x77, 0x44, 0x61, 0x43, 0x6e, 0x70, + 0x78, 0x68, 0x4c, 0x4f, 0x7a, 0x71, 0x63, 0x64, 0x7a, 0x71, 0x67, 0x6b, 0x50, 0x56, 0x54, 0x68, + 0x58, 0x64, 0x66, 0x4c, 0x43, 0x49, 0x74, 0x56, 0x51, 0x51, 0x48, 0x77, 0x6e, 0x64, 0x6c, 0x6f, + 0x75, 0x56, 0x2b, 0x59, 0x46, 0x71, 0x72, 0x51, 0x69, 0x46, 0x6e, 0x74, 0x4d, 0x36, 0x66, 0x37, + 0x54, 0x31, 0x78, 0x4c, 0x68, 0x34, 0x52, 0x33, 0x57, 0x2b, 0x4b, 0x58, 0x51, 0x48, 0x4e, 0x78, + 0x76, 0x62, 0x63, 0x75, 0x68, 0x54, 0x64, 0x33, 0x55, 0x36, 0x30, 0x70, 0x66, 0x53, 0x51, 0x75, + 0x39, 0x43, 0x6c, 0x69, 0x35, 0x41, 0x54, 0x76, 0x66, 0x35, 0x2f, 0x42, 0x58, 0x38, 0x4f, 0x37, + 0x33, 0x72, 0x44, 0x41, 0x36, 0x32, 0x41, 0x36, 0x57, 0x6c, 0x4a, 0x4e, 0x38, 0x31, 0x6a, 0x34, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x45, 0x76, 0x32, 0x59, 0x39, 0x55, 0x77, 0x78, 0x69, 0x54, 0x74, 0x6e, 0x54, 0x42, 0x62, 0x37, + 0x73, 0x44, 0x67, 0x35, 0x74, 0x2f, 0x31, 0x73, 0x70, 0x6e, 0x51, 0x45, 0x4c, 0x2f, 0x46, 0x77, + 0x61, 0x64, 0x48, 0x36, 0x79, 0x77, 0x4e, 0x63, 0x6e, 0x41, 0x32, 0x35, 0x51, 0x35, 0x75, 0x45, + 0x72, 0x73, 0x63, 0x30, 0x5a, 0x44, 0x4c, 0x42, 0x57, 0x41, 0x35, 0x36, 0x34, 0x50, 0x78, 0x62, + 0x77, 0x6c, 0x64, 0x69, 0x73, 0x6e, 0x58, 0x76, 0x45, 0x6e, 0x34, 0x76, 0x44, 0x50, 0x30, 0x52, + 0x33, 0x4a, 0x51, 0x64, 0x4c, 0x45, 0x35, 0x4f, 0x63, 0x53, 0x5a, 0x4a, 0x4d, 0x6d, 0x59, 0x65, + 0x39, 0x43, 0x31, 0x33, 0x42, 0x66, 0x2f, 0x75, 0x59, 0x33, 0x51, 0x6b, 0x45, 0x46, 0x71, 0x71, + 0x74, 0x6b, 0x64, 0x46, 0x72, 0x34, 0x71, 0x41, 0x77, 0x72, 0x43, 0x42, 0x6c, 0x57, 0x6a, 0x53, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7a, 0x59, 0x74, 0x51, 0x63, 0x2b, 0x69, 0x6b, 0x59, 0x73, 0x53, 0x2f, 0x6b, 0x4c, 0x44, 0x75, + 0x78, 0x6e, 0x37, 0x2f, 0x48, 0x6a, 0x44, 0x4d, 0x77, 0x78, 0x64, 0x4d, 0x59, 0x55, 0x4e, 0x79, + 0x77, 0x52, 0x4a, 0x61, 0x49, 0x39, 0x45, 0x6b, 0x30, 0x2f, 0x53, 0x2b, 0x54, 0x30, 0x34, 0x73, + 0x64, 0x42, 0x4c, 0x5a, 0x36, 0x33, 0x64, 0x2b, 0x63, 0x31, 0x75, 0x38, 0x67, 0x34, 0x2b, 0x36, + 0x5a, 0x54, 0x30, 0x6e, 0x6b, 0x62, 0x70, 0x59, 0x65, 0x51, 0x78, 0x37, 0x7a, 0x74, 0x41, 0x6a, + 0x58, 0x48, 0x4e, 0x67, 0x48, 0x52, 0x46, 0x6a, 0x4a, 0x53, 0x35, 0x50, 0x39, 0x49, 0x65, 0x74, + 0x55, 0x6c, 0x64, 0x7a, 0x5a, 0x72, 0x6b, 0x4a, 0x6a, 0x6a, 0x39, 0x51, 0x48, 0x68, 0x6d, 0x75, + 0x51, 0x57, 0x4d, 0x4d, 0x58, 0x50, 0x2b, 0x66, 0x34, 0x61, 0x69, 0x4d, 0x37, 0x4d, 0x6a, 0x39, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x35, 0x4a, 0x33, 0x67, 0x38, 0x31, 0x63, 0x49, 0x55, 0x73, 0x6a, 0x64, 0x57, 0x59, 0x64, 0x74, + 0x43, 0x43, 0x42, 0x64, 0x6f, 0x37, 0x59, 0x5a, 0x4f, 0x63, 0x54, 0x65, 0x49, 0x36, 0x32, 0x54, + 0x50, 0x6f, 0x4d, 0x79, 0x4c, 0x56, 0x36, 0x59, 0x69, 0x51, 0x4e, 0x4f, 0x6f, 0x32, 0x41, 0x41, + 0x55, 0x49, 0x55, 0x54, 0x75, 0x7a, 0x34, 0x4a, 0x68, 0x52, 0x4d, 0x64, 0x77, 0x37, 0x31, 0x72, + 0x46, 0x34, 0x7a, 0x33, 0x58, 0x65, 0x51, 0x46, 0x54, 0x6a, 0x63, 0x6a, 0x79, 0x33, 0x34, 0x45, + 0x34, 0x31, 0x57, 0x6e, 0x4c, 0x6e, 0x34, 0x6d, 0x36, 0x68, 0x31, 0x41, 0x63, 0x49, 0x76, 0x55, + 0x78, 0x53, 0x4d, 0x58, 0x56, 0x50, 0x67, 0x75, 0x35, 0x67, 0x53, 0x65, 0x54, 0x68, 0x70, 0x37, + 0x31, 0x47, 0x2f, 0x31, 0x4f, 0x45, 0x49, 0x78, 0x33, 0x4c, 0x71, 0x63, 0x59, 0x49, 0x4d, 0x74, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x50, 0x6c, 0x30, 0x77, 0x68, 0x4b, 0x63, 0x62, 0x59, 0x2b, 0x75, 0x70, 0x77, 0x47, 0x30, 0x65, + 0x64, 0x6f, 0x78, 0x6c, 0x2f, 0x62, 0x42, 0x79, 0x47, 0x4d, 0x50, 0x6a, 0x51, 0x43, 0x33, 0x58, + 0x33, 0x6d, 0x6c, 0x62, 0x75, 0x62, 0x43, 0x5a, 0x75, 0x54, 0x4d, 0x37, 0x57, 0x50, 0x31, 0x35, + 0x34, 0x43, 0x43, 0x59, 0x67, 0x4e, 0x78, 0x78, 0x5a, 0x67, 0x5a, 0x53, 0x57, 0x36, 0x6a, 0x6a, + 0x5a, 0x48, 0x63, 0x36, 0x39, 0x2b, 0x6b, 0x2b, 0x47, 0x38, 0x58, 0x6a, 0x57, 0x4c, 0x51, 0x7a, + 0x47, 0x65, 0x34, 0x6b, 0x62, 0x5a, 0x35, 0x36, 0x2b, 0x62, 0x6d, 0x57, 0x75, 0x73, 0x6e, 0x68, + 0x34, 0x69, 0x4b, 0x63, 0x53, 0x50, 0x79, 0x31, 0x76, 0x6b, 0x37, 0x4e, 0x57, 0x48, 0x36, 0x5a, + 0x30, 0x67, 0x75, 0x69, 0x53, 0x42, 0x33, 0x59, 0x76, 0x2b, 0x77, 0x48, 0x77, 0x46, 0x34, 0x41, + 0x59, 0x63, 0x6f, 0x50, 0x59, 0x4e, 0x31, 0x79, 0x66, 0x75, 0x76, 0x4a, 0x4d, 0x72, 0x72, 0x6b, + 0x74, 0x67, 0x6f, 0x6a, 0x70, 0x54, 0x56, 0x2b, 0x68, 0x78, 0x74, 0x74, 0x6f, 0x41, 0x5a, 0x66, + 0x76, 0x59, 0x73, 0x6a, 0x75, 0x4d, 0x47, 0x37, 0x73, 0x48, 0x76, 0x63, 0x2f, 0x2b, 0x55, 0x68, + 0x68, 0x4b, 0x51, 0x52, 0x39, 0x75, 0x62, 0x6e, 0x4a, 0x48, 0x53, 0x63, 0x57, 0x6e, 0x73, 0x34, + 0x32, 0x50, 0x2f, 0x30, 0x61, 0x48, 0x48, 0x6e, 0x36, 0x36, 0x37, 0x4b, 0x79, 0x76, 0x4e, 0x31, + 0x6e, 0x6f, 0x4c, 0x73, 0x4e, 0x53, 0x7a, 0x35, 0x79, 0x47, 0x47, 0x4f, 0x6e, 0x49, 0x58, 0x74, + 0x6b, 0x68, 0x33, 0x31, 0x55, 0x38, 0x65, 0x69, 0x4a, 0x75, 0x5a, 0x73, 0x4d, 0x46, 0x42, 0x47, + 0x48, 0x79, 0x5a, 0x44, 0x45, 0x44, 0x68, 0x6b, 0x6d, 0x6d, 0x77, 0x76, 0x66, 0x35, 0x52, 0x42, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + + +// Corresponding usersig for the example v0 memory map v0 +// First 32 bytes used in construction of mempass +// In map v1, the next bytes are used for byte flags; should be 0xFF in map v0. +const uint8_t usersig_factory_v0[] = { + 0x20, 0xc1, 0xc7, 0x8c, 0x39, 0x4c, 0x1b, 0x92, 0x9e, 0x35, 0x1d, 0x55, 0xaa, 0xde, 0xe1, 0xe6, + 0xdc, 0x8d, 0x46, 0x54, 0xc2, 0x48, 0x93, 0x37, 0xed, 0x5f, 0xce, 0x7e, 0x9e, 0xca, 0x35, 0x2c, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + + +// eeprom zone 0xA containing example v1 memory map values matching the example v0 memory map zone +const uint8_t eeprom_factory_zoneA_v1[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xca, 0x4a, 0xe2, 0x18, 0x03, 0x65, 0x1c, 0x67, 0xb1, 0xb6, 0xc0, 0xa0, 0x2b, 0x8d, 0xb7, 0xf6, + 0x2f, 0x6b, 0xdb, 0xd5, 0x93, 0x05, 0x66, 0xd1, 0xeb, 0x63, 0xe8, 0x80, 0xf3, 0x86, 0xc9, 0x03, + 0x35, 0xfb, 0x3c, 0x54, 0xb7, 0x16, 0xbe, 0xbd, 0xbf, 0x5b, 0x70, 0x12, 0xbe, 0xde, 0xfe, 0xbe, + 0xe8, 0x70, 0x5b, 0x2d, 0x59, 0x92, 0x95, 0x2a, 0xf2, 0xc4, 0xcd, 0x67, 0x5f, 0x97, 0x07, 0xc9, + 0x07, 0x85, 0x06, 0x14, 0xa8, 0x19, 0x32, 0x49, 0x9f, 0xe6, 0xac, 0x9c, 0x0f, 0x31, 0x7a, 0xd2, + 0x26, 0xe3, 0x2a, 0x3c, 0xec, 0x77, 0x13, 0x6a, 0x39, 0x3f, 0x36, 0x45, 0xa4, 0x05, 0xa3, 0xe3, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + + +static void memory_mapping_clear_memory(void) +{ + uint8_t usersig[FLASH_USERSIG_SIZE]; + ataes_eeprom_simulation_clear(); + flash_wrapper_erase_usersig(); + flash_wrapper_read_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + u_assert_mem_eq(usersig, FF_ARRAY, FLASH_USERSIG_SIZE); + u_assert_mem_eq(ataes_eeprom_simulation_report(), FF_ARRAY, ATAES_EEPROM_LEN); +} + + +static void memory_mapping_install_v0(void) +{ + memory_write_memory_map_version(MEM_DEFAULT_memory_map_version); + ataes_eeprom_simulation_write(eeprom_factory_v0, 0, ATAES_EEPROM_LEN); + flash_wrapper_erase_usersig(); + flash_wrapper_write_usersig((const uint32_t *)usersig_factory_v0, + FLASH_USERSIG_SIZE / sizeof(uint32_t)); +} + + +static void memory_mapping_format_v0(void) +{ + // Check that eeprom is not erased and matches example v0 memory + u_assert_mem_eq(ataes_eeprom_simulation_report(), eeprom_factory_v0, ATAES_EEPROM_LEN); + // Check byte flags in zone 0 (should be different for v1 and v0) + u_assert_mem_eq(ataes_eeprom_simulation_report(), eeprom_factory_v0, + ATAES_EEPROM_ZONE_LEN); + u_assert_mem_not_eq(ataes_eeprom_simulation_report(), eeprom_factory_zone0_v1, + ATAES_EEPROM_ZONE_LEN); + // Check device name in zone 1 + u_assert_mem_eq(ataes_eeprom_simulation_report() + ATAES_EEPROM_ZONE_LEN * 1, + eeprom_factory_v0 + ATAES_EEPROM_ZONE_LEN * 1, ATAES_EEPROM_ZONE_LEN); + // Check secret keys in zone 2 and later. For map v0: + // 8 keys stored in first half of zone + // 1 key stored in second half of zone + int i, c, d; + for (i = 2, c = 0, d = 0; i < ATAES_EEPROM_ZONE_NUM; i++) { + if (!MEMEQ(ataes_eeprom_simulation_report() + ATAES_EEPROM_ZONE_LEN * i, FF_ARRAY, + ATAES_EEPROM_ZONE_LEN / 2)) { + c++; + } + if (!MEMEQ(ataes_eeprom_simulation_report() + ATAES_EEPROM_ZONE_LEN * i + + ATAES_EEPROM_ZONE_LEN / 2, FF_ARRAY, ATAES_EEPROM_ZONE_LEN / 2)) { + d++; + } + } + u_assert_int_eq(c, 8); + u_assert_int_eq(d, 1); + // Check that byte flags are not in flash + uint8_t usersig[FLASH_USERSIG_SIZE]; + flash_wrapper_read_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + u_assert_mem_eq(usersig, usersig_factory_v0, FLASH_USERSIG_SIZE); + u_assert_mem_eq(usersig + FLASH_USERSIG_FLAG_START, FF_ARRAY, FLASH_USERSIG_FLAG_LEN); +} + + +static void memory_mapping_format_v1(void) +{ + // Check that eeprom is not erased + u_assert_mem_not_eq(ataes_eeprom_simulation_report(), FF_ARRAY, ATAES_EEPROM_LEN); + // Check byte flags in zone 0 + u_assert_mem_eq(ataes_eeprom_simulation_report(), eeprom_factory_zone0_v1, + ATAES_EEPROM_ZONE_LEN); + // Check device name in zone 1 changed + u_assert_mem_eq(ataes_eeprom_simulation_report() + ATAES_EEPROM_ZONE_LEN * 1, FF_ARRAY, + ATAES_EEPROM_ZONE_LEN / 2); + u_assert_mem_not_eq(ataes_eeprom_simulation_report() + ATAES_EEPROM_ZONE_LEN * 1, + eeprom_factory_v0 + ATAES_EEPROM_ZONE_LEN * 1, ATAES_EEPROM_ZONE_LEN); + u_assert_mem_not_eq(ataes_eeprom_simulation_report() + ATAES_EEPROM_ZONE_LEN * 1 + + ATAES_EEPROM_ZONE_LEN / 2, FF_ARRAY, ATAES_EEPROM_ZONE_LEN / 2); + // Check secret keys in zone 2 and later. For map v1: + // 0 keys stored in first half of a zone + // 9 keys stored in second half of a zone + int i, c; + for (i = 2, c = 0; i < ATAES_EEPROM_ZONE_NUM; i++) { + u_assert_mem_eq(ataes_eeprom_simulation_report() + ATAES_EEPROM_ZONE_LEN * i, FF_ARRAY, + ATAES_EEPROM_ZONE_LEN / 2); + if (!MEMEQ(ataes_eeprom_simulation_report() + ATAES_EEPROM_ZONE_LEN * i + + ATAES_EEPROM_ZONE_LEN / 2, FF_ARRAY, ATAES_EEPROM_ZONE_LEN / 2)) { + c++; + } + } + u_assert_int_eq(c, 9); + // Check that byte flags were copied to flash + uint8_t usersig[FLASH_USERSIG_SIZE]; + flash_wrapper_read_usersig((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t)); + u_assert_mem_not_eq(usersig, FF_ARRAY, FLASH_USERSIG_SIZE); + u_assert_mem_eq(ataes_eeprom_simulation_report(), usersig + FLASH_USERSIG_FLAG_START, + 0x10); + u_assert_mem_eq(ataes_eeprom_simulation_report() + 0x14, + usersig + FLASH_USERSIG_FLAG_START + 0x14, + 0x0C);// Skip MEM_U2F_COUNT which is not updatied in flash due to write endurance limits +} + + +static void test_memory_mapping_update(void) +{ + // Normal setup should give memory map v1 layout + memory_mapping_clear_memory();// 'Reset' device + memory_setup(); // First call to memory_setup() does one-time factory install that intializes eeprom. + memory_mapping_format_v1(); // Check eeprom matches memory map v1 layout + memory_setup(); // Second call to memory_setup() reads eeprom + memory_mapping_format_v1(); // The memory should be the same + + // Test updating from v0 to v1 memory map layout + memory_mapping_clear_memory();// 'Reset' device + memory_mapping_install_v0(); // 'Factory install' v0 memory map example + memory_mapping_format_v0(); // Check eeprom matches memory map v0 example + memory_setup(); // Call memory_setup() should remap to memory map v1 + memory_mapping_format_v1(); // Check eeprom matches memory map v1 layout + + // Test edge cases during upgrade: + uint8_t eeprom[ATAES_EEPROM_LEN]; + memory_mapping_clear_memory();// 'Reset' device + memory_mapping_install_v0(); // 'Factory install' v0 memory map example + memory_mapping_format_v0(); // Check eeprom matches memory map v0 example + // Set a v1 area with non-0xFF data + memcpy(eeprom, eeprom_factory_v0, ATAES_EEPROM_LEN); + eeprom[ATAES_EEPROM_ZONE_LEN * 2 + ATAES_EEPROM_ZONE_LEN / 2] = 0; + // Set a v1 area to have valid data not matching data in v0 (i.e. can be decrypted); should never occur + memcpy(eeprom + ATAES_EEPROM_ZONE_LEN * 4 + ATAES_EEPROM_ZONE_LEN / 2, + eeprom_factory_zoneA_v1 + ATAES_EEPROM_ZONE_LEN / 2, ATAES_EEPROM_ZONE_LEN / 2); + // Set a v1 area to have valid data matching data in v0; could occur if the device was unplugged early + memcpy(eeprom + ATAES_EEPROM_ZONE_LEN * 0xA + ATAES_EEPROM_ZONE_LEN / 2, + eeprom_factory_zoneA_v1 + ATAES_EEPROM_ZONE_LEN / 2, ATAES_EEPROM_ZONE_LEN / 2); + // Set a v0 area to have invalid data; could occur if upgrading from an early firmware version + memcpy(eeprom + ATAES_EEPROM_ZONE_LEN * 5, + eeprom_factory_zoneA_v1 + ATAES_EEPROM_ZONE_LEN / 2, ATAES_EEPROM_ZONE_LEN / 2); + // Write new eeprom data + ataes_eeprom_simulation_write(eeprom, 0, ATAES_EEPROM_LEN); + memory_setup(); // Call memory_setup() should remap to memory map v1 + memory_mapping_format_v1(); // Check eeprom matches memory map v1 layout +} + + int main(void) { ecc_context_init(); @@ -1136,6 +1712,7 @@ int main(void) u_run_test(test_buffer_overflow); u_run_test(test_utils); u_run_test(test_aes_encrypt_decrypt_hmac); + u_run_test(test_memory_mapping_update); // unit tests for secp256k1 rfc6979 are in tests_secp256k1.c u_run_test(test_rfc6979);