summaryrefslogtreecommitdiff
path: root/random
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2021-12-08 09:48:29 +0900
committerNIIBE Yutaka <gniibe@fsij.org>2021-12-08 09:48:29 +0900
commit5521cac32d75f2b94894cd5a94deb2c5d25f43a5 (patch)
treeb8450a1373f42275450822a40b336e9bf2132419 /random
parent05472c1882df2fb84b867c0bdbbff510065785ba (diff)
downloadlibgcrypt-5521cac32d75f2b94894cd5a94deb2c5d25f43a5.tar.gz
random: Remove random-fips.c from repo.
* random/random-fips.c: Remove. -- GnuPG-bug-id: 5723 Fixes-commit: e9b692d25d1c149b5417b70e18f2ce173bc25b6d Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Diffstat (limited to 'random')
-rw-r--r--random/random-fips.c1131
1 files changed, 0 insertions, 1131 deletions
diff --git a/random/random-fips.c b/random/random-fips.c
deleted file mode 100644
index 5c251684..00000000
--- a/random/random-fips.c
+++ /dev/null
@@ -1,1131 +0,0 @@
-/* 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 <http://www.gnu.org/licenses/>.
- */
-
-/*
- 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 <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <unistd.h>
-#ifdef HAVE_GETTIMEOFDAY
-#include <sys/time.h>
-#endif
-
-#include "g10lib.h"
-#include "random.h"
-#include "rand-internal.h"
-
-/* 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. */
-GPGRT_LOCK_DEFINE (fips_rng_lock);
-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 accidentally 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 function. 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;
-
- if (initialized)
- return;
- initialized = 1;
-
- 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)
-{
- gpg_err_code_t rc;
-
- rc = gpgrt_lock_lock (&fips_rng_lock);
- if (rc)
- log_fatal ("failed to acquire the RNG lock: %s\n", gpg_strerror (rc));
- fips_rng_is_locked = 1;
-}
-
-
-/* Release the fips_rng_lock. */
-static void
-unlock_rng (void)
-{
- gpg_err_code_t rc;
-
- fips_rng_is_locked = 0;
- rc = gpgrt_lock_unlock (&fips_rng_lock);
- if (rc)
- log_fatal ("failed to release the RNG lock: %s\n", gpg_strerror (rc));
-}
-
-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 million (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 = xmalloc_secure (nbytes);
- entropy_collect_buffer_size = nbytes;
- entropy_collect_buffer_len = 0;
-
-#if USE_RNDGETENTROPY
- rc = _gcry_rndgetentropy_gather_random (entropy_collect_cb, 0,
- X931_AES_KEYLEN,
- GCRY_VERY_STRONG_RANDOM);
-#elif 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)
- {
- xfree (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_err_code_t rc;
- void *buffer;
-
- gcry_assert (fips_rng_is_locked);
-
- /* Allocate a cipher context. */
- rc = _gcry_cipher_open (&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
- GCRY_CIPHER_SECURE);
- if (rc)
- {
- log_error ("error creating cipher context for RNG: %s\n",
- _gcry_strerror (rc));
- return NULL;
- }
-
- /* Get a key from the standard RNG or from the entropy source. */
- if (for_nonce)
- {
- buffer = 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. */
- rc = _gcry_cipher_setkey (hd, buffer, X931_AES_KEYLEN);
- wipememory (buffer, X931_AES_KEYLEN);
- xfree (buffer);
- if (rc)
- {
- log_error ("error creating key for RNG: %s\n", _gcry_strerror (rc));
- _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);
- xfree (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
- = 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 = xcalloc (1, sizeof *nonce_context);
- setup_guards (nonce_context);
-
- std_rng_context = xcalloc_secure (1, sizeof *std_rng_context);
- setup_guards (std_rng_context);
-
- strong_rng_context = 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 ();
-}
-
-
-/* Try to close the FDs of the random gather module. This is
- currently only implemented for rndlinux. */
-void
-_gcry_rngfips_close_fds (void)
-{
- lock_rng ();
-#if USE_RNDGETENTROPY
- _gcry_rndgetentropy_gather_random (NULL, 0, 0, 0);
-#endif
-#if USE_RNDLINUX
- _gcry_rndlinux_gather_random (NULL, 0, 0, 0);
-#endif
- 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_err_code_t rc;
- const char *errtxt = NULL;
- unsigned char result[16];
-
- gcry_assert (tempvalue_for_x931_aes_driver);
-
- test_ctx = xcalloc (1, sizeof *test_ctx);
- setup_guards (test_ctx);
-
- lock_rng ();
-
- for (tvidx=0; tvidx < DIM (tv); tvidx++)
- {
- /* Setup the key. */
- rc = _gcry_cipher_open (&test_ctx->cipher_hd,
- GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
- GCRY_CIPHER_SECURE);
- if (rc)
- {
- errtxt = "error creating cipher context for RNG";
- goto leave;
- }
-
- rc = _gcry_cipher_setkey (test_ctx->cipher_hd, tv[tvidx].key, 16);
- if (rc)
- {
- 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);
- xfree (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_RNDGETENTROPY) || defined(USE_RNDLINUX) || defined(USE_RNDW32)
- {
- char buffer[8];
-
- /* Do a simple test using the public interface. This will also
- enforce full initialization 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_RNDGETENTROPY||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_err_code_t rc;
- 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 = xtrycalloc (1, sizeof *test_ctx + dtlen);
- if (!test_ctx)
- return gpg_err_code_from_syserror ();
- setup_guards (test_ctx);
-
- /* Setup the key. */
- rc = _gcry_cipher_open (&test_ctx->cipher_hd,
- GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
- GCRY_CIPHER_SECURE);
- if (rc)
- goto leave;
-
- rc = _gcry_cipher_setkey (test_ctx->cipher_hd, key, keylen);
- if (rc)
- 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. */
- rc = 0;
-
- leave:
- if (rc)
- {
- _gcry_cipher_close (test_ctx->cipher_hd);
- xfree (test_ctx);
- *r_context = NULL;
- }
- else
- *r_context = test_ctx;
- return rc;
-}
-
-
-/* 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);
- xfree (test_ctx);
- }
-}