diff --git a/random/jitterentropy-base-user.h b/random/jitterentropy-base-user.h index 389106ff..3b4274af 100644 --- a/random/jitterentropy-base-user.h +++ b/random/jitterentropy-base-user.h @@ -1,307 +1,320 @@ /* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2013 * * License * ======= * * 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 #ifndef GCRYPT_JITTERENTROPY_BASE_USER_H #define GCRYPT_JITTERENTROPY_BASE_USER_H /* * This is Libgcrypt specific platform dependent code. We use a * separate file because jitterentropy.h expects such a file. */ #ifndef USE_JENT # error This file expects to be included from rndjent.c (via jitterentropy.h) #endif #ifndef HAVE_STDINT_H # error This module needs stdint.h - try ./configure --disable-jent-support #endif /* When using the libgcrypt secure memory mechanism, all precautions * are taken to protect our state. If the user disables secmem during * runtime, it is his decision and we thus try not to overrule his * decision for less memory protection. */ #define JENT_CPU_JITTERENTROPY_SECURE_MEMORY 1 #define jent_zalloc(n) _gcry_calloc_secure (1, (n)) static void jent_get_nstime(u64 *out) { #if USE_JENT == JENT_USES_RDTSC u32 t_eax, t_edx; asm volatile (".byte 0x0f,0x31\n\t" : "=a" (t_eax), "=d" (t_edx) ); *out = (((u64)t_edx << 32) | t_eax); #elif USE_JENT == JENT_USES_GETTIME struct timespec tv; u64 tmp; /* On Linux we could use CLOCK_MONOTONIC(_RAW), but with * CLOCK_REALTIME we get some nice extra entropy once in a while * from the NTP actions that we want to use as well... though, we do * not rely on that extra little entropy. */ if (!clock_gettime (CLOCK_REALTIME, &tv)) { tmp = tv.tv_sec; tmp = tmp << 32; tmp = tmp | tv.tv_nsec; } else tmp = 0; *out = tmp; #elif USE_JENT == JENT_USES_READ_REAL_TIME /* clock_gettime() on AIX returns a timer value that increments in * steps of 1000. */ u64 tmp = 0; timebasestruct_t aixtime; read_real_time (&aixtime, TIMEBASE_SZ); tmp = aixtime.tb_high; tmp = tmp << 32; tmp = tmp | aixtime.tb_low; *out = tmp; #else # error No clock available in jent_get_nstime #endif } static GPGRT_INLINE void jent_zfree (void *ptr, unsigned int len) { if (ptr) { wipememory (ptr, len); _gcry_free (ptr); } } static GPGRT_INLINE int jent_fips_enabled(void) { return fips_mode(); } static inline void jent_memset_secure(void *s, size_t n) { wipememory (s, n); } static inline long jent_ncpu(void) { -#ifdef _POSIX_SOURCE +#if defined(_POSIX_SOURCE) long ncpu = sysconf(_SC_NPROCESSORS_ONLN); if (ncpu == -1) return -errno; if (ncpu == 0) return -EFAULT; return ncpu; +#elif defined(HAVE_W32_SYSTEM) + SYSTEM_INFO sysinfo; + long ncpu; + + GetNativeSystemInfo (&sysinfo); + ncpu = sysinfo.dwNumberOfProcessors; + if (ncpu <= 0) { + GetSystemInfo (&sysinfo); + ncpu = sysinfo.dwNumberOfProcessors; + } + if (ncpu <= 0) + ncpu = 1; + return ncpu; #else return 1; #endif } #ifdef __linux__ # if defined(_SC_LEVEL1_DCACHE_SIZE) && \ defined(_SC_LEVEL2_CACHE_SIZE) && \ defined(_SC_LEVEL3_CACHE_SIZE) static inline void jent_get_cachesize(long *l1, long *l2, long *l3) { *l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE); *l2 = sysconf(_SC_LEVEL2_CACHE_SIZE); *l3 = sysconf(_SC_LEVEL3_CACHE_SIZE); } # else static inline void jent_get_cachesize(long *l1, long *l2, long *l3) { #define JENT_SYSFS_CACHE_DIR "/sys/devices/system/cpu/cpu0/cache" long val; unsigned int i; char buf[10], file[50]; int fd = 0; /* Iterate over all caches */ for (i = 0; i < 4; i++) { unsigned int shift = 0; char *ext; /* * Check the cache type - we are only interested in Unified * and Data caches. */ memset(buf, 0, sizeof(buf)); snprintf(file, sizeof(file), "%s/index%u/type", JENT_SYSFS_CACHE_DIR, i); fd = open(file, O_RDONLY); if (fd < 0) continue; while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR); close(fd); buf[sizeof(buf) - 1] = '\0'; if (strncmp(buf, "Data", 4) && strncmp(buf, "Unified", 7)) continue; /* Get size of cache */ memset(buf, 0, sizeof(buf)); snprintf(file, sizeof(file), "%s/index%u/size", JENT_SYSFS_CACHE_DIR, i); fd = open(file, O_RDONLY); if (fd < 0) continue; while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR); close(fd); buf[sizeof(buf) - 1] = '\0'; ext = strstr(buf, "K"); if (ext) { shift = 10; ext = '\0'; } else { ext = strstr(buf, "M"); if (ext) { shift = 20; ext = '\0'; } } val = strtol(buf, NULL, 10); if (val == LONG_MAX) continue; val <<= shift; if (!*l1) *l1 = val; else if (!*l2) *l2 = val; else { *l3 = val; break; } } #undef JENT_SYSFS_CACHE_DIR } # endif static inline uint32_t jent_cache_size_roundup(void) { static int checked = 0; static uint32_t cache_size = 0; if (!checked) { long l1 = 0, l2 = 0, l3 = 0; jent_get_cachesize(&l1, &l2, &l3); checked = 1; /* Cache size reported by system */ if (l1 > 0) cache_size += (uint32_t)l1; if (l2 > 0) cache_size += (uint32_t)l2; if (l3 > 0) cache_size += (uint32_t)l3; /* * Force the output_size to be of the form * (bounding_power_of_2 - 1). */ cache_size |= (cache_size >> 1); cache_size |= (cache_size >> 2); cache_size |= (cache_size >> 4); cache_size |= (cache_size >> 8); cache_size |= (cache_size >> 16); if (cache_size == 0) return 0; /* * Make the output_size the smallest power of 2 strictly * greater than cache_size. */ cache_size++; } return cache_size; } #else /* __linux__ */ static inline uint32_t jent_cache_size_roundup(void) { return 0; } #endif /* __linux__ */ #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER #include static inline void jent_yield(void) { sched_yield(); } #endif #endif /* GCRYPT_JITTERENTROPY_BASE_USER_H */ diff --git a/random/rndjent.c b/random/rndjent.c index 14d23794..0468c7cb 100644 --- a/random/rndjent.c +++ b/random/rndjent.c @@ -1,398 +1,409 @@ /* 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 #include +#ifndef EOPNOTSUPP +# define EOPNOTSUPP ENOSYS +#endif + +#ifdef HAVE_W32_SYSTEM +# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0501 +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0501 /* for GetNativeSystemInfo */ +# endif +# 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" #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER #include #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ #include "jitterentropy-gcd.c" #include "jitterentropy-health.c" #include "jitterentropy-noise.c" #include "jitterentropy-sha3.c" #include "jitterentropy-timer.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_safe (&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 }