mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 07:28:10 +00:00
Merge pull request #239 from trezor/andrewkozlik/hmac_drbg
Add HMAC DRBG and use it to generate random delays
This commit is contained in:
commit
c1f5432904
@ -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',
|
||||
]
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -234,6 +234,7 @@ static void check_bootloader_version(void) {
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
drbg_init();
|
||||
touch_init();
|
||||
touch_power_on();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -24,14 +24,16 @@
|
||||
#include "common.h"
|
||||
#include "display.h"
|
||||
#include "flash.h"
|
||||
#include "hmac_drbg.h"
|
||||
#include "rand.h"
|
||||
#include "rng.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))
|
||||
@ -120,8 +122,12 @@ 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;
|
||||
/*
|
||||
* 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;
|
||||
while (i < wait) {
|
||||
@ -185,3 +191,23 @@ void collect_hw_entropy(void) {
|
||||
FLASH_OTP_BLOCK_SIZE),
|
||||
NULL);
|
||||
}
|
||||
|
||||
void drbg_init(void) {
|
||||
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;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#ifndef __TREZORHAL_COMMON_H__
|
||||
#define __TREZORHAL_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "secbool.h"
|
||||
|
||||
@ -65,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);
|
||||
|
||||
@ -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);
|
||||
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);
|
||||
|
@ -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:
|
||||
|
@ -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); }
|
||||
|
@ -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)
|
||||
|
@ -64,6 +64,8 @@ SRCS += nem.c
|
||||
SRCS += segwit_addr.c cash_addr.c
|
||||
SRCS += memzero.c
|
||||
SRCS += shamir.c
|
||||
SRCS += hmac_drbg.c
|
||||
SRCS += rfc6979.c
|
||||
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
130
crypto/hmac_drbg.c
Normal file
130
crypto/hmac_drbg.c
Normal file
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* 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 "hmac_drbg.h"
|
||||
#include <string.h>
|
||||
#include "memzero.h"
|
||||
#include "sha2.h"
|
||||
|
||||
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 (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);
|
||||
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, 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++)
|
||||
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 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.
|
||||
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, entropy_len, nonce, nonce_len);
|
||||
|
||||
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) {
|
||||
update_k(ctx, 0, entropy, len, addin, addin_len);
|
||||
update_v(ctx);
|
||||
if (len == 0) return;
|
||||
update_k(ctx, 1, entropy, len, addin, addin_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 && i < len; j++) {
|
||||
uint32_t r = ctx->v[j];
|
||||
for (int k = 24; k >= 0 && i < len; k -= 8) {
|
||||
buf[i++] = (r >> k) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
update_k(ctx, 0, NULL, 0, NULL, 0);
|
||||
update_v(ctx);
|
||||
}
|
43
crypto/hmac_drbg.h
Normal file
43
crypto/hmac_drbg.h
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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 <sha2.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// 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,
|
||||
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
|
@ -23,48 +23,17 @@
|
||||
*/
|
||||
|
||||
#include "rfc6979.h"
|
||||
#include <string.h>
|
||||
#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
|
||||
|
@ -27,11 +27,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#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);
|
||||
|
@ -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,43 @@ START_TEST(test_pbkdf2_hmac_sha512) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_hmac_drbg) {
|
||||
char entropy[] =
|
||||
"06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d";
|
||||
char nonce[] = "0e66f71edc43e42a45ad3c6fc6cdc4df";
|
||||
char reseed[] =
|
||||
"01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552";
|
||||
char expected[] =
|
||||
"76fc79fe9b50beccc991a11b5635783a83536add03c157fb30645e611c2898bb2b1bc215"
|
||||
"000209208cd506cb28da2a51bdb03826aaf2bd2335d576d519160842e7158ad0949d1a9e"
|
||||
"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));
|
||||
HMAC_DRBG_CTX ctx;
|
||||
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));
|
||||
|
||||
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
|
||||
|
||||
START_TEST(test_mnemonic) {
|
||||
static const char *vectors[] = {
|
||||
"00000000000000000000000000000000",
|
||||
@ -8628,6 +8666,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);
|
||||
|
@ -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
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#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 = 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;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#ifndef __TREZORHAL_COMMON_H__
|
||||
#define __TREZORHAL_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <libopencm3/usb/hid.h>
|
||||
#include <libopencm3/usb/usbd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "messages.h"
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "usb21_standard.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
|
||||
static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos,
|
||||
|
@ -38,6 +38,7 @@ LGPL License Terms @ref lgpl_license
|
||||
|
||||
#include <string.h>
|
||||
#include <libopencm3/usb/usbd.h>
|
||||
#include "common.h"
|
||||
#include "usb_private.h"
|
||||
#include "util.h"
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "usb21_standard.h"
|
||||
#include "util.h"
|
||||
#include "webusb.h"
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "winusb.h"
|
||||
#include <libopencm3/usb/usbd.h>
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
|
||||
static int usb_descriptor_type(uint16_t wValue) { return wValue >> 8; }
|
||||
|
@ -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]) {
|
||||
|
@ -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:
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void wait_random(void) {}
|
||||
|
||||
void __shutdown(void) {
|
||||
printf("SHUTDOWN\n");
|
||||
exit(3);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user