/* 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" /* 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_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_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_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_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); } }