aboutsummaryrefslogtreecommitdiffstats
path: root/test/monniaux/BearSSL/src/rand
diff options
context:
space:
mode:
Diffstat (limited to 'test/monniaux/BearSSL/src/rand')
-rw-r--r--test/monniaux/BearSSL/src/rand/aesctr_drbg.c206
-rw-r--r--test/monniaux/BearSSL/src/rand/hmac_drbg.c157
-rw-r--r--test/monniaux/BearSSL/src/rand/sysrng.c170
3 files changed, 533 insertions, 0 deletions
diff --git a/test/monniaux/BearSSL/src/rand/aesctr_drbg.c b/test/monniaux/BearSSL/src/rand/aesctr_drbg.c
new file mode 100644
index 00000000..8dbd5010
--- /dev/null
+++ b/test/monniaux/BearSSL/src/rand/aesctr_drbg.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * 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 "inner.h"
+
+/* see bearssl_rand.h */
+void
+br_aesctr_drbg_init(br_aesctr_drbg_context *ctx,
+ const br_block_ctr_class *aesctr,
+ const void *seed, size_t len)
+{
+ unsigned char tmp[16];
+
+ ctx->vtable = &br_aesctr_drbg_vtable;
+ memset(tmp, 0, sizeof tmp);
+ aesctr->init(&ctx->sk.vtable, tmp, 16);
+ ctx->cc = 0;
+ br_aesctr_drbg_update(ctx, seed, len);
+}
+
+/* see bearssl_rand.h */
+void
+br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx, void *out, size_t len)
+{
+ unsigned char *buf;
+ unsigned char iv[12];
+
+ buf = out;
+ memset(iv, 0, sizeof iv);
+ while (len > 0) {
+ size_t clen;
+
+ /*
+ * We generate data by blocks of at most 65280 bytes. This
+ * allows for unambiguously testing the counter overflow
+ * condition; also, it should work on 16-bit architectures
+ * (where 'size_t' is 16 bits only).
+ */
+ clen = len;
+ if (clen > 65280) {
+ clen = 65280;
+ }
+
+ /*
+ * We make sure that the counter won't exceed the configured
+ * limit.
+ */
+ if ((uint32_t)(ctx->cc + ((clen + 15) >> 4)) > 32768) {
+ clen = (32768 - ctx->cc) << 4;
+ if (clen > len) {
+ clen = len;
+ }
+ }
+
+ /*
+ * Run CTR.
+ */
+ memset(buf, 0, clen);
+ ctx->cc = ctx->sk.vtable->run(&ctx->sk.vtable,
+ iv, ctx->cc, buf, clen);
+ buf += clen;
+ len -= clen;
+
+ /*
+ * Every 32768 blocks, we force a state update.
+ */
+ if (ctx->cc >= 32768) {
+ br_aesctr_drbg_update(ctx, NULL, 0);
+ }
+ }
+}
+
+/* see bearssl_rand.h */
+void
+br_aesctr_drbg_update(br_aesctr_drbg_context *ctx, const void *seed, size_t len)
+{
+ /*
+ * We use a Hirose construction on AES-256 to make a hash function.
+ * Function definition:
+ * - running state consists in two 16-byte blocks G and H
+ * - initial values of G and H are conventional
+ * - there is a fixed block-sized constant C
+ * - for next data block m:
+ * set AES key to H||m
+ * G' = E(G) xor G
+ * H' = E(G xor C) xor G xor C
+ * G <- G', H <- H'
+ * - once all blocks have been processed, output is H||G
+ *
+ * Constants:
+ * G_init = B6 B6 ... B6
+ * H_init = A5 A5 ... A5
+ * C = 01 00 ... 00
+ *
+ * With this hash function h(), we compute the new state as
+ * follows:
+ * - produce a state-dependent value s as encryption of an
+ * all-one block with AES and the current key
+ * - compute the new key as the first 128 bits of h(s||seed)
+ *
+ * Original Hirose article:
+ * https://www.iacr.org/archive/fse2006/40470213/40470213.pdf
+ */
+
+ unsigned char s[16], iv[12];
+ unsigned char G[16], H[16];
+ int first;
+
+ /*
+ * Use an all-one IV to get a fresh output block that depends on the
+ * current seed.
+ */
+ memset(iv, 0xFF, sizeof iv);
+ memset(s, 0, 16);
+ ctx->sk.vtable->run(&ctx->sk.vtable, iv, 0xFFFFFFFF, s, 16);
+
+ /*
+ * Set G[] and H[] to conventional start values.
+ */
+ memset(G, 0xB6, sizeof G);
+ memset(H, 0x5A, sizeof H);
+
+ /*
+ * Process the concatenation of the current state and the seed
+ * with the custom hash function.
+ */
+ first = 1;
+ for (;;) {
+ unsigned char tmp[32];
+ unsigned char newG[16];
+
+ /*
+ * Assemble new key H||m into tmp[].
+ */
+ memcpy(tmp, H, 16);
+ if (first) {
+ memcpy(tmp + 16, s, 16);
+ first = 0;
+ } else {
+ size_t clen;
+
+ if (len == 0) {
+ break;
+ }
+ clen = len < 16 ? len : 16;
+ memcpy(tmp + 16, seed, clen);
+ memset(tmp + 16 + clen, 0, 16 - clen);
+ seed = (const unsigned char *)seed + clen;
+ len -= clen;
+ }
+ ctx->sk.vtable->init(&ctx->sk.vtable, tmp, 32);
+
+ /*
+ * Compute new G and H values.
+ */
+ memcpy(iv, G, 12);
+ memcpy(newG, G, 16);
+ ctx->sk.vtable->run(&ctx->sk.vtable, iv,
+ br_dec32be(G + 12), newG, 16);
+ iv[0] ^= 0x01;
+ memcpy(H, G, 16);
+ H[0] ^= 0x01;
+ ctx->sk.vtable->run(&ctx->sk.vtable, iv,
+ br_dec32be(G + 12), H, 16);
+ memcpy(G, newG, 16);
+ }
+
+ /*
+ * Output hash value is H||G. We truncate it to its first 128 bits,
+ * i.e. H; that's our new AES key.
+ */
+ ctx->sk.vtable->init(&ctx->sk.vtable, H, 16);
+ ctx->cc = 0;
+}
+
+/* see bearssl_rand.h */
+const br_prng_class br_aesctr_drbg_vtable = {
+ sizeof(br_aesctr_drbg_context),
+ (void (*)(const br_prng_class **, const void *, const void *, size_t))
+ &br_aesctr_drbg_init,
+ (void (*)(const br_prng_class **, void *, size_t))
+ &br_aesctr_drbg_generate,
+ (void (*)(const br_prng_class **, const void *, size_t))
+ &br_aesctr_drbg_update
+};
diff --git a/test/monniaux/BearSSL/src/rand/hmac_drbg.c b/test/monniaux/BearSSL/src/rand/hmac_drbg.c
new file mode 100644
index 00000000..d746756d
--- /dev/null
+++ b/test/monniaux/BearSSL/src/rand/hmac_drbg.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * 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 "inner.h"
+
+/* see bearssl.h */
+void
+br_hmac_drbg_init(br_hmac_drbg_context *ctx,
+ const br_hash_class *digest_class, const void *seed, size_t len)
+{
+ size_t hlen;
+
+ ctx->vtable = &br_hmac_drbg_vtable;
+ hlen = br_digest_size(digest_class);
+ memset(ctx->K, 0x00, hlen);
+ memset(ctx->V, 0x01, hlen);
+ ctx->digest_class = digest_class;
+ br_hmac_drbg_update(ctx, seed, len);
+}
+
+/* see bearssl.h */
+void
+br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len)
+{
+ const br_hash_class *dig;
+ br_hmac_key_context kc;
+ br_hmac_context hc;
+ size_t hlen;
+ unsigned char *buf;
+ unsigned char x;
+
+ dig = ctx->digest_class;
+ hlen = br_digest_size(dig);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+ buf = out;
+ while (len > 0) {
+ size_t clen;
+
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+ clen = hlen;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(buf, ctx->V, clen);
+ buf += clen;
+ len -= clen;
+ }
+
+ /*
+ * To prepare the state for the next request, we should call
+ * br_hmac_drbg_update() with an empty additional seed. However,
+ * we already have an initialized HMAC context with the right
+ * initial key, and we don't want to push another one on the
+ * stack, so we inline that update() call here.
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ x = 0x00;
+ br_hmac_update(&hc, &x, 1);
+ br_hmac_out(&hc, ctx->K);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+}
+
+/* see bearssl.h */
+void
+br_hmac_drbg_update(br_hmac_drbg_context *ctx, const void *seed, size_t len)
+{
+ const br_hash_class *dig;
+ br_hmac_key_context kc;
+ br_hmac_context hc;
+ size_t hlen;
+ unsigned char x;
+
+ dig = ctx->digest_class;
+ hlen = br_digest_size(dig);
+
+ /*
+ * 1. K = HMAC(K, V || 0x00 || seed)
+ */
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ x = 0x00;
+ br_hmac_update(&hc, &x, 1);
+ br_hmac_update(&hc, seed, len);
+ br_hmac_out(&hc, ctx->K);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+
+ /*
+ * 2. V = HMAC(K, V)
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+
+ /*
+ * 3. If the additional seed is empty, then stop here.
+ */
+ if (len == 0) {
+ return;
+ }
+
+ /*
+ * 4. K = HMAC(K, V || 0x01 || seed)
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ x = 0x01;
+ br_hmac_update(&hc, &x, 1);
+ br_hmac_update(&hc, seed, len);
+ br_hmac_out(&hc, ctx->K);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+
+ /*
+ * 5. V = HMAC(K, V)
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+}
+
+/* see bearssl.h */
+const br_prng_class br_hmac_drbg_vtable = {
+ sizeof(br_hmac_drbg_context),
+ (void (*)(const br_prng_class **, const void *, const void *, size_t))
+ &br_hmac_drbg_init,
+ (void (*)(const br_prng_class **, void *, size_t))
+ &br_hmac_drbg_generate,
+ (void (*)(const br_prng_class **, const void *, size_t))
+ &br_hmac_drbg_update
+};
diff --git a/test/monniaux/BearSSL/src/rand/sysrng.c b/test/monniaux/BearSSL/src/rand/sysrng.c
new file mode 100644
index 00000000..5ddbcbea
--- /dev/null
+++ b/test/monniaux/BearSSL/src/rand/sysrng.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * 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.
+ */
+
+#define BR_ENABLE_INTRINSICS 1
+#include "inner.h"
+
+#if BR_USE_URANDOM
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#if BR_USE_WIN32_RAND
+#include <windows.h>
+#include <wincrypt.h>
+#pragma comment(lib, "advapi32")
+#endif
+
+#if BR_RDRAND
+BR_TARGETS_X86_UP
+BR_TARGET("rdrnd")
+static int
+seeder_rdrand(const br_prng_class **ctx)
+{
+ unsigned char tmp[32];
+ size_t u;
+
+ for (u = 0; u < sizeof tmp; u += sizeof(uint32_t)) {
+ int j;
+ uint32_t x;
+
+ /*
+ * We use the 32-bit intrinsic so that code is compatible
+ * with both 32-bit and 64-bit architectures.
+ *
+ * Intel recommends trying at least 10 times in case of
+ * failure.
+ */
+ for (j = 0; j < 10; j ++) {
+ if (_rdrand32_step(&x)) {
+ goto next_word;
+ }
+ }
+ return 0;
+ next_word:
+ br_enc32le(tmp + u, x);
+ }
+ (*ctx)->update(ctx, tmp, sizeof tmp);
+ return 1;
+}
+BR_TARGETS_X86_DOWN
+
+static int
+rdrand_supported(void)
+{
+ /*
+ * The RDRND support is bit 30 of ECX, as returned by CPUID.
+ */
+ return br_cpuid(0, 0, 0x40000000, 0);
+}
+
+#endif
+
+#if BR_USE_URANDOM
+static int
+seeder_urandom(const br_prng_class **ctx)
+{
+ int f;
+
+ f = open("/dev/urandom", O_RDONLY);
+ if (f >= 0) {
+ unsigned char tmp[32];
+ size_t u;
+
+ for (u = 0; u < sizeof tmp;) {
+ ssize_t len;
+
+ len = read(f, tmp + u, (sizeof tmp) - u);
+ if (len < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ break;
+ }
+ u += (size_t)len;
+ }
+ close(f);
+ if (u == sizeof tmp) {
+ (*ctx)->update(ctx, tmp, sizeof tmp);
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+#if BR_USE_WIN32_RAND
+static int
+seeder_win32(const br_prng_class **ctx)
+{
+ HCRYPTPROV hp;
+
+ if (CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+ {
+ BYTE buf[32];
+ BOOL r;
+
+ r = CryptGenRandom(hp, sizeof buf, buf);
+ CryptReleaseContext(hp, 0);
+ if (r) {
+ (*ctx)->update(ctx, buf, sizeof buf);
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+/* see bearssl_rand.h */
+br_prng_seeder
+br_prng_seeder_system(const char **name)
+{
+#if BR_RDRAND
+ if (rdrand_supported()) {
+ if (name != NULL) {
+ *name = "rdrand";
+ }
+ return &seeder_rdrand;
+ }
+#endif
+#if BR_USE_URANDOM
+ if (name != NULL) {
+ *name = "urandom";
+ }
+ return &seeder_urandom;
+#elif BR_USE_WIN32_RAND
+ if (name != NULL) {
+ *name = "win32";
+ }
+ return &seeder_win32;
+#else
+ if (name != NULL) {
+ *name = "none";
+ }
+ return 0;
+#endif
+}