summaryrefslogtreecommitdiffstats
path: root/comm/third_party/libgcrypt/random/rndjent.c
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/libgcrypt/random/rndjent.c')
-rw-r--r--comm/third_party/libgcrypt/random/rndjent.c389
1 files changed, 389 insertions, 0 deletions
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 <smueller@chronox.de>
+ *
+ * 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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#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<<i) ? 1:0; */
+
+ /* /\* collect the count of bit changes between the current */
+ /* * and the previous random data value per bit position *\/ */
+ /* if ((rand_data->data & 1<<i) != (prev_data & 1<<i)) */
+ /* rand_data->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<<i) ? 1:0; */
+ /* } */
+
+ /* jent_statistic_copy_stat(stat, target); */
+
+ /* stat->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
+}