Add PRNG based on AES-CTR (#37)

This commit is contained in:
Alex Parent 2016-10-26 21:46:19 -04:00 committed by Douglas Stebila
parent 42cad43e15
commit 2777bfd449
6 changed files with 188 additions and 2 deletions

View File

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

View File

@ -3,12 +3,15 @@
#include <oqs/rand.h>
#include <oqs/rand_urandom_chacha20.h>
#include <oqs/rand_urandom_aesctr.h>
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

View File

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

View File

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

View File

@ -0,0 +1,150 @@
#include <sys/types.h>
#if defined(WINDOWS)
#include <windows.h>
#include <Wincrypt.h>
#else
#include <sys/uio.h>
#include <unistd.h>
#include <strings.h>
#endif
#include <string.h> //memcpy
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <oqs/rand.h>
#include <oqs/rand_urandom_aesctr.h>
#include <oqs/aes.h>
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;
}

View File

@ -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 <stddef.h>
#include <stdint.h>
#include <oqs/rand.h>
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