crypto: Add HMAC deterministic random bit generator and unit tests.

pull/239/head
Andrew Kozlik 5 years ago
parent 0e277dfcb0
commit 7c44340c40

@ -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)

@ -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 <string.h>
#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);
}

@ -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 <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);
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

@ -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);

Loading…
Cancel
Save