From 7c44340c40fd147fe62ae589a62491a54200f0a8 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 6 Jun 2019 18:48:39 +0200 Subject: [PATCH 01/11] crypto: Add HMAC deterministic random bit generator and unit tests. --- crypto/Makefile | 1 + crypto/hmac_drbg.c | 126 ++++++++++++++++++++++++++++++++++++++ crypto/hmac_drbg.h | 41 +++++++++++++ crypto/tests/test_check.c | 33 ++++++++++ 4 files changed, 201 insertions(+) create mode 100644 crypto/hmac_drbg.c create mode 100644 crypto/hmac_drbg.h diff --git a/crypto/Makefile b/crypto/Makefile index cb3ebe80f3..f51de750ef 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -64,6 +64,7 @@ SRCS += nem.c SRCS += segwit_addr.c cash_addr.c SRCS += memzero.c SRCS += shamir.c +SRCS += hmac_drbg.c OBJS = $(SRCS:.c=.o) diff --git a/crypto/hmac_drbg.c b/crypto/hmac_drbg.c new file mode 100644 index 0000000000..fe53dc7ff7 --- /dev/null +++ b/crypto/hmac_drbg.c @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2019 Andrew R. Kozlik + * + * 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 "hmac_drbg.h" +#include "memzero.h" +#include "sha2.h" + +static void update_k(HMAC_DRBG_CTX *ctx, uint8_t domain, const uint8_t *data, + size_t len) { + // Computes K = HMAC(K, V || domain || data). + + // First hash operation of HMAC. + uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; + if (data == NULL) { + ctx->v[8] = 0x00800000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; + sha256_Transform(ctx->idig, ctx->v, h); + ctx->v[8] = 0x80000000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + } else { + SHA256_CTX sha_ctx; + memcpy(sha_ctx.state, ctx->idig, SHA256_DIGEST_LENGTH); + for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) { +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(ctx->v[i], sha_ctx.buffer[i]); +#else + sha_ctx.buffer[i] = ctx->v[i]; +#endif + } + ((uint8_t *)sha_ctx.buffer)[SHA256_DIGEST_LENGTH] = domain; + sha_ctx.bitcount = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; + sha256_Update(&sha_ctx, data, len); + sha256_Final(&sha_ctx, (uint8_t *)h); +#if BYTE_ORDER == LITTLE_ENDIAN + for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) + REVERSE32(h[i], h[i]); +#endif + } + + // Second hash operation of HMAC. + h[8] = 0x80000000; + h[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + sha256_Transform(ctx->odig, h, h); + + // Precompute the inner digest and outer digest of K. + h[8] = 0; + h[15] = 0; + for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { + h[i] ^= 0x36363636; + } + sha256_Transform(sha256_initial_hash_value, h, ctx->idig); + + for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { + h[i] = h[i] ^ 0x36363636 ^ 0x5c5c5c5c; + } + sha256_Transform(sha256_initial_hash_value, h, ctx->odig); + memzero(h, sizeof(h)); +} + +static void update_v(HMAC_DRBG_CTX *ctx) { + sha256_Transform(ctx->idig, ctx->v, ctx->v); + sha256_Transform(ctx->odig, ctx->v, ctx->v); +} + +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len) { + uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; + + // Precompute the inner digest and outer digest of K = 0x00 ... 0x00. + memset(h, 0x36, sizeof(h)); + sha256_Transform(sha256_initial_hash_value, h, ctx->idig); + memset(h, 0x5c, sizeof(h)); + sha256_Transform(sha256_initial_hash_value, h, ctx->odig); + + // Let V = 0x01 ... 0x01. + memset(ctx->v, 1, SHA256_DIGEST_LENGTH); + for (size_t i = 9; i < 15; i++) ctx->v[i] = 0; + ctx->v[8] = 0x80000000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + + hmac_drbg_reseed(ctx, entropy, len); + + memzero(h, sizeof(h)); +} + +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len) { + update_k(ctx, 0, entropy, len); + update_v(ctx); + if (len == 0) return; + update_k(ctx, 1, entropy, len); + update_v(ctx); +} + +void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len) { + size_t i = 0; + while (i < len) { + update_v(ctx); + for (size_t j = 0; j < 8; j++) { + uint32_t r = ctx->v[j]; + for (int k = 24; k >= 0; k -= 8) { + buf[i++] = (r >> k) & 0xFF; + } + } + } + update_k(ctx, 0, NULL, 0); + update_v(ctx); +} diff --git a/crypto/hmac_drbg.h b/crypto/hmac_drbg.h new file mode 100644 index 0000000000..0bba189015 --- /dev/null +++ b/crypto/hmac_drbg.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2019 Andrew R. Kozlik + * + * 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 __HMAC_DRBG_H__ +#define __HMAC_DRBG_H__ + +#include +#include + +// HMAC based Deterministic Random Bit Generator with SHA-256 + +typedef struct _HMAC_DRBG_CTX { + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t v[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; +} HMAC_DRBG_CTX; + +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len); +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len); +void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len); + +#endif diff --git a/crypto/tests/test_check.c b/crypto/tests/test_check.c index 9a007bed67..85f106cc8f 100644 --- a/crypto/tests/test_check.c +++ b/crypto/tests/test_check.c @@ -53,6 +53,7 @@ #include "ed25519-donna/ed25519-donna.h" #include "ed25519-donna/ed25519-keccak.h" #include "ed25519-donna/ed25519.h" +#include "hmac_drbg.h" #include "memzero.h" #include "monero/monero.h" #include "nem.h" @@ -4624,6 +4625,34 @@ START_TEST(test_pbkdf2_hmac_sha512) { } END_TEST +START_TEST(test_hmac_drbg) { + char entropy[] = + "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d0e66f71e" + "dc43e42a45ad3c6fc6cdc4df"; + char reseed[] = + "01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552"; + char expected[] = + "76fc79fe9b50beccc991a11b5635783a83536add03c157fb30645e611c2898bb2b1bc215" + "000209208cd506cb28da2a51bdb03826aaf2bd2335d576d519160842e7158ad0949d1a9e" + "c3e66ea1b1a064b005de914eac2e9d4f2d72a8616a80225422918250ff66a41bd2f864a6" + "a38cc5b6499dc43f7f2bd09e1e0f8f5885935124"; + uint8_t result[128]; + + HMAC_DRBG_CTX ctx; + hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2); + hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2); + hmac_drbg_generate(&ctx, result, sizeof(result)); + hmac_drbg_generate(&ctx, result, sizeof(result)); + ck_assert_mem_eq(result, fromhex(expected), sizeof(result)); + + hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2); + hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2); + hmac_drbg_generate(&ctx, result, sizeof(result) - 13); + hmac_drbg_generate(&ctx, result, sizeof(result) - 17); + ck_assert_mem_eq(result, fromhex(expected), sizeof(result) - 17); +} +END_TEST + START_TEST(test_mnemonic) { static const char *vectors[] = { "00000000000000000000000000000000", @@ -8628,6 +8657,10 @@ Suite *test_suite(void) { tcase_add_test(tc, test_pbkdf2_hmac_sha512); suite_add_tcase(s, tc); + tc = tcase_create("hmac_drbg"); + tcase_add_test(tc, test_hmac_drbg); + suite_add_tcase(s, tc); + tc = tcase_create("bip39"); tcase_add_test(tc, test_mnemonic); tcase_add_test(tc, test_mnemonic_check); From b915092a444a5004ffd6f27cd9a67743059d9f33 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Fri, 7 Jun 2019 12:14:10 +0200 Subject: [PATCH 02/11] crypto/hmac_drbg: Add nonce parameter to hmac_drbg_init(). --- crypto/hmac_drbg.c | 23 ++++++++++++----------- crypto/hmac_drbg.h | 4 ++-- crypto/tests/test_check.c | 14 ++++++++------ 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/crypto/hmac_drbg.c b/crypto/hmac_drbg.c index fe53dc7ff7..c8772ead2e 100644 --- a/crypto/hmac_drbg.c +++ b/crypto/hmac_drbg.c @@ -25,13 +25,13 @@ #include "memzero.h" #include "sha2.h" -static void update_k(HMAC_DRBG_CTX *ctx, uint8_t domain, const uint8_t *data, - size_t len) { - // Computes K = HMAC(K, V || domain || data). +static void update_k(HMAC_DRBG_CTX *ctx, uint8_t domain, const uint8_t *data1, + size_t len1, const uint8_t *data2, size_t len2) { + // Computes K = HMAC(K, V || domain || data1 || data 2). // First hash operation of HMAC. uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; - if (data == NULL) { + if (len1 + len2 == 0) { ctx->v[8] = 0x00800000; ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; sha256_Transform(ctx->idig, ctx->v, h); @@ -49,7 +49,8 @@ static void update_k(HMAC_DRBG_CTX *ctx, uint8_t domain, const uint8_t *data, } ((uint8_t *)sha_ctx.buffer)[SHA256_DIGEST_LENGTH] = domain; sha_ctx.bitcount = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; - sha256_Update(&sha_ctx, data, len); + sha256_Update(&sha_ctx, data1, len1); + sha256_Update(&sha_ctx, data2, len2); sha256_Final(&sha_ctx, (uint8_t *)h); #if BYTE_ORDER == LITTLE_ENDIAN for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) @@ -82,7 +83,7 @@ static void update_v(HMAC_DRBG_CTX *ctx) { sha256_Transform(ctx->odig, ctx->v, ctx->v); } -void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len) { +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t entropy_len, const uint8_t *nonce, size_t nonce_len) { uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; // Precompute the inner digest and outer digest of K = 0x00 ... 0x00. @@ -97,16 +98,16 @@ void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len) { ctx->v[8] = 0x80000000; ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; - hmac_drbg_reseed(ctx, entropy, len); + hmac_drbg_reseed(ctx, entropy, entropy_len, nonce, nonce_len); memzero(h, sizeof(h)); } -void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len) { - update_k(ctx, 0, entropy, len); +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len, const uint8_t *addin, size_t addin_len) { + update_k(ctx, 0, entropy, len, addin, addin_len); update_v(ctx); if (len == 0) return; - update_k(ctx, 1, entropy, len); + update_k(ctx, 1, entropy, len, addin, addin_len); update_v(ctx); } @@ -121,6 +122,6 @@ void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len) { } } } - update_k(ctx, 0, NULL, 0); + update_k(ctx, 0, NULL, 0, NULL, 0); update_v(ctx); } diff --git a/crypto/hmac_drbg.h b/crypto/hmac_drbg.h index 0bba189015..32d3d6fdc4 100644 --- a/crypto/hmac_drbg.h +++ b/crypto/hmac_drbg.h @@ -34,8 +34,8 @@ typedef struct _HMAC_DRBG_CTX { uint32_t v[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; } HMAC_DRBG_CTX; -void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len); -void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len); +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, const uint8_t *nonce, size_t nonce_len); +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, const uint8_t *addin, size_t addin_len); void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len); #endif diff --git a/crypto/tests/test_check.c b/crypto/tests/test_check.c index 85f106cc8f..2080520b79 100644 --- a/crypto/tests/test_check.c +++ b/crypto/tests/test_check.c @@ -4627,8 +4627,8 @@ END_TEST START_TEST(test_hmac_drbg) { char entropy[] = - "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d0e66f71e" - "dc43e42a45ad3c6fc6cdc4df"; + "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d"; + char nonce[] = "0e66f71edc43e42a45ad3c6fc6cdc4df"; char reseed[] = "01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552"; char expected[] = @@ -4638,15 +4638,17 @@ START_TEST(test_hmac_drbg) { "a38cc5b6499dc43f7f2bd09e1e0f8f5885935124"; uint8_t result[128]; + uint8_t nonce_bytes[16]; + memcpy(nonce_bytes, fromhex(nonce), sizeof(nonce_bytes)); HMAC_DRBG_CTX ctx; - hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2); - hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2); + hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, strlen(nonce) / 2); + hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); hmac_drbg_generate(&ctx, result, sizeof(result)); hmac_drbg_generate(&ctx, result, sizeof(result)); ck_assert_mem_eq(result, fromhex(expected), sizeof(result)); - hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2); - hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2); + hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, strlen(nonce) / 2); + hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); hmac_drbg_generate(&ctx, result, sizeof(result) - 13); hmac_drbg_generate(&ctx, result, sizeof(result) - 17); ck_assert_mem_eq(result, fromhex(expected), sizeof(result) - 17); From 1d9e125fd4925cec96094fb75dd4e23a0752441a Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Fri, 7 Jun 2019 12:16:24 +0200 Subject: [PATCH 03/11] crypto/rfc6979: Use the new HMAC DRBG implementation in rfc6979.c. Remove code duplication between rfc6979.c and ecdsa.c. --- core/SConscript.firmware | 2 ++ core/SConscript.unix | 2 ++ crypto/Makefile | 1 + crypto/ecdsa.c | 49 ---------------------------------------- crypto/gui/gui.pro | 2 ++ crypto/rfc6979.c | 37 +++--------------------------- crypto/rfc6979.h | 5 ++-- 7 files changed, 12 insertions(+), 86 deletions(-) diff --git a/core/SConscript.firmware b/core/SConscript.firmware index d404796543..d36585a890 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -76,12 +76,14 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/groestl.c', 'vendor/trezor-crypto/hasher.c', 'vendor/trezor-crypto/hmac.c', + 'vendor/trezor-crypto/hmac_drbg.c', 'vendor/trezor-crypto/memzero.c', 'vendor/trezor-crypto/nem.c', 'vendor/trezor-crypto/nist256p1.c', 'vendor/trezor-crypto/pbkdf2.c', 'vendor/trezor-crypto/rand.c', 'vendor/trezor-crypto/ripemd160.c', + 'vendor/trezor-crypto/rfc6979.c', 'vendor/trezor-crypto/secp256k1.c', 'vendor/trezor-crypto/sha2.c', 'vendor/trezor-crypto/sha3.c', diff --git a/core/SConscript.unix b/core/SConscript.unix index c62387a356..624682f644 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -74,12 +74,14 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/groestl.c', 'vendor/trezor-crypto/hasher.c', 'vendor/trezor-crypto/hmac.c', + 'vendor/trezor-crypto/hmac_drbg.c', 'vendor/trezor-crypto/memzero.c', 'vendor/trezor-crypto/nem.c', 'vendor/trezor-crypto/nist256p1.c', 'vendor/trezor-crypto/pbkdf2.c', 'vendor/trezor-crypto/rand.c', 'vendor/trezor-crypto/ripemd160.c', + 'vendor/trezor-crypto/rfc6979.c', 'vendor/trezor-crypto/secp256k1.c', 'vendor/trezor-crypto/sha2.c', 'vendor/trezor-crypto/sha3.c', diff --git a/crypto/Makefile b/crypto/Makefile index f51de750ef..7b018482d2 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -65,6 +65,7 @@ SRCS += segwit_addr.c cash_addr.c SRCS += memzero.c SRCS += shamir.c SRCS += hmac_drbg.c +SRCS += rfc6979.c OBJS = $(SRCS:.c=.o) diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c index 124a79e742..2cd02fa3e3 100644 --- a/crypto/ecdsa.c +++ b/crypto/ecdsa.c @@ -654,55 +654,6 @@ int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, return 0; } -void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, - rfc6979_state *state) { - uint8_t bx[2 * 32]; - uint8_t buf[32 + 1 + 2 * 32]; - - memcpy(bx, priv_key, 32); - memcpy(bx + 32, hash, 32); - - memset(state->v, 1, sizeof(state->v)); - memset(state->k, 0, sizeof(state->k)); - - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x00; - memcpy(buf + sizeof(state->v) + 1, bx, 64); - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x01; - memcpy(buf + sizeof(state->v) + 1, bx, 64); - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - - memzero(bx, sizeof(bx)); - memzero(buf, sizeof(buf)); -} - -// generate next number from deterministic random number generator -void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) { - uint8_t buf[32 + 1]; - - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x00; - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(rnd, buf, 32); - memzero(buf, sizeof(buf)); -} - -// generate K in a deterministic way, according to RFC6979 -// http://tools.ietf.org/html/rfc6979 -void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) { - uint8_t buf[32]; - generate_rfc6979(buf, state); - bn_read_be(buf, k); - memzero(buf, sizeof(buf)); -} - // msg is a data to be signed // msg_len is the message length int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, diff --git a/crypto/gui/gui.pro b/crypto/gui/gui.pro index 0197efe1e4..e4623bc4fa 100644 --- a/crypto/gui/gui.pro +++ b/crypto/gui/gui.pro @@ -13,6 +13,8 @@ SOURCES += ../hmac.c SOURCES += ../rand.c SOURCES += ../bignum.c SOURCES += ../ecdsa.c +SOURCES += ../rfc6979.c +SOURCES += ../hmac_drbg.c SOURCES += ../ripemd160.c SOURCES += ../base58.c SOURCES += ../secp256k1.c diff --git a/crypto/rfc6979.c b/crypto/rfc6979.c index 8f5f1c9131..5fe13d47d7 100644 --- a/crypto/rfc6979.c +++ b/crypto/rfc6979.c @@ -23,48 +23,17 @@ */ #include "rfc6979.h" -#include -#include "hmac.h" +#include "hmac_drbg.h" #include "memzero.h" void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) { - uint8_t bx[2 * 32]; - uint8_t buf[32 + 1 + 2 * 32]; - - memcpy(bx, priv_key, 32); - memcpy(bx + 32, hash, 32); - - memset(state->v, 1, sizeof(state->v)); - memset(state->k, 0, sizeof(state->k)); - - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x00; - memcpy(buf + sizeof(state->v) + 1, bx, 64); - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x01; - memcpy(buf + sizeof(state->v) + 1, bx, 64); - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - - memzero(bx, sizeof(bx)); - memzero(buf, sizeof(buf)); + hmac_drbg_init(state, priv_key, 32, hash, 32); } // generate next number from deterministic random number generator void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) { - uint8_t buf[32 + 1]; - - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x00; - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(rnd, buf, 32); - memzero(buf, sizeof(buf)); + hmac_drbg_generate(state, rnd, 32); } // generate K in a deterministic way, according to RFC6979 diff --git a/crypto/rfc6979.h b/crypto/rfc6979.h index 30ef0f17ac..3e40953509 100644 --- a/crypto/rfc6979.h +++ b/crypto/rfc6979.h @@ -27,11 +27,10 @@ #include #include "bignum.h" +#include "hmac_drbg.h" // rfc6979 pseudo random number generator state -typedef struct { - uint8_t v[32], k[32]; -} rfc6979_state; +typedef HMAC_DRBG_CTX rfc6979_state; void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng); From f677a0f0db308e6e028ab62c9fbd9dd137263798 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Fri, 7 Jun 2019 20:16:40 +0200 Subject: [PATCH 04/11] core: Use PRNG when generating random delays. --- core/SConscript.bootloader | 2 ++ core/SConscript.prodtest | 3 +++ core/embed/bootloader/main.c | 1 + core/embed/firmware/main.c | 3 +++ core/embed/prodtest/main.c | 1 + core/embed/trezorhal/common.c | 26 ++++++++++++++++++++++++-- core/embed/trezorhal/common.h | 6 ++++++ 7 files changed, 40 insertions(+), 2 deletions(-) diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index ec0ba8462c..c38168919a 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -26,7 +26,9 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c', 'vendor/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c', 'vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.c', + 'vendor/trezor-crypto/hmac_drbg.c', 'vendor/trezor-crypto/memzero.c', + 'vendor/trezor-crypto/rand.c', 'vendor/trezor-crypto/sha2.c', ] diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index d1be76d112..77075f8934 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -12,7 +12,10 @@ CPPPATH_MOD += [ 'vendor/trezor-crypto', ] SOURCE_MOD += [ + 'vendor/trezor-crypto/hmac_drbg.c', 'vendor/trezor-crypto/memzero.c', + 'vendor/trezor-crypto/rand.c', + 'vendor/trezor-crypto/sha2.c', ] # modtrezorui diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index f1d225ea5a..f80ed50315 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -234,6 +234,7 @@ static void check_bootloader_version(void) { #endif int main(void) { + drbg_init(); touch_init(); touch_power_on(); diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index eb026b95db..8f62e4cc81 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -43,6 +43,9 @@ #include "touch.h" int main(void) { + // initialize pseudo-random number generator + drbg_init(); + // reinitialize HAL for Trezor One #if TREZOR_MODEL == 1 HAL_Init(); diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index a59b5e2d08..3d4affe61f 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -371,6 +371,7 @@ static secbool startswith(const char *s, const char *prefix) { int main(void) { display_orientation(0); + drbg_init(); sdcard_init(); touch_init(); sbu_init(); diff --git a/core/embed/trezorhal/common.c b/core/embed/trezorhal/common.c index 0fba1d0f5b..512c9272f9 100644 --- a/core/embed/trezorhal/common.c +++ b/core/embed/trezorhal/common.c @@ -25,13 +25,15 @@ #include "display.h" #include "flash.h" #include "rand.h" -#include "rng.h" +#include "hmac_drbg.h" #include "stm32f4xx_ll_utils.h" // from util.s extern void shutdown(void); +static HMAC_DRBG_CTX drbg_ctx; + #define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00) void __attribute__((noreturn)) @@ -121,7 +123,7 @@ void __assert_func(const char *file, int line, const char *func, void hal_delay(uint32_t ms) { HAL_Delay(ms); } void delay_random(void) { - int wait = rng_get() & 0xff; + int wait = drbg_random32() & 0xff; volatile int i = 0; volatile int j = wait; while (i < wait) { @@ -185,3 +187,23 @@ void collect_hw_entropy(void) { FLASH_OTP_BLOCK_SIZE), NULL); } + +void drbg_init() { + uint8_t entropy[48]; + random_buffer(entropy, sizeof(entropy)); + hmac_drbg_init(&drbg_ctx, entropy, sizeof(entropy), NULL, 0); +} + +void drbg_reseed(const uint8_t *entropy, size_t len) { + hmac_drbg_reseed(&drbg_ctx, entropy, len, NULL, 0); +} + +void drbg_generate(uint8_t *buf, size_t len) { + hmac_drbg_generate(&drbg_ctx, buf, len); +} + +uint32_t drbg_random32(void) { + uint32_t value; + drbg_generate((uint8_t *)&value, sizeof(value)); + return value; +} diff --git a/core/embed/trezorhal/common.h b/core/embed/trezorhal/common.h index 2954580bdb..229d1678ae 100644 --- a/core/embed/trezorhal/common.h +++ b/core/embed/trezorhal/common.h @@ -20,6 +20,7 @@ #ifndef __TREZORHAL_COMMON_H__ #define __TREZORHAL_COMMON_H__ +#include #include #include "secbool.h" @@ -75,6 +76,11 @@ void collect_hw_entropy(void); #define HW_ENTROPY_LEN (12 + 32) extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; +void drbg_init(); +void drbg_reseed(const uint8_t *entropy, size_t len); +void drbg_generate(uint8_t *buf, size_t len); +uint32_t drbg_random32(void); + // the following functions are defined in util.s void memset_reg(volatile void *start, volatile void *stop, uint32_t val); From d95756ccf3b8429b9b416ee811631e6a25a2888c Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sat, 8 Jun 2019 13:39:41 +0200 Subject: [PATCH 05/11] crypto/hmac_drbg: Fix style. --- crypto/hmac_drbg.c | 9 ++++++--- crypto/hmac_drbg.h | 6 ++++-- crypto/tests/test_check.c | 6 ++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/crypto/hmac_drbg.c b/crypto/hmac_drbg.c index c8772ead2e..fa4569f49b 100644 --- a/crypto/hmac_drbg.c +++ b/crypto/hmac_drbg.c @@ -20,8 +20,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "hmac_drbg.h" +#include #include "memzero.h" #include "sha2.h" @@ -83,7 +83,9 @@ static void update_v(HMAC_DRBG_CTX *ctx) { sha256_Transform(ctx->odig, ctx->v, ctx->v); } -void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t entropy_len, const uint8_t *nonce, size_t nonce_len) { +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_len, const uint8_t *nonce, + size_t nonce_len) { uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; // Precompute the inner digest and outer digest of K = 0x00 ... 0x00. @@ -103,7 +105,8 @@ void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t entropy_l memzero(h, sizeof(h)); } -void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len, const uint8_t *addin, size_t addin_len) { +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len, + const uint8_t *addin, size_t addin_len) { update_k(ctx, 0, entropy, len, addin, addin_len); update_v(ctx); if (len == 0) return; diff --git a/crypto/hmac_drbg.h b/crypto/hmac_drbg.h index 32d3d6fdc4..4b969dedb0 100644 --- a/crypto/hmac_drbg.h +++ b/crypto/hmac_drbg.h @@ -34,8 +34,10 @@ typedef struct _HMAC_DRBG_CTX { uint32_t v[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; } HMAC_DRBG_CTX; -void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, const uint8_t *nonce, size_t nonce_len); -void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, const uint8_t *addin, size_t addin_len); +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, + const uint8_t *nonce, size_t nonce_len); +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, + const uint8_t *addin, size_t addin_len); void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len); #endif diff --git a/crypto/tests/test_check.c b/crypto/tests/test_check.c index 2080520b79..ff42562398 100644 --- a/crypto/tests/test_check.c +++ b/crypto/tests/test_check.c @@ -4641,13 +4641,15 @@ START_TEST(test_hmac_drbg) { uint8_t nonce_bytes[16]; memcpy(nonce_bytes, fromhex(nonce), sizeof(nonce_bytes)); HMAC_DRBG_CTX ctx; - hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, strlen(nonce) / 2); + hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, + strlen(nonce) / 2); hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); hmac_drbg_generate(&ctx, result, sizeof(result)); hmac_drbg_generate(&ctx, result, sizeof(result)); ck_assert_mem_eq(result, fromhex(expected), sizeof(result)); - hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, strlen(nonce) / 2); + hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, + strlen(nonce) / 2); hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); hmac_drbg_generate(&ctx, result, sizeof(result) - 13); hmac_drbg_generate(&ctx, result, sizeof(result) - 17); From 531c610a1701303d1b8b3ec71b09153784dc38b7 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sat, 8 Jun 2019 13:51:28 +0200 Subject: [PATCH 06/11] storage: Use wait_random() from common.h. Fix build for tests. --- storage/storage.c | 24 ------------------------ storage/tests/c/Makefile | 40 ++++++++++++++++++++++++++-------------- storage/tests/c/common.c | 2 ++ storage/tests/c/common.h | 2 ++ 4 files changed, 30 insertions(+), 38 deletions(-) diff --git a/storage/storage.c b/storage/storage.c index fa6e90ca38..14d4114c50 100644 --- a/storage/storage.c +++ b/storage/storage.c @@ -330,30 +330,6 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len) { return sectrue; } -/* - * Generates a delay of random length. Use this to protect sensitive code - * against fault injection. - */ -static void wait_random(void) { -#ifndef TREZOR_STORAGE_TEST - int wait = random32() & 0xff; - volatile int i = 0; - volatile int j = wait; - while (i < wait) { - if (i + j != wait) { - handle_fault("sanity check"); - } - ++i; - --j; - } - - // Double-check loop completion. - if (i != wait) { - handle_fault("loop completion check"); - } -#endif -} - static void derive_kek(uint32_t pin, const uint8_t *random_salt, uint8_t kek[SHA256_DIGEST_LENGTH], uint8_t keiv[SHA256_DIGEST_LENGTH]) { diff --git a/storage/tests/c/Makefile b/storage/tests/c/Makefile index a1fc96c2e3..610c2d1e9e 100644 --- a/storage/tests/c/Makefile +++ b/storage/tests/c/Makefile @@ -1,24 +1,36 @@ CC = gcc -CFLAGS = -Wall -Wshadow -Wextra -Wpedantic -Werror -fPIC -DTREZOR_STORAGE_TEST +CFLAGS = -Wall -Wshadow -Wextra -Wpedantic -Werror -fPIC LIBS = -INC = -I ../../../crypto -I ../../../storage -I . -OBJ = flash.o common.o -OBJ += ../../../storage/storage.o ../../../storage/norcow.o -OBJ += ../../../crypto/pbkdf2.o -OBJ += ../../../crypto/rand.o -OBJ += ../../../crypto/chacha20poly1305/rfc7539.o -OBJ += ../../../crypto/chacha20poly1305/chacha20poly1305.o -OBJ += ../../../crypto/chacha20poly1305/poly1305-donna.o -OBJ += ../../../crypto/chacha20poly1305/chacha_merged.o -OBJ += ../../../crypto/hmac.o -OBJ += ../../../crypto/sha2.o -OBJ += ../../../crypto/memzero.o +INC = -I ../../../crypto -I ../.. -I . +BASE = ../../../ + +SRC = storage/tests/c/flash.c +SRC += storage/tests/c/common.c +SRC += storage/storage.c +SRC += storage/norcow.c +SRC += crypto/pbkdf2.c +SRC += crypto/rand.c +SRC += crypto/chacha20poly1305/rfc7539.c +SRC += crypto/chacha20poly1305/chacha20poly1305.c +SRC += crypto/chacha20poly1305/poly1305-donna.c +SRC += crypto/chacha20poly1305/chacha_merged.c +SRC += crypto/hmac.c +SRC += crypto/sha2.c +SRC += crypto/memzero.c + +OBJ = $(SRC:%.c=build/%.o) + OUT = libtrezor-storage.so $(OUT): $(OBJ) $(CC) $(CFLAGS) $(LIBS) $(OBJ) -shared -o $(OUT) -%.o: %.c %.h +build/crypto/chacha20poly1305/chacha_merged.o: $(BASE)crypto/chacha20poly1305/chacha_merged.c + mkdir -p $(@D) + $(CC) $(CFLAGS) $(INC) -c $< -o $@ + +build/%.o: $(BASE)%.c $(BASE)%.h + mkdir -p $(@D) $(CC) $(CFLAGS) $(INC) -c $< -o $@ clean: diff --git a/storage/tests/c/common.c b/storage/tests/c/common.c index b3f9b7ffce..b53e1c34d4 100644 --- a/storage/tests/c/common.c +++ b/storage/tests/c/common.c @@ -23,6 +23,8 @@ #include "common.h" +void wait_random(void) {} + void __shutdown(void) { printf("SHUTDOWN\n"); exit(3); diff --git a/storage/tests/c/common.h b/storage/tests/c/common.h index eaa0773790..cfab1fcf85 100644 --- a/storage/tests/c/common.h +++ b/storage/tests/c/common.h @@ -22,6 +22,8 @@ #include "secbool.h" +void wait_random(void); + void __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); void error_shutdown(const char *line1, const char *line2, const char *line3, From c2bdd1cf32f5ae85052918e057d79a22df0cc5e2 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sat, 8 Jun 2019 13:53:17 +0200 Subject: [PATCH 07/11] core/common: Change delay_random() to wait_random(). --- core/embed/trezorhal/common.c | 10 +++++++--- core/embed/trezorhal/common.h | 4 ++-- core/embed/trezorhal/usb.c | 8 ++++---- core/embed/unix/common.c | 2 ++ core/embed/unix/common.h | 1 + 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/core/embed/trezorhal/common.c b/core/embed/trezorhal/common.c index 512c9272f9..98848e8d21 100644 --- a/core/embed/trezorhal/common.c +++ b/core/embed/trezorhal/common.c @@ -24,8 +24,8 @@ #include "common.h" #include "display.h" #include "flash.h" -#include "rand.h" #include "hmac_drbg.h" +#include "rand.h" #include "stm32f4xx_ll_utils.h" @@ -122,7 +122,11 @@ void __assert_func(const char *file, int line, const char *func, void hal_delay(uint32_t ms) { HAL_Delay(ms); } -void delay_random(void) { +/* + * Generates a delay of random length. Use this to protect sensitive code + * against fault injection. + */ +void wait_random(void) { int wait = drbg_random32() & 0xff; volatile int i = 0; volatile int j = wait; @@ -188,7 +192,7 @@ void collect_hw_entropy(void) { NULL); } -void drbg_init() { +void drbg_init(void) { uint8_t entropy[48]; random_buffer(entropy, sizeof(entropy)); hmac_drbg_init(&drbg_ctx, entropy, sizeof(entropy), NULL, 0); diff --git a/core/embed/trezorhal/common.h b/core/embed/trezorhal/common.h index 229d1678ae..56485480a6 100644 --- a/core/embed/trezorhal/common.h +++ b/core/embed/trezorhal/common.h @@ -66,7 +66,7 @@ error_shutdown(const char *line1, const char *line2, const char *line3, void hal_delay(uint32_t ms); -void delay_random(void); +void wait_random(void); void clear_otg_hs_memory(void); @@ -76,7 +76,7 @@ void collect_hw_entropy(void); #define HW_ENTROPY_LEN (12 + 32) extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; -void drbg_init(); +void drbg_init(void); void drbg_reseed(const uint8_t *entropy, size_t len); void drbg_generate(uint8_t *buf, size_t len); uint32_t drbg_random32(void); diff --git a/core/embed/trezorhal/usb.c b/core/embed/trezorhal/usb.c index 2b3466e6e7..b1b6a04891 100644 --- a/core/embed/trezorhal/usb.c +++ b/core/embed/trezorhal/usb.c @@ -343,7 +343,7 @@ static uint8_t usb_class_deinit(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { static uint8_t usb_class_setup(USBD_HandleTypeDef *dev, USBD_SetupReqTypedef *req) { - delay_random(); + wait_random(); if (((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_CLASS) && ((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) && ((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_VENDOR)) { @@ -472,7 +472,7 @@ static uint8_t usb_class_setup(USBD_HandleTypeDef *dev, } static uint8_t usb_class_data_in(USBD_HandleTypeDef *dev, uint8_t ep_num) { - delay_random(); + wait_random(); for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { switch (usb_ifaces[i].type) { case USB_IFACE_TYPE_HID: @@ -492,7 +492,7 @@ static uint8_t usb_class_data_in(USBD_HandleTypeDef *dev, uint8_t ep_num) { } static uint8_t usb_class_data_out(USBD_HandleTypeDef *dev, uint8_t ep_num) { - delay_random(); + wait_random(); for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { switch (usb_ifaces[i].type) { case USB_IFACE_TYPE_HID: @@ -512,7 +512,7 @@ static uint8_t usb_class_data_out(USBD_HandleTypeDef *dev, uint8_t ep_num) { } static uint8_t usb_class_sof(USBD_HandleTypeDef *dev) { - delay_random(); + wait_random(); for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { switch (usb_ifaces[i].type) { case USB_IFACE_TYPE_VCP: diff --git a/core/embed/unix/common.c b/core/embed/unix/common.c index a5898175d1..573b22ea09 100644 --- a/core/embed/unix/common.c +++ b/core/embed/unix/common.c @@ -109,6 +109,8 @@ error_shutdown(const char *line1, const char *line2, const char *line3, void hal_delay(uint32_t ms) { usleep(1000 * ms); } +void wait_random(void) {} + uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; void collect_hw_entropy(void) { memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); } diff --git a/core/embed/unix/common.h b/core/embed/unix/common.h index 4254940e2a..e9b7f0928a 100644 --- a/core/embed/unix/common.h +++ b/core/embed/unix/common.h @@ -56,6 +56,7 @@ error_shutdown(const char *line1, const char *line2, const char *line3, : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) void hal_delay(uint32_t ms); +void wait_random(void); void collect_hw_entropy(void); #define HW_ENTROPY_LEN (12 + 32) From 013929de0b8a28b94b429839e2b01053c45a14cc Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sun, 9 Jun 2019 21:03:14 +0200 Subject: [PATCH 08/11] crypto/hmac_drbg: Fix buffer overflow. --- crypto/hmac_drbg.c | 4 ++-- crypto/tests/test_check.c | 17 +++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/crypto/hmac_drbg.c b/crypto/hmac_drbg.c index fa4569f49b..639fed8417 100644 --- a/crypto/hmac_drbg.c +++ b/crypto/hmac_drbg.c @@ -118,9 +118,9 @@ void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len) { size_t i = 0; while (i < len) { update_v(ctx); - for (size_t j = 0; j < 8; j++) { + for (size_t j = 0; j < 8 && i < len; j++) { uint32_t r = ctx->v[j]; - for (int k = 24; k >= 0; k -= 8) { + for (int k = 24; k >= 0 && i < len; k -= 8) { buf[i++] = (r >> k) & 0xFF; } } diff --git a/crypto/tests/test_check.c b/crypto/tests/test_check.c index ff42562398..310640ced8 100644 --- a/crypto/tests/test_check.c +++ b/crypto/tests/test_check.c @@ -4637,6 +4637,7 @@ START_TEST(test_hmac_drbg) { "c3e66ea1b1a064b005de914eac2e9d4f2d72a8616a80225422918250ff66a41bd2f864a6" "a38cc5b6499dc43f7f2bd09e1e0f8f5885935124"; uint8_t result[128]; + uint8_t null_bytes[128] = {0}; uint8_t nonce_bytes[16]; memcpy(nonce_bytes, fromhex(nonce), sizeof(nonce_bytes)); @@ -4648,12 +4649,16 @@ START_TEST(test_hmac_drbg) { hmac_drbg_generate(&ctx, result, sizeof(result)); ck_assert_mem_eq(result, fromhex(expected), sizeof(result)); - hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, - strlen(nonce) / 2); - hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); - hmac_drbg_generate(&ctx, result, sizeof(result) - 13); - hmac_drbg_generate(&ctx, result, sizeof(result) - 17); - ck_assert_mem_eq(result, fromhex(expected), sizeof(result) - 17); + for (size_t i = 0; i <= sizeof(result); ++i) { + hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, + strlen(nonce) / 2); + hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); + hmac_drbg_generate(&ctx, result, sizeof(result) - 13); + memset(result, 0, sizeof(result)); + hmac_drbg_generate(&ctx, result, i); + ck_assert_mem_eq(result, fromhex(expected), i); + ck_assert_mem_eq(result + i, null_bytes, sizeof(result) - i); + } } END_TEST From ad5d9168c820ae4352ca19197af956ec16ba5f85 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sun, 9 Jun 2019 23:32:19 +0200 Subject: [PATCH 09/11] legacy: Move wait_random() to common.c and use HMAC DRBG to generate delays. --- legacy/common.c | 40 ++++++++++++++++++++++++++++++++++++++++ legacy/common.h | 8 ++++++++ legacy/demo/Makefile | 2 ++ legacy/firmware/Makefile | 2 ++ legacy/firmware/trezor.c | 3 +++ legacy/firmware/usb.c | 1 + legacy/usb21_standard.c | 1 + legacy/usb_standard.c | 1 + legacy/util.c | 18 ------------------ legacy/util.h | 2 -- legacy/webusb.c | 1 + legacy/winusb.c | 1 + 12 files changed, 60 insertions(+), 20 deletions(-) diff --git a/legacy/common.c b/legacy/common.c index 0bd282ead3..ad745f3577 100644 --- a/legacy/common.c +++ b/legacy/common.c @@ -21,6 +21,7 @@ #include #include "bitmaps.h" #include "firmware/usb.h" +#include "hmac_drbg.h" #include "layout.h" #include "oled.h" #include "rng.h" @@ -28,6 +29,8 @@ uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; +static HMAC_DRBG_CTX drbg_ctx; + void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { @@ -81,3 +84,40 @@ void __assert_func(const char *file, int line, const char *func, #endif void hal_delay(uint32_t ms) { usbSleep(ms); } + +void wait_random(void) { + int wait = drbg_random32() & 0xff; + volatile int i = 0; + volatile int j = wait; + while (i < wait) { + if (i + j != wait) { + shutdown(); + } + ++i; + --j; + } + // Double-check loop completion. + if (i != wait || j != 0) { + shutdown(); + } +} + +void drbg_init() { + uint8_t entropy[48]; + random_buffer(entropy, sizeof(entropy)); + hmac_drbg_init(&drbg_ctx, entropy, sizeof(entropy), NULL, 0); +} + +void drbg_reseed(const uint8_t *entropy, size_t len) { + hmac_drbg_reseed(&drbg_ctx, entropy, len, NULL, 0); +} + +void drbg_generate(uint8_t *buf, size_t len) { + hmac_drbg_generate(&drbg_ctx, buf, len); +} + +uint32_t drbg_random32(void) { + uint32_t value; + drbg_generate((uint8_t *)&value, sizeof(value)); + return value; +} diff --git a/legacy/common.h b/legacy/common.h index 1774bc7f02..08f82c96dc 100644 --- a/legacy/common.h +++ b/legacy/common.h @@ -20,6 +20,7 @@ #ifndef __TREZORHAL_COMMON_H__ #define __TREZORHAL_COMMON_H__ +#include #include #include "secbool.h" @@ -40,4 +41,11 @@ error_shutdown(const char *line1, const char *line2, const char *line3, void hal_delay(uint32_t ms); +void wait_random(void); + +void drbg_init(void); +void drbg_reseed(const uint8_t *entropy, size_t len); +void drbg_generate(uint8_t *buf, size_t len); +uint32_t drbg_random32(void); + #endif diff --git a/legacy/demo/Makefile b/legacy/demo/Makefile index 306597b7ea..7a58e1ff84 100644 --- a/legacy/demo/Makefile +++ b/legacy/demo/Makefile @@ -8,6 +8,8 @@ OBJS += ../vendor/trezor-crypto/bignum.o OBJS += ../vendor/trezor-crypto/bip32.o OBJS += ../vendor/trezor-crypto/ecdsa.o OBJS += ../vendor/trezor-crypto/hmac.o +OBJS += ../vendor/trezor-crypto/hmac_drbg.o +OBJS += ../vendor/trezor-crypto/rfc6979.o OBJS += ../vendor/trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/sha2.o diff --git a/legacy/firmware/Makefile b/legacy/firmware/Makefile index 85e759fea1..30e123fe7f 100644 --- a/legacy/firmware/Makefile +++ b/legacy/firmware/Makefile @@ -47,6 +47,8 @@ OBJS += ../vendor/trezor-crypto/ecdsa.o OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o +OBJS += ../vendor/trezor-crypto/hmac_drbg.o +OBJS += ../vendor/trezor-crypto/rfc6979.o OBJS += ../vendor/trezor-crypto/rand.o OBJS += ../vendor/trezor-crypto/memzero.o diff --git a/legacy/firmware/trezor.c b/legacy/firmware/trezor.c index 406cd95900..6d616cf4ff 100644 --- a/legacy/firmware/trezor.c +++ b/legacy/firmware/trezor.c @@ -128,6 +128,9 @@ int main(void) { __stack_chk_guard = random32(); // this supports compiler provided // unpredictable stack protection checks #endif + + drbg_init(); + if (!is_mode_unprivileged()) { collect_hw_entropy(true); timer_init(); diff --git a/legacy/firmware/usb.c b/legacy/firmware/usb.c index 45ecb9ac21..f70a86fcaf 100644 --- a/legacy/firmware/usb.c +++ b/legacy/firmware/usb.c @@ -20,6 +20,7 @@ #include #include +#include "common.h" #include "config.h" #include "debug.h" #include "messages.h" diff --git a/legacy/usb21_standard.c b/legacy/usb21_standard.c index f5ca3546d8..b3906d941a 100644 --- a/legacy/usb21_standard.c +++ b/legacy/usb21_standard.c @@ -19,6 +19,7 @@ #include "usb21_standard.h" #include #include +#include "common.h" #include "util.h" static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos, diff --git a/legacy/usb_standard.c b/legacy/usb_standard.c index 26f5925a24..a3bcf2b408 100644 --- a/legacy/usb_standard.c +++ b/legacy/usb_standard.c @@ -38,6 +38,7 @@ LGPL License Terms @ref lgpl_license #include #include +#include "common.h" #include "usb_private.h" #include "util.h" diff --git a/legacy/util.c b/legacy/util.c index 5a96381de2..95ec978d9d 100644 --- a/legacy/util.c +++ b/legacy/util.c @@ -18,29 +18,11 @@ */ #include "util.h" -#include "rng.h" inline void delay(uint32_t wait) { while (--wait > 0) __asm__("nop"); } -void wait_random(void) { - int wait = random32() & 0xff; - volatile int i = 0; - volatile int j = wait; - while (i < wait) { - if (i + j != wait) { - shutdown(); - } - ++i; - --j; - } - // Double-check loop completion. - if (i != wait || j != 0) { - shutdown(); - } -} - static const char *hexdigits = "0123456789ABCDEF"; void uint32hex(uint32_t num, char *str) { diff --git a/legacy/util.h b/legacy/util.h index 54c610430e..1841ff14ba 100644 --- a/legacy/util.h +++ b/legacy/util.h @@ -52,8 +52,6 @@ void delay(uint32_t wait); -void wait_random(void); - // converts uint32 to hexa (8 digits) void uint32hex(uint32_t num, char *str); diff --git a/legacy/webusb.c b/legacy/webusb.c index b4f2677e2d..eda931a780 100644 --- a/legacy/webusb.c +++ b/legacy/webusb.c @@ -18,6 +18,7 @@ #include +#include "common.h" #include "usb21_standard.h" #include "util.h" #include "webusb.h" diff --git a/legacy/winusb.c b/legacy/winusb.c index e18f9d0e07..9c30cf477f 100644 --- a/legacy/winusb.c +++ b/legacy/winusb.c @@ -18,6 +18,7 @@ #include "winusb.h" #include +#include "common.h" #include "util.h" static int usb_descriptor_type(uint16_t wValue) { return wValue >> 8; } From 6e884203c3ea5053c7f096114aff807fd2a5bb2b Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 10 Jun 2019 09:44:37 +0200 Subject: [PATCH 10/11] legacy: Add hmac_drbg to bootloader build. --- legacy/bootloader/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/legacy/bootloader/Makefile b/legacy/bootloader/Makefile index 72b251ae17..8c3df14994 100644 --- a/legacy/bootloader/Makefile +++ b/legacy/bootloader/Makefile @@ -9,6 +9,7 @@ OBJS += ../vendor/trezor-crypto/ecdsa.small.o OBJS += ../vendor/trezor-crypto/secp256k1.small.o OBJS += ../vendor/trezor-crypto/sha2.small.o OBJS += ../vendor/trezor-crypto/memzero.small.o +OBJS += ../vendor/trezor-crypto/hmac_drbg.small.o CFLAGS += -DUSE_PRECOMPUTED_IV=0 CFLAGS += -DUSE_PRECOMPUTED_CP=0 From e6ee13e7980608ae4bfeb5b3fa92bbb3515a2b1a Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 10 Jun 2019 12:59:35 +0200 Subject: [PATCH 11/11] legacy/common: Temporarily use TRNG to generate random delays. --- legacy/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/legacy/common.c b/legacy/common.c index ad745f3577..d88b6bab57 100644 --- a/legacy/common.c +++ b/legacy/common.c @@ -86,7 +86,7 @@ void __assert_func(const char *file, int line, const char *func, void hal_delay(uint32_t ms) { usbSleep(ms); } void wait_random(void) { - int wait = drbg_random32() & 0xff; + int wait = random32() & 0xff; volatile int i = 0; volatile int j = wait; while (i < wait) {