From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- comm/third_party/libgcrypt/random/rndjent.c | 389 ++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 comm/third_party/libgcrypt/random/rndjent.c (limited to 'comm/third_party/libgcrypt/random/rndjent.c') diff --git a/comm/third_party/libgcrypt/random/rndjent.c b/comm/third_party/libgcrypt/random/rndjent.c new file mode 100644 index 0000000000..56648a8756 --- /dev/null +++ b/comm/third_party/libgcrypt/random/rndjent.c @@ -0,0 +1,389 @@ +/* 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__)) && defined(HAVE_CPU_ARCH_X86) +# 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*/ +} + + +void +_gcry_rndjent_fini (void) +{ +#ifdef USE_JENT + lock_rng (); + + if (jent_rng_is_initialized) + { + jent_entropy_collector_free (jent_rng_collector); + jent_rng_collector = NULL; + } + + unlock_rng (); +#endif +} -- cgit v1.2.3