From 462b7c2f69a300b8b7bd857ca67011bf85ff85ea Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Thu, 22 Dec 2022 14:30:35 +0800 Subject: [PATCH] Add SM3 RNG --- include/gmssl/sm3_rng.h | 42 ++++++++ src/sm3_rng.c | 215 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 include/gmssl/sm3_rng.h create mode 100644 src/sm3_rng.c diff --git a/include/gmssl/sm3_rng.h b/include/gmssl/sm3_rng.h new file mode 100644 index 00000000..418ddf3f --- /dev/null +++ b/include/gmssl/sm3_rng.h @@ -0,0 +1,42 @@ +/* + * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +#ifndef GMSSL_SM3_RNG_H +#define GMSSL_SM3_RNG_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SM3_RNG_MAX_RESEED_COUNTER (1<<20) +#define SM3_RNG_MAX_RESEED_SECONDS 600 + + +typedef struct { + uint8_t V[55]; + uint8_t C[55]; + uint32_t reseed_counter; + time_t last_reseed_time; +} SM3_RNG; + +int sm3_rng_init(SM3_RNG *rng, const uint8_t *nonce, size_t nonce_len, + const uint8_t *label, size_t label_len); +int sm3_rng_reseed(SM3_RNG *rng, const uint8_t *addin, size_t addin_len); +int sm3_rng_generate(SM3_RNG *rng, const uint8_t *addin, size_t addin_len, + uint8_t *out, size_t outlen); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/sm3_rng.c b/src/sm3_rng.c new file mode 100644 index 00000000..599a91c8 --- /dev/null +++ b/src/sm3_rng.c @@ -0,0 +1,215 @@ +/* + * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +// see GM/T 0105-2021 Design Guide for Software-based Random Number Generators + +#include +#include +#include +#include +#include +#include +#include +#include + + +static const uint8_t num[4] = { 0, 1, 2, 3 }; + +typedef struct { + SM3_CTX sm3_ctx[2]; +} SM3_DF_CTX; + +// sm3_df(in) := ( sm3(be32(1) || be32(440) || in) || +// sm3(b332(2) || be32(440) || in) )[0:55] +static void sm3_df_init(SM3_DF_CTX *df_ctx) +{ + uint8_t counter[4] = {0, 0, 0, 1}; + uint8_t seedlen[4] = {0, 0, 440/256, 440%256}; + + sm3_init(&df_ctx->sm3_ctx[0]); + sm3_update(&df_ctx->sm3_ctx[0], counter, 4); + sm3_update(&df_ctx->sm3_ctx[0], seedlen, 4); + counter[3] = 2; + sm3_init(&df_ctx->sm3_ctx[1]); + sm3_update(&df_ctx->sm3_ctx[1], counter, 4); + sm3_update(&df_ctx->sm3_ctx[1], seedlen, 4); +} + +static void sm3_df_update(SM3_DF_CTX *df_ctx, const uint8_t *data, size_t datalen) +{ + if (data && datalen) { + sm3_update(&df_ctx->sm3_ctx[0], data, datalen); + sm3_update(&df_ctx->sm3_ctx[1], data, datalen); + } +} + +static void sm3_df_finish(SM3_DF_CTX *df_ctx, uint8_t out[55]) +{ + uint8_t buf[32]; + sm3_finish(&df_ctx->sm3_ctx[0], out); + sm3_finish(&df_ctx->sm3_ctx[1], buf); + memcpy(out + 32, buf, 55 - 32); +} + +int sm3_rng_init(SM3_RNG *rng, const uint8_t *nonce, size_t nonce_len, + const uint8_t *label, size_t label_len) +{ + SM3_DF_CTX df_ctx; + uint8_t entropy[512]; + + // get_entropy, 512-byte might be too long for some system RNGs + if (rand_bytes(entropy, 256) != 1 + || rand_bytes(entropy + 256, 256) != 1) { + error_print(); + return -1; + } + + // V = sm3_df(entropy || nonce || label) + sm3_df_init(&df_ctx); + sm3_df_update(&df_ctx, entropy, sizeof(entropy)); + sm3_df_update(&df_ctx, nonce, nonce_len); + sm3_df_update(&df_ctx, label, label_len); + sm3_df_finish(&df_ctx, rng->V); + + // C = sm3_df(0x00 || V) + sm3_df_init(&df_ctx); + sm3_df_update(&df_ctx, &num[0], 1); + sm3_df_update(&df_ctx, rng->V, 55); + sm3_df_finish(&df_ctx, rng->C); + + // reseed_counter = 1, last_ressed_time = now() + rng->reseed_counter = 1; + rng->last_reseed_time = time(NULL); + + gmssl_secure_clear(&df_ctx, sizeof(df_ctx)); + gmssl_secure_clear(entropy, sizeof(entropy)); + return 1; +} + +int sm3_rng_reseed(SM3_RNG *rng, const uint8_t *addin, size_t addin_len) +{ + SM3_DF_CTX df_ctx; + uint8_t entropy[512]; + + // get_entropy, 512-byte might be too long for some system RNGs + if (rand_bytes(entropy, 256) != 1 + || rand_bytes(entropy + 256, 256) != 1) { + error_print(); + return -1; + } + + // V = sm3_df(0x01 || entropy || V || appin) + sm3_df_init(&df_ctx); + sm3_df_update(&df_ctx, &num[1], 1); + sm3_df_update(&df_ctx, entropy, sizeof(entropy)); + sm3_df_update(&df_ctx, rng->V, 55); + sm3_df_update(&df_ctx, addin, addin_len); + sm3_df_finish(&df_ctx, rng->V); + + // C = sm3_df(0x00 || V) + sm3_df_init(&df_ctx); + sm3_df_update(&df_ctx, &num[0], 1); + sm3_df_update(&df_ctx, rng->V, 55); + sm3_df_finish(&df_ctx, rng->C); + + // reseed_counter = 1, last_ressed_time = now() + rng->reseed_counter = 1; + rng->last_reseed_time = time(NULL); + + gmssl_secure_clear(&df_ctx, sizeof(df_ctx)); + gmssl_secure_clear(entropy, sizeof(entropy)); + return 1; +} + +static void be_add(uint8_t r[55], const uint8_t *a, size_t alen) +{ + int i, j, carry = 0; + + for (i = 54, j = (int)(alen - 1); j >= 0; i--, j--) { + carry += r[i] + a[j]; + r[i] = carry & 0xff; + carry >>= 8; + } + for (; i >= 0; i--) { + carry += r[i]; + r[i] = carry & 0xff; + carry >>= 8; + } +} + +int sm3_rng_generate(SM3_RNG *rng, const uint8_t *addin, size_t addin_len, + uint8_t *out, size_t outlen) +{ + SM3_CTX sm3_ctx; + uint8_t H[32]; + uint8_t counter[4]; + + if (!outlen || outlen > 32) { + error_print(); + return -1; + } + + if (rng->reseed_counter > SM3_RNG_MAX_RESEED_COUNTER + || time(NULL) - rng->last_reseed_time > SM3_RNG_MAX_RESEED_SECONDS) { + if (sm3_rng_reseed(rng, addin, addin_len) != 1) { + error_print(); + return -1; + } + if (addin) { + addin = NULL; + } + } + + if (addin && addin_len) { + uint8_t W[32]; + + // W = sm3(0x02 || V || addin) + sm3_init(&sm3_ctx); + sm3_update(&sm3_ctx, &num[2], 1); + sm3_update(&sm3_ctx, rng->V, 55); + sm3_update(&sm3_ctx, addin, addin_len); + sm3_finish(&sm3_ctx, W); + + // V = (V + W) mod 2^440 + be_add(rng->V, W, 32); + + gmssl_secure_clear(W, sizeof(W)); + } + + // output sm3(V) + sm3_init(&sm3_ctx); + sm3_update(&sm3_ctx, rng->V, 55); + if (outlen < 32) { + uint8_t buf[32]; + sm3_finish(&sm3_ctx, buf); + memcpy(out, buf, outlen); + } else { + sm3_finish(&sm3_ctx, out); + } + + // H = sm3(0x03 || V) + sm3_init(&sm3_ctx); + sm3_update(&sm3_ctx, &num[3], 1); + sm3_update(&sm3_ctx, rng->V, 55); + sm3_finish(&sm3_ctx, H); + + // V = (V + H + C + reseed_counter) mod 2^440 + be_add(rng->V, H, 32); + be_add(rng->V, rng->C, 55); + counter[0] = (rng->reseed_counter >> 24) & 0xff; + counter[1] = (rng->reseed_counter >> 16) & 0xff; + counter[2] = (rng->reseed_counter >> 8) & 0xff; + counter[3] = (rng->reseed_counter ) & 0xff; + be_add(rng->V, counter, 4); + + (rng->reseed_counter)++; + + gmssl_secure_clear(&sm3_ctx, sizeof(sm3_ctx)); + gmssl_secure_clear(H, sizeof(H)); + return 1; +}