pqc/common/nistseedexpander.c
2021-03-24 21:02:46 +00:00

104 lines
2.5 KiB
C

//
// rng.c
//
// Created by Bassham, Lawrence E (Fed) on 8/29/17.
// Copyright © 2017 Bassham, Lawrence E (Fed). All rights reserved.
// Modified for PQClean by Sebastian Verschoor
//
#include "nistseedexpander.h"
#include "aes.h"
#include <string.h>
/*
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,
const uint8_t *seed,
const uint8_t *diversifier,
size_t maxlen)
{
ctx->length_remaining = maxlen;
memcpy(ctx->key, seed, 32);
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;
}
static void AES256_ECB(uint8_t *key, uint8_t *ctr, uint8_t *buffer) {
aes256ctx ctx;
aes256_ecb_keyexp(&ctx, key);
aes256_ecb(buffer, ctr, 1, &ctx);
aes256_ctx_release(&ctx);
}
/*
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, uint8_t *x, size_t xlen)
{
size_t 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 (size_t i=15; i>=12; i--) {
if ( ctx->ctr[i] == 0xff ) {
ctx->ctr[i] = 0x00;
} else {
ctx->ctr[i]++;
break;
}
}
}
return RNG_SUCCESS;
}