956 lines
25 KiB
C
956 lines
25 KiB
C
/******************************************************************************
|
|
* NTRU Cryptography Reference Source Code
|
|
*
|
|
* Copyright (C) 2009-2016 Security Innovation (SI)
|
|
*
|
|
* SI has dedicated the work to the public domain by waiving all of its rights
|
|
* to the work worldwide under copyright law, including all related and
|
|
* neighboring rights, to the extent allowed by law.
|
|
*
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* You can copy, modify, distribute and perform the work, even for commercial
|
|
* purposes, all without asking permission. You should have received a copy of
|
|
* the creative commons license (CC0 1.0 universal) along with this program.
|
|
* See the license file for more information.
|
|
*
|
|
*
|
|
*********************************************************************************/
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* File: ntru_crypto_drbg.c
|
|
*
|
|
* Contents: Implementation of a SHA-256 HMAC-based deterministic random byte
|
|
* generator (HMAC_DRBG) as defined in ANSI X9.82, Part 3 - 2007.
|
|
*
|
|
* This implementation:
|
|
* - allows for MAX_INSTANTIATIONS simultaneous drbg instantiations
|
|
* (may be overridden on compiler command line)
|
|
* - has a maximum security strength of 256 bits
|
|
* - automatically uses SHA-256 for all security strengths
|
|
* - allows a personalization string of length up to
|
|
* HMAC_DRBG_MAX_PERS_STR_BYTES bytes
|
|
* - implments reseeding
|
|
* - does not implement additional input for reseeding or generation
|
|
* - does not implement predictive resistance
|
|
* - limits the number of bytes requested in one invocation of generate to
|
|
* MAX_BYTES_PER_REQUEST
|
|
* - uses a callback function to allow the caller to supply the
|
|
* Get_entropy_input routine (entropy function)
|
|
* - limits the number of bytes returned from the entropy function to
|
|
* MAX_ENTROPY_NONCE_BYTES
|
|
* - gets the nonce bytes along with the entropy input from the entropy
|
|
* function
|
|
* - automatically reseeds an instantitation after MAX_REQUESTS calls to
|
|
* generate
|
|
*
|
|
*****************************************************************************/
|
|
|
|
|
|
#include "ntru_crypto.h"
|
|
#include "ntru_crypto_drbg.h"
|
|
#include "ntru_crypto_hmac.h"
|
|
|
|
|
|
/************************
|
|
* HMAC_DRBG parameters *
|
|
************************/
|
|
|
|
/* Note: Combined entropy input and nonce are a total of 2 * sec_strength_bits
|
|
* of randomness to provide quantum resistance */
|
|
#define HMAC_DRBG_MAX_MIN_ENTROPY_NONCE_BYTES \
|
|
(2 * DRBG_MAX_SEC_STRENGTH_BITS)/8
|
|
#define HMAC_DRBG_MAX_ENTROPY_NONCE_BYTES \
|
|
HMAC_DRBG_MAX_MIN_ENTROPY_NONCE_BYTES * DRBG_MAX_BYTES_PER_BYTE_OF_ENTROPY
|
|
#define HMAC_DRBG_MAX_REQUESTS 0xffffffff
|
|
|
|
|
|
/*******************
|
|
* DRBG structures *
|
|
*******************/
|
|
|
|
/* SHA256_HMAC_DRBG state structure */
|
|
|
|
typedef struct {
|
|
uint32_t sec_strength; /* security strength in bits */
|
|
uint32_t requests_left; /* generation requests remaining
|
|
before reseeding */
|
|
ENTROPY_FN entropy_fn; /* pointer to entropy function */
|
|
NTRU_CRYPTO_HMAC_CTX *hmac_ctx; /* pointer to HMAC context */
|
|
uint8_t V[33]; /* md_len size internal state + 1 */
|
|
} SHA256_HMAC_DRBG_STATE;
|
|
|
|
|
|
/* External DRBG state structure */
|
|
|
|
typedef struct {
|
|
RANDOM_BYTES_FN randombytesfn;
|
|
} EXTERNAL_DRBG_STATE;
|
|
|
|
|
|
/* DRBG state structure */
|
|
|
|
typedef struct {
|
|
uint32_t handle;
|
|
DRBG_TYPE type;
|
|
void *state;
|
|
} DRBG_STATE;
|
|
|
|
|
|
/*************
|
|
* DRBG DATA *
|
|
*************/
|
|
|
|
/* array of drbg states */
|
|
|
|
static DRBG_STATE drbg_state[DRBG_MAX_INSTANTIATIONS];
|
|
|
|
|
|
/******************************
|
|
* SHA256 HMAC_DRBG functions *
|
|
******************************/
|
|
|
|
/* sha256_hmac_drbg_update
|
|
*
|
|
* This routine is the SHA-256 HMAC_DRBG derivation function for
|
|
* instantiation, and reseeding, and it is used in generation as well.
|
|
* It updates the internal state.
|
|
*
|
|
* For instantiation, provided_data1 holds the entropy input and nonce;
|
|
* provided_data2 holds the optional personalization string. Combined, this
|
|
* is the seed material.
|
|
*
|
|
* For reseeding, provided_data1 holds the entropy input;
|
|
* provided_data2 is NULL (because this implementation does not support
|
|
* additional input).
|
|
*
|
|
* For byte generation, both provided_data1 and provided_data2 are NULL.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns HMAC errors if they occur.
|
|
*/
|
|
|
|
static uint32_t
|
|
sha256_hmac_drbg_update(
|
|
SHA256_HMAC_DRBG_STATE *s,
|
|
uint8_t *key, /* md_len size array */
|
|
uint32_t md_len,
|
|
uint8_t const *provided_data1,
|
|
uint32_t provided_data1_bytes,
|
|
uint8_t const *provided_data2,
|
|
uint32_t provided_data2_bytes)
|
|
{
|
|
uint32_t result;
|
|
|
|
/* new key = HMAC(K, V || 0x00 [|| provided data1 [|| provided data2]] */
|
|
|
|
if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) != NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
s->V[md_len] = 0x00;
|
|
|
|
if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V, md_len + 1)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (provided_data1)
|
|
{
|
|
if ((result = ntru_crypto_hmac_update(s->hmac_ctx, provided_data1,
|
|
provided_data1_bytes)) != NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (provided_data2)
|
|
{
|
|
if ((result = ntru_crypto_hmac_update(s->hmac_ctx, provided_data2,
|
|
provided_data2_bytes)) != NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_final(s->hmac_ctx, key)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_set_key(s->hmac_ctx, key)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
/* new V = HMAC(K, V) */
|
|
|
|
if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) != NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V, md_len)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_final(s->hmac_ctx, s->V)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
/* if provided data exists, update K and V again */
|
|
|
|
if (provided_data1)
|
|
{
|
|
/* new key = HMAC(K, V || 0x01 || provided data1 [|| provided data2] */
|
|
|
|
if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
s->V[md_len] = 0x01;
|
|
|
|
if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V, md_len + 1)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_update(s->hmac_ctx, provided_data1,
|
|
provided_data1_bytes)) != NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (provided_data2)
|
|
{
|
|
if ((result = ntru_crypto_hmac_update(s->hmac_ctx, provided_data2,
|
|
provided_data2_bytes)) != NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_final(s->hmac_ctx, key)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_set_key(s->hmac_ctx, key)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
/* new V = HMAC(K, V) */
|
|
|
|
if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V, md_len)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_final(s->hmac_ctx, s->V)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
memset(key, 0, md_len);
|
|
DRBG_RET(DRBG_OK);
|
|
}
|
|
|
|
|
|
/* sha256_hmac_drbg_instantiate
|
|
*
|
|
* This routine allocates and initializes a SHA-256 HMAC_DRBG internal state.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns DRBG_BAD_LENGTH if the personalization string is too long.
|
|
* Returns DRBG_OUT_OF_MEMORY if the internal state cannot be allocated.
|
|
* Returns errors from HASH or SHA256 if those errors occur.
|
|
*/
|
|
|
|
static uint32_t
|
|
sha256_hmac_drbg_instantiate(
|
|
uint32_t sec_strength_bits, /* strength to instantiate */
|
|
uint8_t const *pers_str,
|
|
uint32_t pers_str_bytes,
|
|
ENTROPY_FN entropy_fn,
|
|
SHA256_HMAC_DRBG_STATE **state)
|
|
{
|
|
uint8_t entropy_nonce[HMAC_DRBG_MAX_ENTROPY_NONCE_BYTES];
|
|
uint32_t entropy_nonce_bytes;
|
|
uint32_t min_bytes_of_entropy;
|
|
uint8_t num_bytes_per_byte_of_entropy;
|
|
uint8_t key[32]; /* array of md_len size */
|
|
SHA256_HMAC_DRBG_STATE *s;
|
|
uint32_t result;
|
|
uint32_t i;
|
|
|
|
/* check arguments */
|
|
|
|
if (pers_str_bytes > HMAC_DRBG_MAX_PERS_STR_BYTES)
|
|
{
|
|
DRBG_RET(DRBG_BAD_LENGTH);
|
|
}
|
|
|
|
/* calculate number of bytes needed for the entropy input and nonce
|
|
* for a SHA256_HMAC_DRBG, and get them from the entropy source
|
|
*/
|
|
|
|
if (entropy_fn(GET_NUM_BYTES_PER_BYTE_OF_ENTROPY,
|
|
&num_bytes_per_byte_of_entropy) == 0)
|
|
{
|
|
DRBG_RET(DRBG_ENTROPY_FAIL);
|
|
}
|
|
|
|
if ((num_bytes_per_byte_of_entropy == 0) ||
|
|
(num_bytes_per_byte_of_entropy >
|
|
DRBG_MAX_BYTES_PER_BYTE_OF_ENTROPY))
|
|
{
|
|
DRBG_RET(DRBG_ENTROPY_FAIL);
|
|
}
|
|
|
|
min_bytes_of_entropy = (2 * sec_strength_bits) / 8;
|
|
entropy_nonce_bytes = min_bytes_of_entropy * num_bytes_per_byte_of_entropy;
|
|
|
|
for (i = 0; i < entropy_nonce_bytes; i++)
|
|
{
|
|
if (entropy_fn(GET_BYTE_OF_ENTROPY, entropy_nonce+i) == 0)
|
|
{
|
|
DRBG_RET(DRBG_ENTROPY_FAIL);
|
|
}
|
|
}
|
|
|
|
/* allocate SHA256_HMAC_DRBG state */
|
|
s = (SHA256_HMAC_DRBG_STATE*) MALLOC(sizeof(SHA256_HMAC_DRBG_STATE));
|
|
if (s == NULL)
|
|
{
|
|
DRBG_RET(DRBG_OUT_OF_MEMORY);
|
|
}
|
|
|
|
/* allocate HMAC context */
|
|
|
|
memset(key, 0, sizeof(key));
|
|
if ((result = ntru_crypto_hmac_create_ctx(NTRU_CRYPTO_HASH_ALGID_SHA256,
|
|
key, sizeof(key), &s->hmac_ctx)) != NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
FREE(s);
|
|
return result;
|
|
}
|
|
|
|
/* init and update internal state */
|
|
|
|
memset(s->V, 0x01, sizeof(s->V));
|
|
if ((result = sha256_hmac_drbg_update(s, key, sizeof(key),
|
|
entropy_nonce, entropy_nonce_bytes,
|
|
pers_str, pers_str_bytes)) != DRBG_OK)
|
|
{
|
|
(void) ntru_crypto_hmac_destroy_ctx(s->hmac_ctx);
|
|
memset(s->V, 0, sizeof(s->V));
|
|
FREE(s);
|
|
memset(entropy_nonce, 0, sizeof(entropy_nonce));
|
|
return result;
|
|
}
|
|
|
|
memset(entropy_nonce, 0, sizeof(entropy_nonce));
|
|
|
|
/* init instantiation parameters */
|
|
|
|
s->sec_strength = sec_strength_bits;
|
|
s->requests_left = HMAC_DRBG_MAX_REQUESTS;
|
|
s->entropy_fn = entropy_fn;
|
|
*state = s;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/* sha256_hmac_drbg_free
|
|
*
|
|
* This routine frees a SHA-256 HMAC_DRBG internal state.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns DRBG_BAD_PARAMETER if inappropriate NULL pointers are passed.
|
|
*/
|
|
|
|
static void
|
|
sha256_hmac_drbg_free(
|
|
SHA256_HMAC_DRBG_STATE *s)
|
|
{
|
|
if (s->hmac_ctx)
|
|
{
|
|
(void) ntru_crypto_hmac_destroy_ctx(s->hmac_ctx);
|
|
}
|
|
|
|
memset(s->V, 0, sizeof(s->V));
|
|
s->sec_strength = 0;
|
|
s->requests_left = 0;
|
|
s->entropy_fn = NULL;
|
|
FREE(s);
|
|
}
|
|
|
|
|
|
/* sha256_hmac_drbg_reseed
|
|
*
|
|
* This function reseeds an instantiated SHA256_HMAC DRBG.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns HMAC errors if they occur.
|
|
*/
|
|
|
|
static uint32_t
|
|
sha256_hmac_drbg_reseed(
|
|
SHA256_HMAC_DRBG_STATE *s)
|
|
{
|
|
uint8_t entropy[HMAC_DRBG_MAX_ENTROPY_NONCE_BYTES];
|
|
uint32_t entropy_bytes;
|
|
uint32_t min_bytes_of_entropy;
|
|
uint8_t num_bytes_per_byte_of_entropy;
|
|
uint8_t key[32]; /* array of md_len size for sha256_hmac_drbg_update() */
|
|
uint32_t result;
|
|
uint32_t i;
|
|
|
|
/* calculate number of bytes needed for the entropy input
|
|
* for a SHA256_HMAC_DRBG, and get them from the entropy source
|
|
*/
|
|
|
|
if (s->entropy_fn(GET_NUM_BYTES_PER_BYTE_OF_ENTROPY,
|
|
&num_bytes_per_byte_of_entropy) == 0)
|
|
{
|
|
DRBG_RET(DRBG_ENTROPY_FAIL);
|
|
}
|
|
|
|
if ((num_bytes_per_byte_of_entropy == 0) ||
|
|
(num_bytes_per_byte_of_entropy >
|
|
DRBG_MAX_BYTES_PER_BYTE_OF_ENTROPY))
|
|
{
|
|
DRBG_RET(DRBG_ENTROPY_FAIL);
|
|
}
|
|
|
|
/* note: factor of 2 here is probably unnecessary, but ensures quantum
|
|
* resistance even if internal state is leaked prior to reseed */
|
|
min_bytes_of_entropy = (2 * s->sec_strength) / 8;
|
|
entropy_bytes = min_bytes_of_entropy * num_bytes_per_byte_of_entropy;
|
|
|
|
for (i = 0; i < entropy_bytes; i++)
|
|
{
|
|
if (s->entropy_fn(GET_BYTE_OF_ENTROPY, entropy+i) == 0)
|
|
{
|
|
DRBG_RET(DRBG_ENTROPY_FAIL);
|
|
}
|
|
}
|
|
|
|
/* update internal state */
|
|
|
|
if ((result = sha256_hmac_drbg_update(s, key, sizeof(key),
|
|
entropy, entropy_bytes, NULL, 0)) != DRBG_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
/* reset request counter */
|
|
|
|
s->requests_left = HMAC_DRBG_MAX_REQUESTS;
|
|
DRBG_RET(DRBG_OK);
|
|
}
|
|
|
|
|
|
/* sha256_hmac_drbg_generate
|
|
*
|
|
* This routine generates pseudorandom bytes from a SHA256_HMAC DRBG.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns DRBG_BAD_LENGTH if too many bytes are requested or the requested
|
|
* security strength is too large.
|
|
* Returns HMAC errors if they occur.
|
|
*/
|
|
|
|
static uint32_t
|
|
sha256_hmac_drbg_generate(
|
|
SHA256_HMAC_DRBG_STATE *s,
|
|
uint32_t sec_strength_bits,
|
|
uint32_t num_bytes,
|
|
uint8_t *out)
|
|
{
|
|
uint8_t key[32]; /* array of md_len size for sha256_hmac_drbg_update() */
|
|
uint32_t result;
|
|
|
|
/* check if number of bytes requested exceeds the maximum allowed */
|
|
|
|
if (num_bytes > HMAC_DRBG_MAX_BYTES_PER_REQUEST)
|
|
{
|
|
DRBG_RET(DRBG_BAD_LENGTH);
|
|
}
|
|
|
|
/* check if drbg has adequate security strength */
|
|
|
|
if (sec_strength_bits > s->sec_strength)
|
|
{
|
|
DRBG_RET(DRBG_BAD_LENGTH);
|
|
}
|
|
|
|
/* check if max requests have been exceeded */
|
|
|
|
if (s->requests_left == 0)
|
|
{
|
|
if ((result = sha256_hmac_drbg_reseed(s)) != DRBG_OK)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/* generate pseudorandom bytes */
|
|
|
|
while (num_bytes > 0)
|
|
{
|
|
/* generate md_len bytes = V = HMAC(K, V) */
|
|
|
|
if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V,
|
|
sizeof(key))) != NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ((result = ntru_crypto_hmac_final(s->hmac_ctx, s->V)) !=
|
|
NTRU_CRYPTO_HMAC_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
/* copy generated bytes to output buffer */
|
|
|
|
if (num_bytes < sizeof(key))
|
|
{
|
|
memcpy(out, s->V, num_bytes);
|
|
num_bytes = 0;
|
|
}
|
|
else
|
|
{
|
|
memcpy(out, s->V, sizeof(key));
|
|
out += sizeof(key);
|
|
num_bytes -= sizeof(key);
|
|
}
|
|
}
|
|
|
|
/* update internal state */
|
|
|
|
if ((result = sha256_hmac_drbg_update(s, key, sizeof(key),
|
|
NULL, 0, NULL, 0)) != DRBG_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
s->requests_left--;
|
|
|
|
DRBG_RET(DRBG_OK);
|
|
}
|
|
|
|
|
|
/******************
|
|
* DRBG functions *
|
|
******************/
|
|
|
|
/* drbg_get_new_drbg
|
|
*
|
|
* This routine finds an uninstantiated drbg state and returns a pointer to it.
|
|
*
|
|
* Returns a pointer to an uninstantiated drbg state if found.
|
|
* Returns NULL if all drbg states are instantiated.
|
|
*/
|
|
|
|
static DRBG_STATE *
|
|
drbg_get_new_drbg()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < DRBG_MAX_INSTANTIATIONS; i++)
|
|
{
|
|
if (drbg_state[i].state == NULL)
|
|
{
|
|
return drbg_state+i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* drbg_get_drbg
|
|
*
|
|
* This routine finds an instantiated drbg state given its handle, and returns
|
|
* a pointer to it.
|
|
*
|
|
* Returns a pointer to the drbg state if found.
|
|
* Returns NULL if the drbg state is not found.
|
|
*/
|
|
|
|
static DRBG_STATE *
|
|
drbg_get_drbg(
|
|
DRBG_HANDLE handle) /* in/out - drbg handle */
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < DRBG_MAX_INSTANTIATIONS; i++)
|
|
{
|
|
if ((drbg_state[i].handle == handle) && drbg_state[i].state)
|
|
{
|
|
return drbg_state+i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* drbg_get_new_handle
|
|
*
|
|
* This routine gets a new, unique 32-bit handle.
|
|
*
|
|
* Returns the new DRBG handle.
|
|
*/
|
|
|
|
static DRBG_HANDLE
|
|
drbg_get_new_handle(void)
|
|
{
|
|
DRBG_HANDLE h = 0;
|
|
|
|
/* ensure the new handle is unique:
|
|
* if it already exists, increment it
|
|
*/
|
|
|
|
while (drbg_get_drbg(h) != NULL)
|
|
{
|
|
++h;
|
|
}
|
|
|
|
return h;
|
|
}
|
|
|
|
|
|
/********************
|
|
* Public functions *
|
|
********************/
|
|
|
|
/* ntru_crypto_drbg_instantiate
|
|
*
|
|
* This routine instantiates a drbg with the requested security strength.
|
|
* See ANS X9.82: Part 3-2007. This routine currently returns an instance
|
|
* of SHA-256 HMAC_DRBG for all requested security strengths.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if an argument pointer is NULL.
|
|
* Returns DRBG_ERROR_BASE + DRBG_BAD_LENGTH if the security strength requested
|
|
* or the personalization string is too large.
|
|
* Returns DRBG_ERROR_BASE + DRBG_NOT_AVAILABLE if there are no instantiation
|
|
* slots available
|
|
* Returns DRBG_ERROR_BASE + DRBG_OUT_OF_MEMORY if the internal state cannot be
|
|
* allocated from the heap.
|
|
*/
|
|
|
|
uint32_t
|
|
ntru_crypto_drbg_instantiate(
|
|
uint32_t sec_strength_bits, /* in - requested sec strength in bits */
|
|
uint8_t const *pers_str, /* in - ptr to personalization string */
|
|
uint32_t pers_str_bytes, /* in - no. personalization str bytes */
|
|
ENTROPY_FN entropy_fn, /* in - pointer to entropy function */
|
|
DRBG_HANDLE *handle) /* out - address for drbg handle */
|
|
{
|
|
DRBG_STATE *drbg = NULL;
|
|
SHA256_HMAC_DRBG_STATE *state = NULL;
|
|
uint32_t result;
|
|
|
|
/* check arguments */
|
|
|
|
if ((!pers_str && pers_str_bytes) || !entropy_fn || !handle)
|
|
{
|
|
DRBG_RET(DRBG_BAD_PARAMETER);
|
|
}
|
|
|
|
if (sec_strength_bits > DRBG_MAX_SEC_STRENGTH_BITS)
|
|
{
|
|
DRBG_RET(DRBG_BAD_LENGTH);
|
|
}
|
|
|
|
if (pers_str && (pers_str_bytes == 0))
|
|
{
|
|
pers_str = NULL;
|
|
}
|
|
|
|
/* set security strength */
|
|
|
|
if (sec_strength_bits <= 112)
|
|
{
|
|
sec_strength_bits = 112;
|
|
}
|
|
else if (sec_strength_bits <= 128)
|
|
{
|
|
sec_strength_bits = 128;
|
|
}
|
|
else if (sec_strength_bits <= 192)
|
|
{
|
|
sec_strength_bits = 192;
|
|
}
|
|
else
|
|
{
|
|
sec_strength_bits = 256;
|
|
}
|
|
|
|
/* get an uninstantiated drbg */
|
|
|
|
if ((drbg = drbg_get_new_drbg()) == NULL)
|
|
{
|
|
DRBG_RET(DRBG_NOT_AVAILABLE);
|
|
}
|
|
|
|
/* init entropy function */
|
|
|
|
if (entropy_fn(INIT, NULL) == 0)
|
|
{
|
|
DRBG_RET(DRBG_ENTROPY_FAIL);
|
|
}
|
|
|
|
/* instantiate a SHA-256 HMAC_DRBG */
|
|
|
|
if ((result = sha256_hmac_drbg_instantiate(sec_strength_bits,
|
|
pers_str, pers_str_bytes,
|
|
entropy_fn,
|
|
&state)) != DRBG_OK)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
/* init drbg state */
|
|
|
|
drbg->handle = drbg_get_new_handle();
|
|
drbg->type = SHA256_HMAC_DRBG;
|
|
drbg->state = state;
|
|
|
|
/* return drbg handle */
|
|
|
|
*handle = drbg->handle;
|
|
DRBG_RET(DRBG_OK);
|
|
}
|
|
|
|
|
|
/* ntru_crypto_drbg_external_instantiate
|
|
*
|
|
* This routine instruments an external DRBG so that ntru_crypto routines
|
|
* can call it. randombytesfn must be of type
|
|
* uint32_t (randombytesfn*)(unsigned char *out, unsigned long long num_bytes);
|
|
* and should return DRBG_OK on success.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns DRBG_ERROR_BASE + DRBG_NOT_AVAILABLE if there are no instantiation
|
|
* slots available
|
|
* Returns DRBG_ERROR_BASE + DRBG_OUT_OF_MEMORY if the internal state cannot be
|
|
* allocated from the heap.
|
|
*/
|
|
|
|
uint32_t
|
|
ntru_crypto_drbg_external_instantiate(
|
|
RANDOM_BYTES_FN randombytesfn, /* in - pointer to random bytes function */
|
|
DRBG_HANDLE *handle) /* out - address for drbg handle */
|
|
{
|
|
DRBG_STATE *drbg = NULL;
|
|
EXTERNAL_DRBG_STATE *state = NULL;
|
|
|
|
if (!randombytesfn || !handle)
|
|
{
|
|
DRBG_RET(DRBG_BAD_PARAMETER);
|
|
}
|
|
|
|
/* get an uninstantiated drbg */
|
|
|
|
if ((drbg = drbg_get_new_drbg()) == NULL)
|
|
{
|
|
DRBG_RET(DRBG_NOT_AVAILABLE);
|
|
}
|
|
|
|
/* instantiate an External DRBG */
|
|
|
|
state = (EXTERNAL_DRBG_STATE*) MALLOC(sizeof(EXTERNAL_DRBG_STATE));
|
|
if (state == NULL)
|
|
{
|
|
DRBG_RET(DRBG_OUT_OF_MEMORY);
|
|
}
|
|
|
|
state->randombytesfn = randombytesfn;
|
|
|
|
/* init drbg state */
|
|
|
|
drbg->handle = drbg_get_new_handle();
|
|
drbg->type = EXTERNAL_DRBG;
|
|
drbg->state = state;
|
|
|
|
/* return drbg handle */
|
|
|
|
*handle = drbg->handle;
|
|
|
|
DRBG_RET(DRBG_OK);
|
|
}
|
|
|
|
/* ntru_crypto_drbg_uninstantiate
|
|
*
|
|
* This routine frees a drbg given its handle.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if handle is not valid.
|
|
*/
|
|
|
|
uint32_t
|
|
ntru_crypto_drbg_uninstantiate(
|
|
DRBG_HANDLE handle) /* in - drbg handle */
|
|
{
|
|
DRBG_STATE *drbg = NULL;
|
|
|
|
/* find the instantiated drbg */
|
|
|
|
if ((drbg = drbg_get_drbg(handle)) == NULL)
|
|
{
|
|
DRBG_RET(DRBG_BAD_PARAMETER);
|
|
}
|
|
|
|
/* zero and free drbg state */
|
|
|
|
if (drbg->state)
|
|
{
|
|
switch (drbg->type)
|
|
{
|
|
case EXTERNAL_DRBG:
|
|
FREE(drbg->state);
|
|
break;
|
|
case SHA256_HMAC_DRBG:
|
|
sha256_hmac_drbg_free((SHA256_HMAC_DRBG_STATE *)drbg->state);
|
|
break;
|
|
}
|
|
drbg->state = NULL;
|
|
}
|
|
|
|
drbg->handle = 0;
|
|
DRBG_RET(DRBG_OK);
|
|
}
|
|
|
|
|
|
/* ntru_crypto_drbg_reseed
|
|
*
|
|
* This routine reseeds an instantiated drbg.
|
|
* See ANS X9.82: Part 3-2007.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if handle is not valid.
|
|
* Returns HMAC errors if they occur.
|
|
*/
|
|
|
|
uint32_t
|
|
ntru_crypto_drbg_reseed(
|
|
DRBG_HANDLE handle) /* in - drbg handle */
|
|
{
|
|
DRBG_STATE *drbg = NULL;
|
|
|
|
/* find the instantiated drbg */
|
|
|
|
if ((drbg = drbg_get_drbg(handle)) == NULL)
|
|
{
|
|
DRBG_RET(DRBG_BAD_PARAMETER);
|
|
}
|
|
|
|
if (drbg->type == EXTERNAL_DRBG)
|
|
{
|
|
DRBG_RET(DRBG_BAD_PARAMETER);
|
|
}
|
|
|
|
/* reseed the SHA-256 HMAC_DRBG */
|
|
|
|
return sha256_hmac_drbg_reseed((SHA256_HMAC_DRBG_STATE *)drbg->state);
|
|
}
|
|
|
|
|
|
/* ntru_crypto_drbg_generate
|
|
*
|
|
* This routine generates pseudorandom bytes using an instantiated drbg.
|
|
* If the maximum number of requests has been reached, reseeding will occur.
|
|
* See ANS X9.82: Part 3-2007.
|
|
*
|
|
* Returns DRBG_OK if successful.
|
|
* Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if handle is not valid or if
|
|
* an argument pointer is NULL.
|
|
* Returns DRBG_ERROR_BASE + DRBG_BAD_LENGTH if the security strength requested
|
|
* is too large or the number of bytes requested is zero or too large.
|
|
* Returns HMAC errors if they occur.
|
|
*/
|
|
|
|
uint32_t
|
|
ntru_crypto_drbg_generate(
|
|
DRBG_HANDLE handle, /* in - drbg handle */
|
|
uint32_t sec_strength_bits, /* in - requested sec strength in bits */
|
|
uint32_t num_bytes, /* in - number of octets to generate */
|
|
uint8_t *out) /* out - address for generated octets */
|
|
{
|
|
DRBG_STATE *drbg = NULL;
|
|
|
|
/* find the instantiated drbg */
|
|
|
|
if ((drbg = drbg_get_drbg(handle)) == NULL)
|
|
{
|
|
DRBG_RET(DRBG_BAD_PARAMETER);
|
|
}
|
|
|
|
/* check arguments */
|
|
|
|
if (!out)
|
|
{
|
|
DRBG_RET(DRBG_BAD_PARAMETER);
|
|
}
|
|
|
|
if (num_bytes == 0)
|
|
{
|
|
DRBG_RET(DRBG_BAD_LENGTH);
|
|
}
|
|
|
|
/* generate pseudorandom output from the SHA256_HMAC_DRBG */
|
|
|
|
switch (drbg->type)
|
|
{
|
|
case EXTERNAL_DRBG:
|
|
return ((EXTERNAL_DRBG_STATE *)drbg->state)->randombytesfn(out,
|
|
num_bytes);
|
|
case SHA256_HMAC_DRBG:
|
|
return sha256_hmac_drbg_generate(
|
|
(SHA256_HMAC_DRBG_STATE *)drbg->state,
|
|
sec_strength_bits, num_bytes, out);
|
|
default:
|
|
DRBG_RET(DRBG_BAD_PARAMETER);
|
|
}
|
|
}
|
|
|