/* random-fips.c - FIPS style random number generator
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
*/
/*
The core of this deterministic random number generator is
implemented according to the document "NIST-Recommended Random
Number Generator Based on ANSI X9.31 Appendix A.2.4 Using the 3-Key
Triple DES and AES Algorithms" (2005-01-31). This implementation
uses the AES variant.
There are 3 random context which map to the different levels of
random quality:
Generator Seed and Key Kernel entropy (init/reseed)
------------------------------------------------------------
GCRY_VERY_STRONG_RANDOM /dev/random 256/128 bits
GCRY_STRONG_RANDOM /dev/random 256/128 bits
gcry_create_nonce GCRY_STRONG_RANDOM n/a
All random generators return their data in 128 bit blocks. If the
caller requested less bits, the extra bits are not used. The key
for each generator is only set once at the first time a generator
is used. The seed value is set with the key and again after 1000
(SEED_TTL) output blocks; the re-seeding is disabled in test mode.
The GCRY_VERY_STRONG_RANDOM and GCRY_STRONG_RANDOM generators are
keyed and seeded from the /dev/random device. Thus these
generators may block until the kernel has collected enough entropy.
The gcry_create_nonce generator is keyed and seeded from the
GCRY_STRONG_RANDOM generator. It may also block if the
GCRY_STRONG_RANDOM generator has not yet been used before and thus
gets initialized on the first use by gcry_create_nonce. This
special treatment is justified by the weaker requirements for a
nonce generator and to save precious kernel entropy for use by the
real random generators.
*/
#include
#include
#include
#include
#include
#include
#ifdef HAVE_GETTIMEOFDAY
#include
#endif
#include "g10lib.h"
#include "random.h"
#include "rand-internal.h"
#include "ath.h"
#include
/* This is the lock we use to serialize access to this RNG. The extra
integer variable is only used to check the locking state; that is,
it is not meant to be thread-safe but merely as a failsafe feature
to assert proper locking. */
static ath_mutex_t fips_rng_lock = ATH_MUTEX_INITIALIZER;
static int fips_rng_is_locked;
/* The required size for the temporary buffer of the x931_aes_driver
function and the buffer itself which will be allocated in secure
memory. This needs to be global variable for proper initialization
and to allow shutting down the RNG without leaking memory. May
only be used while holding the FIPS_RNG_LOCK.
This variable is also used to avoid duplicate initialization. */
#define TEMPVALUE_FOR_X931_AES_DRIVER_SIZE 48
static unsigned char *tempvalue_for_x931_aes_driver;
/* After having retrieved this number of blocks from the RNG, we want
to do a reseeding. */
#define SEED_TTL 1000
/* The length of the key we use: 16 bytes (128 bit) for AES128. */
#define X931_AES_KEYLEN 16
/* A global buffer used to communicate between the x931_generate_key
and x931_generate_seed functions and the entropy_collect_cb
function. It may only be used by these functions. */
static unsigned char *entropy_collect_buffer; /* Buffer. */
static size_t entropy_collect_buffer_len; /* Used length. */
static size_t entropy_collect_buffer_size; /* Allocated length. */
/* This random context type is used to track properties of one random
generator. Thee context are usually allocated in secure memory so
that the seed value is well protected. There are a couble of guard
fields to help detecting applications accidently overwriting parts
of the memory. */
struct rng_context
{
unsigned char guard_0[1];
/* The handle of the cipher used by the RNG. If this one is not
NULL a cipher handle along with a random key has been
established. */
gcry_cipher_hd_t cipher_hd;
/* If this flag is true, the SEED_V buffer below carries a valid
seed. */
int is_seeded:1;
/* The very first block generated is used to compare the result
against the last result. This flag indicates that such a block
is available. */
int compare_value_valid:1;
/* A counter used to trigger re-seeding. */
unsigned int use_counter;
unsigned char guard_1[1];
/* The buffer containing the seed value V. */
unsigned char seed_V[16];
unsigned char guard_2[1];
/* The last result from the x931_aes fucntion. Only valid if
compare_value_valid is set. */
unsigned char compare_value[16];
unsigned char guard_3[1];
/* The external test may want to suppress the duplicate bock check.
This is done if the this flag is set. */
unsigned char test_no_dup_check;
/* To implement a KAT we need to provide a know DT value. To
accomplish this the x931_get_dt function checks whether this
field is not NULL and then uses the 16 bytes at this address for
the DT value. However the last 4 bytes are replaced by the
value of field TEST_DT_COUNTER which will be incremented after
each invocation of x931_get_dt. We use a pointer and not a buffer
because there is no need to put this value into secure memory. */
const unsigned char *test_dt_ptr;
u32 test_dt_counter;
/* We need to keep track of the process which did the initialization
so that we can detect a fork. The volatile modifier is required
so that the compiler does not optimize it away in case the getpid
function is badly attributed. */
pid_t key_init_pid;
pid_t seed_init_pid;
};
typedef struct rng_context *rng_context_t;
/* The random context used for the nonce generator. May only be used
while holding the FIPS_RNG_LOCK. */
static rng_context_t nonce_context;
/* The random context used for the standard random generator. May
only be used while holding the FIPS_RNG_LOCK. */
static rng_context_t std_rng_context;
/* The random context used for the very strong random generator. May
only be used while holding the FIPS_RNG_LOCK. */
static rng_context_t strong_rng_context;
/* --- Local prototypes --- */
static void x931_reseed (rng_context_t rng_ctx);
static void get_random (void *buffer, size_t length, rng_context_t rng_ctx);
/* --- Functions --- */
/* Basic initialization is required to initialize mutexes and
do a few checks on the implementation. */
static void
basic_initialization (void)
{
static int initialized;
int my_errno;
if (!initialized)
return;
initialized = 1;
my_errno = ath_mutex_init (&fips_rng_lock);
if (my_errno)
log_fatal ("failed to create the RNG lock: %s\n", strerror (my_errno));
fips_rng_is_locked = 0;
/* Make sure that we are still using the values we have
traditionally used for the random levels. */
gcry_assert (GCRY_WEAK_RANDOM == 0
&& GCRY_STRONG_RANDOM == 1
&& GCRY_VERY_STRONG_RANDOM == 2);
}
/* Acquire the fips_rng_lock. */
static void
lock_rng (void)
{
int my_errno;
my_errno = ath_mutex_lock (&fips_rng_lock);
if (my_errno)
log_fatal ("failed to acquire the RNG lock: %s\n", strerror (my_errno));
fips_rng_is_locked = 1;
}
/* Release the fips_rng_lock. */
static void
unlock_rng (void)
{
int my_errno;
fips_rng_is_locked = 0;
my_errno = ath_mutex_unlock (&fips_rng_lock);
if (my_errno)
log_fatal ("failed to release the RNG lock: %s\n", strerror (my_errno));
}
static void
setup_guards (rng_context_t rng_ctx)
{
/* Set the guards to some arbitrary values. */
rng_ctx->guard_0[0] = 17;
rng_ctx->guard_1[0] = 42;
rng_ctx->guard_2[0] = 137;
rng_ctx->guard_3[0] = 252;
}
static void
check_guards (rng_context_t rng_ctx)
{
if ( rng_ctx->guard_0[0] != 17
|| rng_ctx->guard_1[0] != 42
|| rng_ctx->guard_2[0] != 137
|| rng_ctx->guard_3[0] != 252 )
log_fatal ("memory corruption detected in RNG context %p\n", rng_ctx);
}
/* Get the DT vector for use with the core PRNG function. Buffer
needs to be provided by the caller with a size of at least LENGTH
bytes. RNG_CTX needs to be passed to allow for a KAT. The 16 byte
timestamp we construct is made up the real time and three counters:
Buffer: 00112233445566778899AABBCCDDEEFF
!--+---!!-+-!!+!!--+---!!--+---!
seconds ---------/ | | | |
microseconds -----------/ | | |
counter2 -------------------/ | |
counter1 ------------------------/ |
counter0 --------------------------------/
Counter 2 is just 12 bits wide and used to track fractions of
milliseconds whereas counters 1 and 0 are combined to a free
running 64 bit counter. */
static void
x931_get_dt (unsigned char *buffer, size_t length, rng_context_t rng_ctx)
{
gcry_assert (length == 16); /* This length is required for use with AES. */
gcry_assert (fips_rng_is_locked);
/* If the random context indicates that a test DT should be used,
take the DT value from the context. For safety reasons we do
this only if the context is not one of the regular contexts. */
if (rng_ctx->test_dt_ptr
&& rng_ctx != nonce_context
&& rng_ctx != std_rng_context
&& rng_ctx != strong_rng_context)
{
memcpy (buffer, rng_ctx->test_dt_ptr, 16);
buffer[12] = (rng_ctx->test_dt_counter >> 24);
buffer[13] = (rng_ctx->test_dt_counter >> 16);
buffer[14] = (rng_ctx->test_dt_counter >> 8);
buffer[15] = rng_ctx->test_dt_counter;
rng_ctx->test_dt_counter++;
return;
}
#if HAVE_GETTIMEOFDAY
{
static u32 last_sec, last_usec;
static u32 counter1, counter0;
static u16 counter2;
unsigned int usec;
struct timeval tv;
if (!last_sec)
{
/* This is the very first time we are called: Set the counters
to an not so easy predictable value to avoid always
starting at 0. Not really needed but it doesn't harm. */
counter1 = (u32)getpid ();
#ifndef HAVE_W32_SYSTEM
counter0 = (u32)getppid ();
#endif
}
if (gettimeofday (&tv, NULL))
log_fatal ("gettimeofday() failed: %s\n", strerror (errno));
/* The microseconds part is always less than 1 millon (0x0f4240).
Thus we don't care about the MSB and in addition shift it to
the left by 4 bits. */
usec = tv.tv_usec;
usec <<= 4;
/* If we got the same time as by the last invocation, bump up
counter2 and save the time for the next invocation. */
if (tv.tv_sec == last_sec && usec == last_usec)
{
counter2++;
counter2 &= 0x0fff;
}
else
{
counter2 = 0;
last_sec = tv.tv_sec;
last_usec = usec;
}
/* Fill the buffer with the timestamp. */
buffer[0] = ((tv.tv_sec >> 24) & 0xff);
buffer[1] = ((tv.tv_sec >> 16) & 0xff);
buffer[2] = ((tv.tv_sec >> 8) & 0xff);
buffer[3] = (tv.tv_sec & 0xff);
buffer[4] = ((usec >> 16) & 0xff);
buffer[5] = ((usec >> 8) & 0xff);
buffer[6] = ((usec & 0xf0) | ((counter2 >> 8) & 0x0f));
buffer[7] = (counter2 & 0xff);
/* Add the free running counter. */
buffer[8] = ((counter1 >> 24) & 0xff);
buffer[9] = ((counter1 >> 16) & 0xff);
buffer[10] = ((counter1 >> 8) & 0xff);
buffer[11] = ((counter1) & 0xff);
buffer[12] = ((counter0 >> 24) & 0xff);
buffer[13] = ((counter0 >> 16) & 0xff);
buffer[14] = ((counter0 >> 8) & 0xff);
buffer[15] = ((counter0) & 0xff);
/* Bump up that counter. */
if (!++counter0)
++counter1;
}
#else
log_fatal ("gettimeofday() not available on this system\n");
#endif
/* log_printhex ("x931_get_dt: ", buffer, 16); */
}
/* XOR the buffers A and B which are each of LENGTH bytes and store
the result at R. R needs to be provided by the caller with a size
of at least LENGTH bytes. */
static void
xor_buffer (unsigned char *r,
const unsigned char *a, const unsigned char *b, size_t length)
{
for ( ; length; length--, a++, b++, r++)
*r = (*a ^ *b);
}
/* Encrypt LENGTH bytes of INPUT to OUTPUT using KEY. LENGTH
needs to be 16. */
static void
encrypt_aes (gcry_cipher_hd_t key,
unsigned char *output, const unsigned char *input, size_t length)
{
gpg_error_t err;
gcry_assert (length == 16);
err = gcry_cipher_encrypt (key, output, length, input, length);
if (err)
log_fatal ("AES encryption in RNG failed: %s\n", gcry_strerror (err));
}
/* The core ANSI X9.31, Appendix A.2.4 function using AES. The caller
needs to pass a 16 byte buffer for the result, the 16 byte
datetime_DT value and the 16 byte seed value V. The caller also
needs to pass an appropriate KEY and make sure to pass a valid
seed_V. The caller also needs to provide two 16 bytes buffer for
intermediate results, they may be reused by the caller later.
On return the result is stored at RESULT_R and the SEED_V is
updated. May only be used while holding the lock. */
static void
x931_aes (unsigned char result_R[16],
unsigned char datetime_DT[16], unsigned char seed_V[16],
gcry_cipher_hd_t key,
unsigned char intermediate_I[16], unsigned char temp_xor[16])
{
/* Let ede*X(Y) represent the AES encryption of Y under the key *X.
Let V be a 128-bit seed value which is also kept secret, and XOR
be the exclusive-or operator. Let DT be a date/time vector which
is updated on each iteration. I is a intermediate value.
I = ede*K(DT) */
encrypt_aes (key, intermediate_I, datetime_DT, 16);
/* R = ede*K(I XOR V) */
xor_buffer (temp_xor, intermediate_I, seed_V, 16);
encrypt_aes (key, result_R, temp_xor, 16);
/* V = ede*K(R XOR I). */
xor_buffer (temp_xor, result_R, intermediate_I, 16);
encrypt_aes (key, seed_V, temp_xor, 16);
/* Zero out temporary values. */
wipememory (intermediate_I, 16);
wipememory (temp_xor, 16);
}
/* The high level driver to x931_aes. This one does the required
tests and calls the core function until the entire buffer has been
filled. OUTPUT is a caller provided buffer of LENGTH bytes to
receive the random, RNG_CTX is the context of the RNG. The context
must be properly initialized. Returns 0 on success. */
static int
x931_aes_driver (unsigned char *output, size_t length, rng_context_t rng_ctx)
{
unsigned char datetime_DT[16];
unsigned char *intermediate_I, *temp_buffer, *result_buffer;
size_t nbytes;
gcry_assert (fips_rng_is_locked);
gcry_assert (rng_ctx->cipher_hd);
gcry_assert (rng_ctx->is_seeded);
gcry_assert (tempvalue_for_x931_aes_driver);
gcry_assert (TEMPVALUE_FOR_X931_AES_DRIVER_SIZE == 48);
intermediate_I = tempvalue_for_x931_aes_driver;
temp_buffer = tempvalue_for_x931_aes_driver + 16;
result_buffer = tempvalue_for_x931_aes_driver + 32;
while (length)
{
/* Unless we are running with a test context, we require a new
seed after some time. */
if (!rng_ctx->test_dt_ptr && rng_ctx->use_counter > SEED_TTL)
{
x931_reseed (rng_ctx);
rng_ctx->use_counter = 0;
}
/* Due to the design of the RNG, we always receive 16 bytes (128
bit) of random even if we require less. The extra bytes
returned are not used. Intheory we could save them for the
next invocation, but that would make the control flow harder
to read. */
nbytes = length < 16? length : 16;
x931_get_dt (datetime_DT, 16, rng_ctx);
x931_aes (result_buffer,
datetime_DT, rng_ctx->seed_V, rng_ctx->cipher_hd,
intermediate_I, temp_buffer);
rng_ctx->use_counter++;
if (rng_ctx->test_no_dup_check
&& rng_ctx->test_dt_ptr
&& rng_ctx != nonce_context
&& rng_ctx != std_rng_context
&& rng_ctx != strong_rng_context)
{
/* This is a test context which does not want the duplicate
block check. */
}
else
{
/* Do a basic check on the output to avoid a stuck generator. */
if (!rng_ctx->compare_value_valid)
{
/* First time used, only save the result. */
memcpy (rng_ctx->compare_value, result_buffer, 16);
rng_ctx->compare_value_valid = 1;
continue;
}
if (!memcmp (rng_ctx->compare_value, result_buffer, 16))
{
/* Ooops, we received the same 128 bit block - that should
in theory never happen. The FIPS requirement says that
we need to put ourself into the error state in such
case. */
fips_signal_error ("duplicate 128 bit block returned by RNG");
return -1;
}
memcpy (rng_ctx->compare_value, result_buffer, 16);
}
/* Append to outbut. */
memcpy (output, result_buffer, nbytes);
wipememory (result_buffer, 16);
output += nbytes;
length -= nbytes;
}
return 0;
}
/* Callback for x931_generate_key. Note that this callback uses the
global ENTROPY_COLLECT_BUFFER which has been setup by get_entropy.
ORIGIN is not used but required due to the design of entropy
gathering module. */
static void
entropy_collect_cb (const void *buffer, size_t length,
enum random_origins origin)
{
const unsigned char *p = buffer;
(void)origin;
gcry_assert (fips_rng_is_locked);
gcry_assert (entropy_collect_buffer);
/* Note that we need to protect against gatherers returning more
than the requested bytes (e.g. rndw32). */
while (length-- && entropy_collect_buffer_len < entropy_collect_buffer_size)
{
entropy_collect_buffer[entropy_collect_buffer_len++] ^= *p++;
}
}
/* Get NBYTES of entropy from the kernel device. The callers needs to
free the returned buffer. The function either succeeds or
terminates the process in case of a fatal error. */
static void *
get_entropy (size_t nbytes)
{
void *result;
int rc;
gcry_assert (!entropy_collect_buffer);
entropy_collect_buffer = gcry_xmalloc_secure (nbytes);
entropy_collect_buffer_size = nbytes;
entropy_collect_buffer_len = 0;
#if USE_RNDLINUX
rc = _gcry_rndlinux_gather_random (entropy_collect_cb, 0,
X931_AES_KEYLEN,
GCRY_VERY_STRONG_RANDOM);
#elif USE_RNDW32
do
{
rc = _gcry_rndw32_gather_random (entropy_collect_cb, 0,
X931_AES_KEYLEN,
GCRY_VERY_STRONG_RANDOM);
}
while (rc >= 0 && entropy_collect_buffer_len < entropy_collect_buffer_size);
#else
rc = -1;
#endif
if (rc < 0 || entropy_collect_buffer_len != entropy_collect_buffer_size)
{
gcry_free (entropy_collect_buffer);
entropy_collect_buffer = NULL;
log_fatal ("error getting entropy data\n");
}
result = entropy_collect_buffer;
entropy_collect_buffer = NULL;
return result;
}
/* Generate a key for use with x931_aes. The function returns a
handle to the cipher context readily prepared for ECB encryption.
If FOR_NONCE is true, the key is retrieved by readong random from
the standard generator. On error NULL is returned. */
static gcry_cipher_hd_t
x931_generate_key (int for_nonce)
{
gcry_cipher_hd_t hd;
gpg_error_t err;
void *buffer;
gcry_assert (fips_rng_is_locked);
/* Allocate a cipher context. */
err = gcry_cipher_open (&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
GCRY_CIPHER_SECURE);
if (err)
{
log_error ("error creating cipher context for RNG: %s\n",
gcry_strerror (err));
return NULL;
}
/* Get a key from the standard RNG or from the entropy source. */
if (for_nonce)
{
buffer = gcry_xmalloc (X931_AES_KEYLEN);
get_random (buffer, X931_AES_KEYLEN, std_rng_context);
}
else
{
buffer = get_entropy (X931_AES_KEYLEN);
}
/* Set the key and delete the buffer because the key is now part of
the cipher context. */
err = gcry_cipher_setkey (hd, buffer, X931_AES_KEYLEN);
wipememory (buffer, X931_AES_KEYLEN);
gcry_free (buffer);
if (err)
{
log_error ("error creating key for RNG: %s\n", gcry_strerror (err));
gcry_cipher_close (hd);
return NULL;
}
return hd;
}
/* Generate a key for use with x931_aes. The function copies a seed
of LENGTH bytes into SEED_BUFFER. LENGTH needs to by given as 16. */
static void
x931_generate_seed (unsigned char *seed_buffer, size_t length)
{
void *buffer;
gcry_assert (fips_rng_is_locked);
gcry_assert (length == 16);
buffer = get_entropy (X931_AES_KEYLEN);
memcpy (seed_buffer, buffer, X931_AES_KEYLEN);
wipememory (buffer, X931_AES_KEYLEN);
gcry_free (buffer);
}
/* Reseed a generator. This is also used for the initial seeding. */
static void
x931_reseed (rng_context_t rng_ctx)
{
gcry_assert (fips_rng_is_locked);
if (rng_ctx == nonce_context)
{
/* The nonce context is special. It will be seeded using the
standard random generator. */
get_random (rng_ctx->seed_V, 16, std_rng_context);
rng_ctx->is_seeded = 1;
rng_ctx->seed_init_pid = _getpid();
}
else
{
/* The other two generators are seeded from /dev/random. */
x931_generate_seed (rng_ctx->seed_V, 16);
rng_ctx->is_seeded = 1;
rng_ctx->seed_init_pid = _getpid();
}
}
/* Core random function. This is used for both nonce and random
generator. The actual RNG to be used depends on the random context
RNG_CTX passed. Note that this function is called with the RNG not
yet locked. */
static void
get_random (void *buffer, size_t length, rng_context_t rng_ctx)
{
gcry_assert (buffer);
gcry_assert (rng_ctx);
check_guards (rng_ctx);
/* Initialize the cipher handle and thus setup the key if needed. */
if (!rng_ctx->cipher_hd)
{
if (rng_ctx == nonce_context)
rng_ctx->cipher_hd = x931_generate_key (1);
else
rng_ctx->cipher_hd = x931_generate_key (0);
if (!rng_ctx->cipher_hd)
goto bailout;
rng_ctx->key_init_pid = _getpid();
}
/* Initialize the seed value if needed. */
if (!rng_ctx->is_seeded)
x931_reseed (rng_ctx);
if (rng_ctx->key_init_pid != _getpid()
|| rng_ctx->seed_init_pid != _getpid())
{
/* We are in a child of us. Because we have no way yet to do
proper re-initialization (including self-checks etc), the
only chance we have is to bail out. Obviusly a fork/exec
won't harm because the exec overwrites the old image. */
fips_signal_error ("fork without proper re-initialization "
"detected in RNG");
goto bailout;
}
if (x931_aes_driver (buffer, length, rng_ctx))
goto bailout;
check_guards (rng_ctx);
return;
bailout:
log_fatal ("severe error getting random\n");
/*NOTREACHED*/
}
/* --- Public Functions --- */
/* Initialize this random subsystem. If FULL is false, this function
merely calls the basic initialization of the module and does not do
anything more. Doing this is not really required but when running
in a threaded environment we might get a race condition
otherwise. */
void
_gcry_rngfips_initialize (int full)
{
basic_initialization ();
if (!full)
return;
/* Allocate temporary buffers. If that buffer already exists we
know that we are already initialized. */
lock_rng ();
if (!tempvalue_for_x931_aes_driver)
{
tempvalue_for_x931_aes_driver
= gcry_xmalloc_secure (TEMPVALUE_FOR_X931_AES_DRIVER_SIZE);
/* Allocate the random contexts. Note that we do not need to use
secure memory for the nonce context. */
nonce_context = gcry_xcalloc (1, sizeof *nonce_context);
setup_guards (nonce_context);
std_rng_context = gcry_xcalloc_secure (1, sizeof *std_rng_context);
setup_guards (std_rng_context);
strong_rng_context = gcry_xcalloc_secure (1, sizeof *strong_rng_context);
setup_guards (strong_rng_context);
}
else
{
/* Already initialized. Do some sanity checks. */
gcry_assert (!nonce_context->test_dt_ptr);
gcry_assert (!std_rng_context->test_dt_ptr);
gcry_assert (!strong_rng_context->test_dt_ptr);
check_guards (nonce_context);
check_guards (std_rng_context);
check_guards (strong_rng_context);
}
unlock_rng ();
}
/* Print some statistics about the RNG. */
void
_gcry_rngfips_dump_stats (void)
{
/* Not yet implemented. */
}
/* This function returns true if no real RNG is available or the
quality of the RNG has been degraded for test purposes. */
int
_gcry_rngfips_is_faked (void)
{
return 0; /* Faked random is not allowed. */
}
/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY
should be in the range of 0..100 to indicate the goodness of the
entropy added, or -1 for goodness not known. */
gcry_error_t
_gcry_rngfips_add_bytes (const void *buf, size_t buflen, int quality)
{
(void)buf;
(void)buflen;
(void)quality;
return 0; /* Not implemented. */
}
/* Public function to fill the buffer with LENGTH bytes of
cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is
here mapped to GCRY_STRONG_RANDOM, GCRY_STRONG_RANDOM is strong
enough for most usage, GCRY_VERY_STRONG_RANDOM is good for key
generation stuff but may be very slow. */
void
_gcry_rngfips_randomize (void *buffer, size_t length,
enum gcry_random_level level)
{
_gcry_rngfips_initialize (1); /* Auto-initialize if needed. */
lock_rng ();
if (level == GCRY_VERY_STRONG_RANDOM)
get_random (buffer, length, strong_rng_context);
else
get_random (buffer, length, std_rng_context);
unlock_rng ();
}
/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */
void
_gcry_rngfips_create_nonce (void *buffer, size_t length)
{
_gcry_rngfips_initialize (1); /* Auto-initialize if needed. */
lock_rng ();
get_random (buffer, length, nonce_context);
unlock_rng ();
}
/* Run a Know-Answer-Test using a dedicated test context. Note that
we can't use the samples from the NISR RNGVS document because they
don't take the requirement to throw away the first block and use
that for duplicate check in account. Thus we made up our own test
vectors. */
static gcry_err_code_t
selftest_kat (selftest_report_func_t report)
{
static struct
{
const unsigned char key[16];
const unsigned char dt[16];
const unsigned char v[16];
const unsigned char r[3][16];
} tv[] =
{
{ { 0xb9, 0xca, 0x7f, 0xd6, 0xa0, 0xf5, 0xd3, 0x42,
0x19, 0x6d, 0x84, 0x91, 0x76, 0x1c, 0x3b, 0xbe },
{ 0x48, 0xb2, 0x82, 0x98, 0x68, 0xc2, 0x80, 0x00,
0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x25, 0x00 },
{ 0x52, 0x17, 0x8d, 0x29, 0xa2, 0xd5, 0x84, 0x12,
0x9d, 0x89, 0x9a, 0x45, 0x82, 0x02, 0xf7, 0x77 },
{ { 0x42, 0x9c, 0x08, 0x3d, 0x82, 0xf4, 0x8a, 0x40,
0x66, 0xb5, 0x49, 0x27, 0xab, 0x42, 0xc7, 0xc3 },
{ 0x0e, 0xb7, 0x61, 0x3c, 0xfe, 0xb0, 0xbe, 0x73,
0xf7, 0x6e, 0x6d, 0x6f, 0x1d, 0xa3, 0x14, 0xfa },
{ 0xbb, 0x4b, 0xc1, 0x0e, 0xc5, 0xfb, 0xcd, 0x46,
0xbe, 0x28, 0x61, 0xe7, 0x03, 0x2b, 0x37, 0x7d } } },
{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ { 0xf7, 0x95, 0xbd, 0x4a, 0x52, 0xe2, 0x9e, 0xd7,
0x13, 0xd3, 0x13, 0xfa, 0x20, 0xe9, 0x8d, 0xbc },
{ 0xc8, 0xd1, 0xe5, 0x11, 0x59, 0x52, 0xf7, 0xfa,
0x37, 0x38, 0xb4, 0xc5, 0xce, 0xb2, 0xb0, 0x9a },
{ 0x0d, 0x9c, 0xc5, 0x0d, 0x16, 0xe1, 0xbc, 0xed,
0xcf, 0x60, 0x62, 0x09, 0x9d, 0x20, 0x83, 0x7e } } },
{ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
{ 0x80, 0x00, 0x81, 0x01, 0x82, 0x02, 0x83, 0x03,
0xa0, 0x20, 0xa1, 0x21, 0xa2, 0x22, 0xa3, 0x23 },
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
{ { 0x96, 0xed, 0xcc, 0xc3, 0xdd, 0x04, 0x7f, 0x75,
0x63, 0x19, 0x37, 0x6f, 0x15, 0x22, 0x57, 0x56 },
{ 0x7a, 0x14, 0x76, 0x77, 0x95, 0x17, 0x7e, 0xc8,
0x92, 0xe8, 0xdd, 0x15, 0xcb, 0x1f, 0xbc, 0xb1 },
{ 0x25, 0x3e, 0x2e, 0xa2, 0x41, 0x1b, 0xdd, 0xf5,
0x21, 0x48, 0x41, 0x71, 0xb3, 0x8d, 0x2f, 0x4c } } }
};
int tvidx, ridx;
rng_context_t test_ctx;
gpg_error_t err;
const char *errtxt = NULL;
unsigned char result[16];
gcry_assert (tempvalue_for_x931_aes_driver);
test_ctx = gcry_xcalloc (1, sizeof *test_ctx);
setup_guards (test_ctx);
lock_rng ();
for (tvidx=0; tvidx < DIM (tv); tvidx++)
{
/* Setup the key. */
err = gcry_cipher_open (&test_ctx->cipher_hd,
GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
GCRY_CIPHER_SECURE);
if (err)
{
errtxt = "error creating cipher context for RNG";
goto leave;
}
err = gcry_cipher_setkey (test_ctx->cipher_hd, tv[tvidx].key, 16);
if (err)
{
errtxt = "error setting key for RNG";
goto leave;
}
test_ctx->key_init_pid = _getpid();
/* Setup the seed. */
memcpy (test_ctx->seed_V, tv[tvidx].v, 16);
test_ctx->is_seeded = 1;
test_ctx->seed_init_pid = _getpid();
/* Setup a DT value. */
test_ctx->test_dt_ptr = tv[tvidx].dt;
test_ctx->test_dt_counter = ( (tv[tvidx].dt[12] << 24)
|(tv[tvidx].dt[13] << 16)
|(tv[tvidx].dt[14] << 8)
|(tv[tvidx].dt[15]) );
/* Get and compare the first three results. */
for (ridx=0; ridx < 3; ridx++)
{
/* Compute the next value. */
if (x931_aes_driver (result, 16, test_ctx))
{
errtxt = "X9.31 RNG core function failed";
goto leave;
}
/* Compare it to the known value. */
if (memcmp (result, tv[tvidx].r[ridx], 16))
{
/* log_printhex ("x931_aes got: ", result, 16); */
/* log_printhex ("x931_aes exp: ", tv[tvidx].r[ridx], 16); */
errtxt = "RNG output does not match known value";
goto leave;
}
}
/* This test is actual pretty pointless because we use a local test
context. */
if (test_ctx->key_init_pid != _getpid()
|| test_ctx->seed_init_pid != _getpid())
{
errtxt = "fork detection failed";
goto leave;
}
gcry_cipher_close (test_ctx->cipher_hd);
test_ctx->cipher_hd = NULL;
test_ctx->is_seeded = 0;
check_guards (test_ctx);
}
leave:
unlock_rng ();
gcry_cipher_close (test_ctx->cipher_hd);
check_guards (test_ctx);
gcry_free (test_ctx);
if (report && errtxt)
report ("random", 0, "KAT", errtxt);
return errtxt? GPG_ERR_SELFTEST_FAILED : 0;
}
/* Run the self-tests. */
gcry_error_t
_gcry_rngfips_selftest (selftest_report_func_t report)
{
gcry_err_code_t ec;
#if defined(USE_RNDLINUX) || defined(USE_RNDW32)
{
char buffer[8];
/* Do a simple test using the public interface. This will also
enforce full intialization of the RNG. We need to be fully
initialized due to the global requirement of the
tempvalue_for_x931_aes_driver stuff. */
gcry_randomize (buffer, sizeof buffer, GCRY_STRONG_RANDOM);
}
ec = selftest_kat (report);
#else /*!(USE_RNDLINUX||USE_RNDW32)*/
report ("random", 0, "setup", "no entropy gathering module");
ec = GPG_ERR_SELFTEST_FAILED;
#endif
return gpg_error (ec);
}
/* Create a new test context for an external RNG test driver. On
success the test context is stored at R_CONTEXT; on failure NULL is
stored at R_CONTEXT and an error code is returned. */
gcry_err_code_t
_gcry_rngfips_init_external_test (void **r_context, unsigned int flags,
const void *key, size_t keylen,
const void *seed, size_t seedlen,
const void *dt, size_t dtlen)
{
gpg_error_t err;
rng_context_t test_ctx;
_gcry_rngfips_initialize (1); /* Auto-initialize if needed. */
if (!r_context
|| !key || keylen != 16
|| !seed || seedlen != 16
|| !dt || dtlen != 16 )
return GPG_ERR_INV_ARG;
test_ctx = gcry_calloc (1, sizeof *test_ctx + dtlen);
if (!test_ctx)
return gpg_err_code_from_syserror ();
setup_guards (test_ctx);
/* Setup the key. */
err = gcry_cipher_open (&test_ctx->cipher_hd,
GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
GCRY_CIPHER_SECURE);
if (err)
goto leave;
err = gcry_cipher_setkey (test_ctx->cipher_hd, key, keylen);
if (err)
goto leave;
test_ctx->key_init_pid = _getpid();
/* Setup the seed. */
memcpy (test_ctx->seed_V, seed, seedlen);
test_ctx->is_seeded = 1;
test_ctx->seed_init_pid = _getpid();
/* Setup a DT value. Because our context structure only stores a
pointer we copy the DT value to the extra space we allocated in
the test_ctx and set the pointer to that address. */
memcpy ((unsigned char*)test_ctx + sizeof *test_ctx, dt, dtlen);
test_ctx->test_dt_ptr = (unsigned char*)test_ctx + sizeof *test_ctx;
test_ctx->test_dt_counter = ( (test_ctx->test_dt_ptr[12] << 24)
|(test_ctx->test_dt_ptr[13] << 16)
|(test_ctx->test_dt_ptr[14] << 8)
|(test_ctx->test_dt_ptr[15]) );
if ( (flags & 1) )
test_ctx->test_no_dup_check = 1;
check_guards (test_ctx);
/* All fine. */
err = 0;
leave:
if (err)
{
gcry_cipher_close (test_ctx->cipher_hd);
gcry_free (test_ctx);
*r_context = NULL;
}
else
*r_context = test_ctx;
return gcry_err_code (err);
}
/* Get BUFLEN bytes from the RNG using the test CONTEXT and store them
at BUFFER. Return 0 on success or an error code. */
gcry_err_code_t
_gcry_rngfips_run_external_test (void *context, char *buffer, size_t buflen)
{
rng_context_t test_ctx = context;
if (!test_ctx || !buffer || buflen != 16)
return GPG_ERR_INV_ARG;
lock_rng ();
get_random (buffer, buflen, test_ctx);
unlock_rng ();
return 0;
}
/* Release the test CONTEXT. */
void
_gcry_rngfips_deinit_external_test (void *context)
{
rng_context_t test_ctx = context;
if (test_ctx)
{
gcry_cipher_close (test_ctx->cipher_hd);
gcry_free (test_ctx);
}
}