/* rndjent.c - Driver for the jitterentropy module. * Copyright (C) 2017 g10 Code GmbH * Copyright (C) 2017 Bundesamt für Sicherheit in der Informationstechnik * Copyright (C) 2013 Stephan Mueller * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, and the entire permission notice in its entirety, * including the disclaimer of warranties. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include #ifdef HAVE_STDINT_H # include #endif #include "types.h" #include "g10lib.h" #include "../cipher/bithelp.h" #include "rand-internal.h" /* * Decide whether we can support jent at compile time. */ #undef USE_JENT #define JENT_USES_RDTSC 1 #define JENT_USES_GETTIME 2 #define JENT_USES_READ_REAL_TIME 3 #ifdef ENABLE_JENT_SUPPORT # if defined (__i386__) || defined(__x86_64__) # define USE_JENT JENT_USES_RDTSC # elif defined (HAVE_CLOCK_GETTIME) # if _AIX # define USE_JENT JENT_USES_READ_REAL_TIME # else # define USE_JENT JENT_USES_GETTIME # endif # endif #endif /*ENABLE_JENT_SUPPORT*/ #ifdef USE_JENT #undef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT /* Uncomment the next line to build with statistics. */ /* #define CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT 1 */ /* Note that we source include the actual jitter entropy code. * Platform dependent code is indirectly included from our own * jitterentropy-user-base.h file. */ /* Tell jitterentropy* that all functions shall be static. */ #define JENT_PRIVATE_COMPILE 1 #include "jitterentropy-base.c" /* 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 (jent_rng_lock); static int jent_rng_is_locked; /* This flag tracks whether the RNG has been initialized - either * with error or with success. Protected by JENT_RNG_LOCK. */ static int jent_rng_is_initialized; /* Our collector. The RNG is in a working state if its value is not * NULL. Protected by JENT_RNG_LOCK. */ struct rand_data *jent_rng_collector; /* The number of times the core entropy function has been called and * the number of random bytes retrieved. */ static unsigned long jent_rng_totalcalls; static unsigned long jent_rng_totalbytes; /* JENT statistic helper code. */ #ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT static void jent_init_statistic (struct rand_data *rand_data) { /* int i; */ /* struct entropy_stat *stat = &rand_data->entropy_stat; */ /* for (i = 0; i < 64; i++) */ /* { */ /* stat->bitslot[i] = 0; */ /* stat->bitvar[i] = 0; */ /* } */ /* jent_get_nstime (&stat->collection_begin); */ } static void jent_bit_count (struct rand_data *rand_data, u64 prev_data) { /* int i; */ /* if (!rand_data->entropy_stat.enable_bit_test) */ /* return; */ /* for (i = 0; i < 64; i++) */ /* { */ /* /\* collect the count of set bits per bit position in the */ /* * current ->data field *\/ */ /* rand_data->entropy_stat.bitslot[i] += (rand_data->data & 1<data & 1<entropy_stat.bitvar[i] += 1; */ /* } */ } static void jent_statistic_copy_stat (struct entropy_stat *src, struct entropy_stat *dst) { /* /\* not copying bitslot and bitvar as they are not needed for */ /* * statistic printout *\/ */ /* dst->collection_begin = src->collection_begin; */ /* dst->collection_end = src->collection_end; */ /* dst->old_delta = src->old_delta; */ /* dst->setbits = src->setbits; */ /* dst->varbits = src->varbits; */ /* dst->obsbits = src->obsbits; */ /* dst->collection_loop_cnt= src->collection_loop_cnt; */ } /* * Assessment of statistical behavior of the generated output and returning * the information to the caller by filling the target value. * * Details about the bit statistics are given in chapter 4 of the doc. * Chapter 5 documents the timer analysis and the resulting entropy. */ static void jent_calc_statistic (struct rand_data *rand_data, struct entropy_stat *target, unsigned int loop_cnt) { /* int i; */ /* struct entropy_stat *stat = &rand_data->entropy_stat; */ /* jent_get_nstime(&stat->collection_end); */ /* stat->collection_loop_cnt = loop_cnt; */ /* stat->setbits = 0; */ /* stat->varbits = 0; */ /* stat->obsbits = 0; */ /* for (i = 0; i < DATA_SIZE_BITS; i++) */ /* { */ /* stat->setbits += stat->bitslot[i]; */ /* stat->varbits += stat->bitvar[i]; */ /* /\* This is the sum of set bits in the current observation */ /* * of the random data. *\/ */ /* stat->obsbits += (rand_data->data & 1<old_delta = (stat->collection_end - stat->collection_begin); */ } #endif /*CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT*/ /* Acquire the jent_rng_lock. */ static void lock_rng (void) { gpg_err_code_t rc; rc = gpgrt_lock_lock (&jent_rng_lock); if (rc) log_fatal ("failed to acquire the Jent RNG lock: %s\n", gpg_strerror (rc)); jent_rng_is_locked = 1; } /* Release the jent_rng_lock. */ static void unlock_rng (void) { gpg_err_code_t rc; jent_rng_is_locked = 0; rc = gpgrt_lock_unlock (&jent_rng_lock); if (rc) log_fatal ("failed to release the Jent RNG lock: %s\n", gpg_strerror (rc)); } /* Return true if the JENT RNG code can be run. It may not yet been * initialized, though. */ static int is_rng_available (void) { #if USE_JENT == JENT_USES_RDTSC return !!(_gcry_get_hw_features () & HWF_INTEL_RDTSC); #elif USE_JENT == JENT_USES_GETTIME return 2; #elif USE_JENT == JENT_USES_READ_REAL_TIME return 3; #else /* Ooops */ return 0; #endif } #endif /* USE_JENT */ /* * The API used by the high level code. */ /* Read up to LENGTH bytes from a jitter RNG and return the number of * bytes actually read. */ size_t _gcry_rndjent_poll (void (*add)(const void*, size_t, enum random_origins), enum random_origins origin, size_t length) { size_t nbytes = 0; #ifdef USE_JENT if ( is_rng_available () ) { lock_rng (); if (!jent_rng_is_initialized) { /* Auto-initialize. */ jent_rng_is_initialized = 1; jent_entropy_collector_free (jent_rng_collector); jent_rng_collector = NULL; if ( !(_gcry_random_read_conf () & RANDOM_CONF_DISABLE_JENT)) { if (!jent_entropy_init ()) jent_rng_collector = jent_entropy_collector_alloc (1, 0); } } if (jent_rng_collector && add) { /* We have a working JENT and it has not been disabled. */ char buffer[32]; while (length) { int rc; size_t n = length < sizeof(buffer)? length : sizeof (buffer); jent_rng_totalcalls++; rc = jent_read_entropy (jent_rng_collector, buffer, n); if (rc < 0) break; /* We need to hash the output to conform to the BSI * NTG.1 specs. */ _gcry_md_hash_buffer (GCRY_MD_SHA256, buffer, buffer, rc); n = rc < 32? rc : 32; (*add) (buffer, n, origin); length -= n; nbytes += n; jent_rng_totalbytes += n; } wipememory (buffer, sizeof buffer); } unlock_rng (); } #else (void)add; (void)origin; #endif return nbytes; } /* Return the version number of the JENT RNG. If the RNG is not * initialized or usable 0 is returned. If R_ACTIVE is not NULL the * jitter RNG will be initialized and true is stored at R_ACTIVE if * the initialization succeeded. */ unsigned int _gcry_rndjent_get_version (int *r_active) { if (r_active) *r_active = 0; #ifdef USE_JENT if ( is_rng_available () ) { if (r_active) { /* Make sure the RNG is initialized. */ _gcry_rndjent_poll (NULL, 0, 0); lock_rng (); /* To ease debugging we store 2 for a clock_gettime based * implementation and 1 for a rdtsc based code. */ *r_active = jent_rng_collector? is_rng_available () : 0; unlock_rng (); } return jent_version (); } else return 0; #else return 0; #endif } /* Log statistical informantion about the use of this module. */ void _gcry_rndjent_dump_stats (void) { /* In theory we would need to lock the stats here. However this * function is usually called during cleanup and then we _might_ run * into problems. */ #ifdef USE_JENT if ( is_rng_available () ) { log_info ("rndjent stat: collector=%p calls=%lu bytes=%lu\n", jent_rng_collector, jent_rng_totalcalls, jent_rng_totalbytes); } #endif /*USE_JENT*/ }