From 2777bfd449facf45f2229b9ff20f3422dec1c074 Mon Sep 17 00:00:00 2001 From: Alex Parent Date: Wed, 26 Oct 2016 21:46:19 -0400 Subject: [PATCH] Add PRNG based on AES-CTR (#37) --- Makefile | 11 +- src/rand/rand.c | 3 + src/rand/rand.h | 1 + src/rand/test_rand.c | 1 + src/rand_urandom_aesctr/rand_urandom_aesctr.c | 150 ++++++++++++++++++ src/rand_urandom_aesctr/rand_urandom_aesctr.h | 24 +++ 6 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 src/rand_urandom_aesctr/rand_urandom_aesctr.c create mode 100644 src/rand_urandom_aesctr/rand_urandom_aesctr.h diff --git a/Makefile b/Makefile index b4b571ac1..23690ffba 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ CURL=curl RANLIB=ranlib LN=ln -s -DEFAULTS= -O3 -std=c11 -Wpedantic -Wall -Wextra -DOQS_RAND_DEFAULT_URANDOM_CHACHA20 -DOQS_KEX_DEFAULT_BCNS15 +DEFAULTS= -O3 -std=gnu11 -Wpedantic -Wall -Wextra -DOQS_RAND_DEFAULT_URANDOM_CHACHA20 -DOQS_KEX_DEFAULT_BCNS15 CFLAGS=$(DEFAULTS) -DCONSTANT_TIME LDFLAGS=-lm INCLUDES=-Iinclude @@ -49,11 +49,16 @@ links: $(LN) ../../src/kex_lwe_frodo/kex_lwe_frodo.h include/oqs $(LN) ../../src/rand/rand.h include/oqs $(LN) ../../src/rand_urandom_chacha20/rand_urandom_chacha20.h include/oqs + $(LN) ../../src/rand_urandom_aesctr/rand_urandom_aesctr.h include/oqs # RAND_URANDOM_CHACHA RAND_URANDOM_CHACHA_OBJS := $(addprefix objs/rand_urandom_chacha20/, rand_urandom_chacha20.o) $(RAND_URANDOM_CHACHA_OBJS): src/rand_urandom_chacha20/rand_urandom_chacha20.h +# RAND_URANDOM_AESCTR +RAND_URANDOM_AESCTR_OBJS := $(addprefix objs/rand_urandom_aesctr/, rand_urandom_aesctr.o) +$(RAND_URANDOM_AESCTR_OBJS): src/rand_urandom_aesctr/rand_urandom_aesctr.h + # RAND objs/rand/rand.o: src/rand/rand.h @@ -82,7 +87,9 @@ objs/kex/kex.o: src/kex/kex.h # LIB -lib: $(RAND_URANDOM_CHACHA_OBJS) $(KEX_RLWE_BCNS15_OBJS) $(KEX_RLWE_NEWHOPE_OBJS) $(KEX_LWE_FRODO_OBJS) objs/rand/rand.o objs/kex/kex.o $(AES_OBJS) +RAND_OBJS := $(RAND_URANDOM_AESCTR_OBJS) $(RAND_URANDOM_CHACHA_OBJS) + +lib: $(RAND_OBJS) $(KEX_RLWE_BCNS15_OBJS) $(KEX_RLWE_NEWHOPE_OBJS) $(KEX_LWE_FRODO_OBJS) objs/rand/rand.o objs/kex/kex.o $(AES_OBJS) rm -f liboqs.a $(AR) liboqs.a $^ $(RANLIB) liboqs.a diff --git a/src/rand/rand.c b/src/rand/rand.c index 277350f1c..865296869 100644 --- a/src/rand/rand.c +++ b/src/rand/rand.c @@ -3,12 +3,15 @@ #include #include +#include OQS_RAND *OQS_RAND_new(enum OQS_RAND_alg_name alg_name) { switch (alg_name) { case OQS_RAND_alg_default: case OQS_RAND_alg_urandom_chacha20: return OQS_RAND_urandom_chacha20_new(); + case OQS_RAND_alg_urandom_aesctr: + return OQS_RAND_urandom_aesctr_new(); default: assert(0); return NULL; // avoid the warning of potentialy uninitialized variable in VS diff --git a/src/rand/rand.h b/src/rand/rand.h index 6eda27652..79ecf6206 100755 --- a/src/rand/rand.h +++ b/src/rand/rand.h @@ -12,6 +12,7 @@ enum OQS_RAND_alg_name { OQS_RAND_alg_default, OQS_RAND_alg_urandom_chacha20, + OQS_RAND_alg_urandom_aesctr, }; typedef struct OQS_RAND OQS_RAND; diff --git a/src/rand/test_rand.c b/src/rand/test_rand.c index 7585afbde..c5390dafc 100755 --- a/src/rand/test_rand.c +++ b/src/rand/test_rand.c @@ -12,6 +12,7 @@ struct rand_testcase { /* Add new testcases here */ struct rand_testcase rand_testcases[] = { { OQS_RAND_alg_urandom_chacha20 }, + { OQS_RAND_alg_urandom_aesctr}, }; #define RAND_TEST_ITERATIONS 10000000L diff --git a/src/rand_urandom_aesctr/rand_urandom_aesctr.c b/src/rand_urandom_aesctr/rand_urandom_aesctr.c new file mode 100644 index 000000000..110da79de --- /dev/null +++ b/src/rand_urandom_aesctr/rand_urandom_aesctr.c @@ -0,0 +1,150 @@ +#include +#if defined(WINDOWS) +#include +#include +#else +#include +#include +#include +#endif +#include //memcpy +#include +#include +#include + +#include +#include +#include + +typedef struct OQS_RAND_urandom_aesctr_ctx { + union { + uint8_t ba[16]; + uint64_t ui[2]; + } ctr; + uint8_t schedule[20 * 16]; + uint8_t cache[64]; + size_t cache_next_byte; +} OQS_RAND_urandom_aesctr_ctx; + +static OQS_RAND_urandom_aesctr_ctx *OQS_RAND_urandom_aesctr_ctx_new() { + int fd = 0; + OQS_RAND_urandom_aesctr_ctx *rand_ctx = NULL; + rand_ctx = (OQS_RAND_urandom_aesctr_ctx *) malloc(sizeof(OQS_RAND_urandom_aesctr_ctx)); + if (rand_ctx == NULL) { + goto err; + } + uint8_t key[16]; +#if defined(WINDOWS) + HCRYPTPROV hCryptProv; + if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) || + !cryptgenrandom(hcryptprov, 16, key) || + !cryptgenrandom(hcryptprov, 8, &rand_ctx->ctr[8]) ) { + goto err; + } +#else + fd = open("/dev/urandom", O_RDONLY); + if (fd <= 0) { + goto err; + } + int r = read(fd, key, 16); + if (r != 16) { + goto err; + } + r = read(fd, &rand_ctx->ctr.ba[8], 8); + if (r != 8) { + goto err; + } +#endif + OQS_AES128_load_schedule(key, rand_ctx->schedule); + rand_ctx->cache_next_byte = 64; // cache is empty + goto okay; +err: + if (rand_ctx) { + free(rand_ctx); + } +#if !defined(WINDOWS) + if (fd > 0) { + close(fd); + } +#endif + return NULL; +okay: +#if !defined(WINDOWS) + close(fd); +#endif + return rand_ctx; +} + +static void OQS_RAND_urandom_aesctr_fill_cache(OQS_RAND *r) { + OQS_RAND_urandom_aesctr_ctx *rand_ctx = (OQS_RAND_urandom_aesctr_ctx *) r->ctx; + for (int i = 0; i < 4; i++) { + OQS_AES128_enc(rand_ctx->ctr.ba, rand_ctx->schedule, &rand_ctx->cache[i * 16]); + rand_ctx->ctr.ui[0]++; + } + rand_ctx->cache_next_byte = 0; +} + +void OQS_RAND_urandom_aesctr_n(OQS_RAND *r, uint8_t *out, size_t n) { + OQS_RAND_urandom_aesctr_ctx *rand_ctx = (OQS_RAND_urandom_aesctr_ctx *) r->ctx; + while (n > 0) { + if (n + rand_ctx->cache_next_byte < 64) { + memcpy(out, &rand_ctx->cache[rand_ctx->cache_next_byte], n); + rand_ctx->cache_next_byte += n; + n = 0; + } else { + size_t bytes_left = 64 - rand_ctx->cache_next_byte; + memcpy(out, &rand_ctx->cache[rand_ctx->cache_next_byte], bytes_left); + out += bytes_left; + n -= bytes_left; + OQS_RAND_urandom_aesctr_fill_cache(r); + } + } +} + +uint8_t OQS_RAND_urandom_aesctr_8(OQS_RAND *r) { + uint8_t out; + OQS_RAND_urandom_aesctr_n(r, (uint8_t *)&out, 1); + return out; +} + + +uint32_t OQS_RAND_urandom_aesctr_32(OQS_RAND *r) { + uint32_t out; + OQS_RAND_urandom_aesctr_n(r, (uint8_t *)&out, 4); + return out; +} + +uint64_t OQS_RAND_urandom_aesctr_64(OQS_RAND *r) { + uint64_t out; + OQS_RAND_urandom_aesctr_n(r, (uint8_t *)&out, 8); + return out; +} + +void OQS_RAND_urandom_aesctr_free(OQS_RAND *r) { + if (r) { + free(r->ctx); + free(r->method_name); + } + free(r); +} + +OQS_RAND *OQS_RAND_urandom_aesctr_new() { + OQS_RAND *r = malloc(sizeof(OQS_RAND)); + if (r == NULL) { + return NULL; + } + r->method_name = strdup("urandom_aesctr"); + r->ctx = OQS_RAND_urandom_aesctr_ctx_new(); + if (r->ctx == NULL || r->method_name == NULL) { + OQS_RAND_urandom_aesctr_free(r); + return NULL; + } + r->estimated_classical_security = 128; + r->estimated_quantum_security = 64; // Grover search + r->rand_8 = &OQS_RAND_urandom_aesctr_8; + r->rand_32 = &OQS_RAND_urandom_aesctr_32; + r->rand_64 = &OQS_RAND_urandom_aesctr_64; + r->rand_n = &OQS_RAND_urandom_aesctr_n; + r->free = &OQS_RAND_urandom_aesctr_free; + return r; +} diff --git a/src/rand_urandom_aesctr/rand_urandom_aesctr.h b/src/rand_urandom_aesctr/rand_urandom_aesctr.h new file mode 100644 index 000000000..7857f3df3 --- /dev/null +++ b/src/rand_urandom_aesctr/rand_urandom_aesctr.h @@ -0,0 +1,24 @@ +/** + * \file rand_urandom_aesctr.h + * \brief Header for the chacha implementation of OQS_RAND + */ + + +#ifndef __OQS_RAND_URANDOM_AESCTR_H +#define __OQS_RAND_URANDOM_AESCTR_H + +#include +#include + +#include + +OQS_RAND *OQS_RAND_urandom_aesctr_new(); + +uint8_t OQS_RAND_urandom_aesctr_8(OQS_RAND *r); +uint32_t OQS_RAND_urandom_aesctr_32(OQS_RAND *r); +uint64_t OQS_RAND_urandom_aesctr_64(OQS_RAND *r); +void OQS_RAND_urandom_aesctr_n(OQS_RAND *r, uint8_t *out, size_t n); + +void OQS_RAND_urandom_aesctr_free(OQS_RAND *r); + +#endif