mirror of
https://github.com/henrydcase/pqc.git
synced 2024-11-27 18:01:34 +00:00
337 lines
10 KiB
C
337 lines
10 KiB
C
/**
|
|
*
|
|
* <rng.c>
|
|
*
|
|
* @version 2.0 (March 2019)
|
|
*
|
|
* Reference ISO-C11 Implementation of the LEDAcrypt KEM-LT cipher using GCC built-ins.
|
|
*
|
|
* In alphabetical order:
|
|
*
|
|
* @author Marco Baldi <m.baldi@univpm.it>
|
|
* @author Alessandro Barenghi <alessandro.barenghi@polimi.it>
|
|
* @author Franco Chiaraluce <f.chiaraluce@univpm.it>
|
|
* @author Gerardo Pelosi <gerardo.pelosi@polimi.it>
|
|
* @author Paolo Santini <p.santini@pm.univpm.it>
|
|
*
|
|
* This code is hereby placed in the public domain.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
**/
|
|
|
|
|
|
#include "rng.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h> // void srand(unsigned int seed); int rand(void); RAND_MAX
|
|
#include <string.h> // void *memset(void *s, int c, size_t n);
|
|
#define __USE_POSIX199309
|
|
#include <time.h> // struct timespec; clock_gettime(...); CLOCK_REALTIME
|
|
|
|
#include "aes256.h"
|
|
#include "qc_ldpc_parameters.h"
|
|
|
|
|
|
/******************************************************************************/
|
|
/*----------------------------------------------------------------------------*/
|
|
/* start PSEUDO-RAND GENERATOR ROUTINES for rnd.h */
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
void initialize_pseudo_random_generator_seed(int ac, char *av[]) {
|
|
|
|
if (ac == 2) {
|
|
srand(atoi(av[1]));
|
|
} else {
|
|
struct timespec seedValue;
|
|
clock_gettime(CLOCK_REALTIME, &seedValue);
|
|
srand(seedValue.tv_nsec);
|
|
} // end else-if
|
|
unsigned char pseudo_entropy[48];
|
|
for (int i = 0; i < 48; i++) {
|
|
pseudo_entropy[i] = rand() & 0xff;
|
|
}
|
|
randombytes_init(pseudo_entropy,
|
|
NULL,
|
|
0 /*unused in NIST function*/);
|
|
|
|
|
|
} // end initilize_pseudo_random_sequence_seed
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/* Initializes a dedicated DRBG context to avoid conflicts with the global one
|
|
* declared by NIST for KATs. Provides the output of the DRBG in output, for
|
|
* the given length */
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/* end PSEUDO-RAND GENERATOR ROUTINES for rnd.h */
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
AES256_CTR_DRBG_struct DRBG_ctx;
|
|
|
|
void AES256_ECB(unsigned char *key, unsigned char *ctr,
|
|
unsigned char *buffer);
|
|
|
|
/*
|
|
seedexpander_init()
|
|
ctx - stores the current state of an instance of the seed expander
|
|
seed - a 32 byte random value
|
|
diversifier - an 8 byte diversifier
|
|
maxlen - maximum number of bytes (less than 2**32) generated under this seed and diversifier
|
|
*/
|
|
int
|
|
seedexpander_init(AES_XOF_struct *ctx,
|
|
unsigned char *seed,
|
|
unsigned char *diversifier,
|
|
unsigned long maxlen) {
|
|
if ( maxlen >= 0x100000000 ) {
|
|
return RNG_BAD_MAXLEN;
|
|
}
|
|
|
|
ctx->length_remaining = maxlen;
|
|
|
|
memset(ctx->key, 0, 32);
|
|
int max_accessible_seed_len = TRNG_BYTE_LENGTH < 32 ? 32 : TRNG_BYTE_LENGTH;
|
|
memcpy(ctx->key, seed, max_accessible_seed_len);
|
|
|
|
memcpy(ctx->ctr, diversifier, 8);
|
|
ctx->ctr[11] = maxlen % 256;
|
|
maxlen >>= 8;
|
|
ctx->ctr[10] = maxlen % 256;
|
|
maxlen >>= 8;
|
|
ctx->ctr[9] = maxlen % 256;
|
|
maxlen >>= 8;
|
|
ctx->ctr[8] = maxlen % 256;
|
|
memset(ctx->ctr + 12, 0x00, 4);
|
|
|
|
ctx->buffer_pos = 16;
|
|
memset(ctx->buffer, 0x00, 16);
|
|
|
|
return RNG_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
seedexpander()
|
|
ctx - stores the current state of an instance of the seed expander
|
|
x - returns the XOF data
|
|
xlen - number of bytes to return
|
|
*/
|
|
int
|
|
seedexpander(AES_XOF_struct *ctx, unsigned char *x, unsigned long xlen) {
|
|
unsigned long offset;
|
|
|
|
if ( x == NULL ) {
|
|
return RNG_BAD_OUTBUF;
|
|
}
|
|
if ( xlen >= ctx->length_remaining ) {
|
|
return RNG_BAD_REQ_LEN;
|
|
}
|
|
|
|
ctx->length_remaining -= xlen;
|
|
|
|
offset = 0;
|
|
while ( xlen > 0 ) {
|
|
if ( xlen <= (16 - ctx->buffer_pos) ) { // buffer has what we need
|
|
memcpy(x + offset, ctx->buffer + ctx->buffer_pos, xlen);
|
|
ctx->buffer_pos += xlen;
|
|
|
|
return RNG_SUCCESS;
|
|
}
|
|
|
|
// take what's in the buffer
|
|
memcpy(x + offset, ctx->buffer + ctx->buffer_pos, 16 - ctx->buffer_pos);
|
|
xlen -= 16 - ctx->buffer_pos;
|
|
offset += 16 - ctx->buffer_pos;
|
|
|
|
AES256_ECB(ctx->key, ctx->ctr, ctx->buffer);
|
|
ctx->buffer_pos = 0;
|
|
|
|
//increment the counter
|
|
for (int i = 15; i >= 12; i--) {
|
|
if ( ctx->ctr[i] == 0xff ) {
|
|
ctx->ctr[i] = 0x00;
|
|
} else {
|
|
ctx->ctr[i]++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return RNG_SUCCESS;
|
|
}
|
|
|
|
// Use whatever AES implementation you have. This uses AES from openSSL library
|
|
// key - 256-bit AES key
|
|
// ptx - a 128-bit plaintext value
|
|
// ctx - a 128-bit ciphertext value
|
|
|
|
void
|
|
AES256_ECB(unsigned char *key, unsigned char *ptx, unsigned char *ctx) {
|
|
uint32_t round_key[4 * (NROUNDS + 1)] = {0x00};
|
|
rijndaelKeySetupEnc(round_key, key, KEYLEN_b);
|
|
rijndaelEncrypt(round_key, NROUNDS, ptx, ctx);
|
|
}
|
|
|
|
void
|
|
randombytes_init(unsigned char *entropy_input,
|
|
unsigned char *personalization_string,
|
|
int security_strength) {
|
|
unsigned char seed_material[48];
|
|
|
|
memcpy(seed_material, entropy_input, 48);
|
|
if (personalization_string)
|
|
for (int i = 0; i < 48; i++) {
|
|
seed_material[i] ^= personalization_string[i];
|
|
}
|
|
memset(DRBG_ctx.Key, 0x00, 32);
|
|
memset(DRBG_ctx.V, 0x00, 16);
|
|
AES256_CTR_DRBG_Update(seed_material, DRBG_ctx.Key, DRBG_ctx.V);
|
|
DRBG_ctx.reseed_counter = 1;
|
|
}
|
|
|
|
int
|
|
randombytes(unsigned char *x, unsigned long long xlen) {
|
|
unsigned char block[16];
|
|
int i = 0;
|
|
|
|
while ( xlen > 0 ) {
|
|
//increment V
|
|
for (int j = 15; j >= 0; j--) {
|
|
if ( DRBG_ctx.V[j] == 0xff ) {
|
|
DRBG_ctx.V[j] = 0x00;
|
|
} else {
|
|
DRBG_ctx.V[j]++;
|
|
break;
|
|
}
|
|
}
|
|
AES256_ECB(DRBG_ctx.Key, DRBG_ctx.V, block);
|
|
if ( xlen > 15 ) {
|
|
memcpy(x + i, block, 16);
|
|
i += 16;
|
|
xlen -= 16;
|
|
} else {
|
|
memcpy(x + i, block, xlen);
|
|
xlen = 0;
|
|
}
|
|
}
|
|
AES256_CTR_DRBG_Update(NULL, DRBG_ctx.Key, DRBG_ctx.V);
|
|
DRBG_ctx.reseed_counter++;
|
|
|
|
return RNG_SUCCESS;
|
|
}
|
|
|
|
void
|
|
AES256_CTR_DRBG_Update(unsigned char *provided_data,
|
|
unsigned char *Key,
|
|
unsigned char *V) {
|
|
unsigned char temp[48];
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
//increment V
|
|
for (int j = 15; j >= 0; j--) {
|
|
if ( V[j] == 0xff ) {
|
|
V[j] = 0x00;
|
|
} else {
|
|
V[j]++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
AES256_ECB(Key, V, temp + 16 * i);
|
|
}
|
|
if ( provided_data != NULL )
|
|
for (int i = 0; i < 48; i++) {
|
|
temp[i] ^= provided_data[i];
|
|
}
|
|
memcpy(Key, temp, 32);
|
|
memcpy(V, temp + 32, 16);
|
|
}
|
|
|
|
|
|
|
|
void deterministic_random_byte_generator(unsigned char *const output,
|
|
const unsigned long long output_len,
|
|
const unsigned char *const seed,
|
|
const unsigned long long seed_length
|
|
) {
|
|
/* DRBG context initialization */
|
|
AES256_CTR_DRBG_struct ctx;
|
|
unsigned char seed_material[48];
|
|
memset(seed_material, 0x00, 48);
|
|
memcpy(seed_material, seed, seed_length);
|
|
|
|
memset(ctx.Key, 0x00, 32);
|
|
memset(ctx.V, 0x00, 16);
|
|
AES256_CTR_DRBG_Update(seed_material, ctx.Key, ctx.V);
|
|
ctx.reseed_counter = 1;
|
|
|
|
/* Actual DRBG computation as from the randombytes(unsigned char *x,
|
|
* unsigned long long xlen) from NIST */
|
|
|
|
unsigned char block[16];
|
|
int i = 0, length_remaining;
|
|
|
|
length_remaining = output_len;
|
|
|
|
while ( length_remaining > 0 ) {
|
|
//increment V
|
|
for (int j = 15; j >= 0; j--) {
|
|
if ( ctx.V[j] == 0xff ) {
|
|
ctx.V[j] = 0x00;
|
|
} else {
|
|
ctx.V[j]++;
|
|
break;
|
|
}
|
|
}
|
|
AES256_ECB(ctx.Key, ctx.V, block);
|
|
if ( length_remaining > 15 ) {
|
|
memcpy(output + i, block, 16);
|
|
i += 16;
|
|
length_remaining -= 16;
|
|
} else {
|
|
memcpy(output + i, block, length_remaining);
|
|
length_remaining = 0;
|
|
}
|
|
}
|
|
AES256_CTR_DRBG_Update(NULL, ctx.Key, ctx.V);
|
|
ctx.reseed_counter++;
|
|
|
|
} // end deterministic_random_byte_generator
|
|
|
|
void seedexpander_from_trng(AES_XOF_struct *ctx,
|
|
const unsigned char *trng_entropy
|
|
/* TRNG_BYTE_LENGTH wide buffer */) {
|
|
|
|
/*the NIST seedexpander will however access 32B from this buffer */
|
|
unsigned int prng_buffer_size = TRNG_BYTE_LENGTH < 32 ? 32 : TRNG_BYTE_LENGTH;
|
|
unsigned char prng_buffer[TRNG_BYTE_LENGTH < 32 ? 32 : TRNG_BYTE_LENGTH] = { 0x00 };
|
|
memcpy(prng_buffer,
|
|
trng_entropy,
|
|
TRNG_BYTE_LENGTH < prng_buffer_size ? TRNG_BYTE_LENGTH : prng_buffer_size);
|
|
/* if extra entropy is provided, add it to the diversifier */
|
|
#if TRNG_BYTE_LENGTH == 40
|
|
unsigned char *diversifier = ((unsigned char *)trng_entropy) + 32;
|
|
#else
|
|
unsigned char diversifier[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
#endif
|
|
/* the required seed expansion will be quite small, set the max number of
|
|
* bytes conservatively to 10 MiB*/
|
|
seedexpander_init(ctx, prng_buffer, diversifier, 10 * 1024 * 1024);
|
|
}
|