Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP4
libgcrypt
libgcrypt-jitterentropy-3.3.0.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File libgcrypt-jitterentropy-3.3.0.patch of Package libgcrypt
Index: libgcrypt-1.9.4/LICENSES =================================================================== --- libgcrypt-1.9.4.orig/LICENSES +++ libgcrypt-1.9.4/LICENSES @@ -57,46 +57,53 @@ with any binary distributions derived fr For files: - random/jitterentropy-base.c + - random/jitterentropy-gcd.c + - random/jitterentropy-gcd.h + - random/jitterentropy-health.c + - random/jitterentropy-health.h + - random/jitterentropy-noise.c + - random/jitterentropy-noise.h + - random/jitterentropy-sha3.c + - random/jitterentropy-sha3.h + - random/jitterentropy-timer.c + - random/jitterentropy-timer.h - random/jitterentropy.h - random/rndjent.c (plus common Libgcrypt copyright holders) #+begin_quote - * Copyright Stephan Mueller <smueller@chronox.de>, 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. + Copyright (C) 2017 - 2021, 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 GPL2 + 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. #+end_quote For files: Index: libgcrypt-1.9.4/random/jitterentropy-base.c =================================================================== --- libgcrypt-1.9.4.orig/random/jitterentropy-base.c +++ libgcrypt-1.9.4/random/jitterentropy-base.c @@ -11,29 +11,9 @@ * Interface * ========= * - * See documentation in doc/ folder. - * - * License - * ======= + * See documentation in jitterentropy(3) man page. * - * 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 GPL2 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.) + * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -49,30 +29,43 @@ * DAMAGE. */ -#undef _FORTIFY_SOURCE -#ifdef __OPTIMIZE__ -#pragma GCC optimize ("O0") -#endif - #include "jitterentropy.h" -#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT - /* only check optimization in a compilation for real work */ - #ifdef __OPTIMIZE__ - #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy-base.c." - #endif -#endif +#include "jitterentropy-base.h" +#include "jitterentropy-gcd.h" +#include "jitterentropy-health.h" +#include "jitterentropy-noise.h" +#include "jitterentropy-timer.h" +#include "jitterentropy-sha3.h" -#define MAJVERSION 2 /* API / ABI incompatible changes, functional changes that +#define MAJVERSION 3 /* API / ABI incompatible changes, functional changes that * require consumer to be updated (as long as this number * is zero, the API is not considered stable and can * change without a bump of the major version) */ -#define MINVERSION 1 /* API compatible, ABI may change, functional +#define MINVERSION 3 /* API compatible, ABI may change, functional * enhancements only, consumer can be left unchanged if * enhancements are not considered */ #define PATCHLEVEL 0 /* API / ABI compatible, no functional changes, no * enhancements, bug fixes only */ +/*************************************************************************** + * Jitter RNG Static Definitions + * + * None of the following should be altered + ***************************************************************************/ + +#ifdef __OPTIMIZE__ + #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy.c." +#endif + +/* + * JENT_POWERUP_TESTLOOPCOUNT needs some loops to identify edge + * systems. 100 is definitely too little. + * + * SP800-90B requires at least 1024 initial test cycles. + */ +#define JENT_POWERUP_TESTLOOPCOUNT 1024 + /** * jent_version() - Return machine-usable version number of jent library * @@ -84,7 +77,7 @@ * The result of this function can be used in comparing the version number * in a calling program if version-specific calls need to be make. * - * Return: Version number of kcapi library + * @return Version number of jitterentropy library */ JENT_PRIVATE_STATIC unsigned int jent_version(void) @@ -98,414 +91,57 @@ unsigned int jent_version(void) return version; } -/** - * Update of the loop count used for the next round of - * an entropy collection. - * - * Input: - * @ec entropy collector struct -- may be NULL - * @bits is the number of low bits of the timer to consider - * @min is the number of bits we shift the timer value to the right at - * the end to make sure we have a guaranteed minimum value - * - * @return Newly calculated loop counter - */ -static uint64_t jent_loop_shuffle(struct rand_data *ec, - unsigned int bits, unsigned int min) -{ - uint64_t time = 0; - uint64_t shuffle = 0; - unsigned int i = 0; - unsigned int mask = (1<<bits) - 1; - - jent_get_nstime(&time); - /* - * Mix the current state of the random number into the shuffle - * calculation to balance that shuffle a bit more. - */ - if (ec) - time ^= ec->data; - /* - * We fold the time value as much as possible to ensure that as many - * bits of the time stamp are included as possible. - */ - for (i = 0; (DATA_SIZE_BITS / bits) > i; i++) { - shuffle ^= time & mask; - time = time >> bits; - } - - /* - * We add a lower boundary value to ensure we have a minimum - * RNG loop count. - */ - return (shuffle + (1<<min)); -} - /*************************************************************************** - * Noise sources + * Helper ***************************************************************************/ -/** - * CPU Jitter noise source -- this is the noise source based on the CPU - * execution time jitter - * - * This function injects the individual bits of the time value into the - * entropy pool using an LFSR. - * - * The code is deliberately inefficient with respect to the bit shifting - * and shall stay that way. This function is the root cause why the code - * shall be compiled without optimization. This function not only acts as - * folding operation, but this function's execution is used to measure - * the CPU execution time jitter. Any change to the loop in this function - * implies that careful retesting must be done. - * - * Input: - * @ec entropy collector struct -- may be NULL - * @time time stamp to be injected - * @loop_cnt if a value not equal to 0 is set, use the given value as number of - * loops to perform the folding - * - * Output: - * updated ec->data - * - * @return Number of loops the folding operation is performed - */ -static uint64_t jent_lfsr_time(struct rand_data *ec, uint64_t time, - uint64_t loop_cnt) +/* Calculate log2 of given value assuming that the value is a power of 2 */ +static inline unsigned int jent_log2_simple(unsigned int val) { - unsigned int i; - uint64_t j = 0; - uint64_t new = 0; -#define MAX_FOLD_LOOP_BIT 4 -#define MIN_FOLD_LOOP_BIT 0 - uint64_t fold_loop_cnt = - jent_loop_shuffle(ec, MAX_FOLD_LOOP_BIT, MIN_FOLD_LOOP_BIT); - - /* - * testing purposes -- allow test app to set the counter, not - * needed during runtime - */ - if (loop_cnt) - fold_loop_cnt = loop_cnt; - for (j = 0; j < fold_loop_cnt; j++) { - new = ec->data; - for (i = 1; (DATA_SIZE_BITS) >= i; i++) { - uint64_t tmp = time << (DATA_SIZE_BITS - i); - - tmp = tmp >> (DATA_SIZE_BITS - 1); + unsigned int idx = 0; - /* - * Fibonacci LSFR with polynomial of - * x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is - * primitive according to - * http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf - * (the shift values are the polynomial values minus one - * due to counting bits from 0 to 63). As the current - * position is always the LSB, the polynomial only needs - * to shift data in from the left without wrap. - */ - new ^= tmp; - new ^= ((new >> 63) & 1); - new ^= ((new >> 60) & 1); - new ^= ((new >> 55) & 1); - new ^= ((new >> 30) & 1); - new ^= ((new >> 27) & 1); - new ^= ((new >> 22) & 1); - new = rol64(new, 1); - } - } - ec->data = new; - - return fold_loop_cnt; + while (val >>= 1) + idx++; + return idx; } -/** - * Memory Access noise source -- this is a noise source based on variations in - * memory access times - * - * This function performs memory accesses which will add to the timing - * variations due to an unknown amount of CPU wait states that need to be - * added when accessing memory. The memory size should be larger than the L1 - * caches as outlined in the documentation and the associated testing. - * - * The L1 cache has a very high bandwidth, albeit its access rate is usually - * slower than accessing CPU registers. Therefore, L1 accesses only add minimal - * variations as the CPU has hardly to wait. Starting with L2, significant - * variations are added because L2 typically does not belong to the CPU any more - * and therefore a wider range of CPU wait states is necessary for accesses. - * L3 and real memory accesses have even a wider range of wait states. However, - * to reliably access either L3 or memory, the ec->mem memory must be quite - * large which is usually not desirable. - * - * Input: - * @ec Reference to the entropy collector with the memory access data -- if - * the reference to the memory block to be accessed is NULL, this noise - * source is disabled - * @loop_cnt if a value not equal to 0 is set, use the given value as number of - * loops to perform the folding - * - * @return Number of memory access operations - */ -static unsigned int jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) +/* Increase the memory size by one step */ +static inline unsigned int jent_update_memsize(unsigned int flags) { - unsigned int wrap = 0; - uint64_t i = 0; -#define MAX_ACC_LOOP_BIT 7 -#define MIN_ACC_LOOP_BIT 0 - uint64_t acc_loop_cnt = - jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); - - if (NULL == ec || NULL == ec->mem) - return 0; - wrap = ec->memblocksize * ec->memblocks; + unsigned int global_max = JENT_FLAGS_TO_MAX_MEMSIZE( + JENT_MAX_MEMSIZE_MAX); + unsigned int max; - /* - * testing purposes -- allow test app to set the counter, not - * needed during runtime - */ - if (loop_cnt) - acc_loop_cnt = loop_cnt; + max = JENT_FLAGS_TO_MAX_MEMSIZE(flags); - for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { - unsigned char *tmpval = ec->mem + ec->memlocation; - /* - * memory access: just add 1 to one byte, - * wrap at 255 -- memory access implies read - * from and write to memory location - */ - *tmpval = (*tmpval + 1) & 0xff; + if (!max) { /* - * Addition of memblocksize - 1 to pointer - * with wrap around logic to ensure that every - * memory location is hit evenly + * The safe starting value is the amount of memory we allocated + * last round. */ - ec->memlocation = ec->memlocation + ec->memblocksize - 1; - ec->memlocation = ec->memlocation % wrap; - } - return i; + max = jent_log2_simple(JENT_MEMORY_SIZE); + /* Adjust offset */ + max = (max > JENT_MAX_MEMSIZE_OFFSET) ? + max - JENT_MAX_MEMSIZE_OFFSET : 0; + } else { + max++; + } + + max = (max > global_max) ? global_max : max; + + /* Clear out the max size */ + flags &= ~JENT_MAX_MEMSIZE_MASK; + /* Set the freshly calculated max size */ + flags |= JENT_MAX_MEMSIZE_TO_FLAGS(max); + + return flags; } /*************************************************************************** - * Start of entropy processing logic + * Random Number Generation ***************************************************************************/ /** - * Stuck test by checking the: - * 1st derivation of the jitter measurement (time delta) - * 2nd derivation of the jitter measurement (delta of time deltas) - * 3rd derivation of the jitter measurement (delta of delta of time deltas) - * - * All values must always be non-zero. - * - * Input: - * @ec Reference to entropy collector - * @current_delta Jitter time delta - * - * @return - * 0 jitter measurement not stuck (good bit) - * 1 jitter measurement stuck (reject bit) - */ -static int jent_stuck(struct rand_data *ec, uint64_t current_delta) -{ - int64_t delta2 = ec->last_delta - current_delta; - int64_t delta3 = (uint64_t)delta2 - (uint64_t)ec->last_delta2; - - ec->last_delta = current_delta; - ec->last_delta2 = delta2; - - if (!current_delta || !delta2 || !delta3) - return 1; - - return 0; -} - -/** - * This is the heart of the entropy generation: calculate time deltas and - * use the CPU jitter in the time deltas. The jitter is injected into the - * entropy pool. - * - * WARNING: ensure that ->prev_time is primed before using the output - * of this function! This can be done by calling this function - * and not using its result. - * - * Input: - * @entropy_collector Reference to entropy collector - * - * @return: result of stuck test - */ -static int jent_measure_jitter(struct rand_data *ec) -{ - uint64_t time = 0; - uint64_t current_delta = 0; - int stuck; - - /* Invoke one noise source before time measurement to add variations */ - jent_memaccess(ec, 0); - - /* - * Get time stamp and calculate time delta to previous - * invocation to measure the timing variations - */ - jent_get_nstime(&time); - current_delta = time - ec->prev_time; - ec->prev_time = time; - - /* Now call the next noise sources which also injects the data */ - jent_lfsr_time(ec, current_delta, 0); - - /* Check whether we have a stuck measurement. */ - stuck = jent_stuck(ec, current_delta); - - /* - * Rotate the data buffer by a prime number (any odd number would - * do) to ensure that every bit position of the input time stamp - * has an even chance of being merged with a bit position in the - * entropy pool. We do not use one here as the adjacent bits in - * successive time deltas may have some form of dependency. The - * chosen value of 7 implies that the low 7 bits of the next - * time delta value is concatenated with the current time delta. - */ - if (!stuck) - ec->data = rol64(ec->data, 7); - - return stuck; -} - -/** - * Shuffle the pool a bit by mixing some value with a bijective function (XOR) - * into the pool. - * - * The function generates a mixer value that depends on the bits set and the - * location of the set bits in the random number generated by the entropy - * source. Therefore, based on the generated random number, this mixer value - * can have 2**64 different values. That mixer value is initialized with the - * first two SHA-1 constants. After obtaining the mixer value, it is XORed into - * the random number. - * - * The mixer value is not assumed to contain any entropy. But due to the XOR - * operation, it can also not destroy any entropy present in the entropy pool. - * - * Input: - * @entropy_collector Reference to entropy collector - */ -static void jent_stir_pool(struct rand_data *entropy_collector) -{ - /* - * to shut up GCC on 32 bit, we have to initialize the 64 variable - * with two 32 bit variables - */ - union c { - uint64_t uint64; - uint32_t uint32[2]; - }; - /* - * This constant is derived from the first two 32 bit initialization - * vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1 - */ - union c constant; - /* - * The start value of the mixer variable is derived from the third - * and fourth 32 bit initialization vector of SHA-1 as defined in - * FIPS 180-4 section 5.3.1 - */ - union c mixer; - unsigned int i = 0; - - /* Ensure that the function implements a constant time operation. */ - union c throw_away; - - /* - * Store the SHA-1 constants in reverse order to make up the 64 bit - * value -- this applies to a little endian system, on a big endian - * system, it reverses as expected. But this really does not matter - * as we do not rely on the specific numbers. We just pick the SHA-1 - * constants as they have a good mix of bit set and unset. - */ - constant.uint32[1] = 0x67452301; - constant.uint32[0] = 0xefcdab89; - mixer.uint32[1] = 0x98badcfe; - mixer.uint32[0] = 0x10325476; - - for (i = 0; i < DATA_SIZE_BITS; i++) { - /* - * get the i-th bit of the input random number and only XOR - * the constant into the mixer value when that bit is set - */ - if ((entropy_collector->data >> i) & 1) - mixer.uint64 ^= constant.uint64; - else - throw_away.uint64 ^= constant.uint64; - mixer.uint64 = rol64(mixer.uint64, 1); - } - entropy_collector->data ^= mixer.uint64; -} - -/** - * Generator of one 64 bit random number - * Function fills rand_data->data - * - * Input: - * @ec Reference to entropy collector - */ -static void jent_gen_entropy(struct rand_data *ec) -{ - unsigned int k = 0; - - /* priming of the ->prev_time value */ - jent_measure_jitter(ec); - - while (1) { - /* If a stuck measurement is received, repeat measurement */ - if (jent_measure_jitter(ec)) - continue; - - /* - * We multiply the loop value with ->osr to obtain the - * oversampling rate requested by the caller - */ - if (++k >= (DATA_SIZE_BITS * ec->osr)) - break; - } - if (ec->stir) - jent_stir_pool(ec); -} - -/** - * The continuous test required by FIPS 140-2 -- the function automatically - * primes the test if needed. - * - * Return: - * 0 if FIPS test passed - * < 0 if FIPS test failed - */ -static int jent_fips_test(struct rand_data *ec) -{ - if (ec->fips_enabled == -1) - return 0; - - if (ec->fips_enabled == 0) { - if (!jent_fips_enabled()) { - ec->fips_enabled = -1; - return 0; - } else - ec->fips_enabled = 1; - } - - /* prime the FIPS test */ - if (!ec->old_data) { - ec->old_data = ec->data; - jent_gen_entropy(ec); - } - - if (ec->data == ec->old_data) - return -1; - - ec->old_data = ec->data; - - return 0; -} - -/** * Entry function: Obtain entropy for the caller. * * This function invokes the entropy gathering logic as often to generate @@ -515,34 +151,50 @@ static int jent_fips_test(struct rand_da * This function truncates the last 64 bit entropy value output to the exact * size specified by the caller. * - * Input: - * @ec Reference to entropy collector - * @data pointer to buffer for storing random data -- buffer must already - * exist - * @len size of the buffer, specifying also the requested number of random - * in bytes + * @ec [in] Reference to entropy collector + * @data [out] pointer to buffer for storing random data -- buffer must + * already exist + * @len [in] size of the buffer, specifying also the requested number of random + * in bytes * * @return number of bytes returned when request is fulfilled or an error * * The following error codes can occur: * -1 entropy_collector is NULL - * -2 FIPS test failed + * -2 RCT failed + * -3 APT test failed + * -4 The timer cannot be initialized + * -5 LAG failure */ JENT_PRIVATE_STATIC ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len) { char *p = data; size_t orig_len = len; + int ret = 0; if (NULL == ec) return -1; - while (0 < len) { + if (jent_notime_settick(ec)) + return -4; + + while (len > 0) { size_t tocopy; + unsigned int health_test_result; - jent_gen_entropy(ec); - if (jent_fips_test(ec)) - return -2; + jent_random_data(ec); + + if ((health_test_result = jent_health_failure(ec))) { + if (health_test_result & JENT_RCT_FAILURE) + ret = -2; + else if (health_test_result & JENT_APT_FAILURE) + ret = -3; + else + ret = -5; + + goto err; + } if ((DATA_SIZE_BITS / 8) < len) tocopy = (DATA_SIZE_BITS / 8); @@ -569,93 +221,349 @@ ssize_t jent_read_entropy(struct rand_da * memory protects the entropy pool. Moreover, note that using this * call reduces the speed of the RNG by up to half */ -#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY - jent_gen_entropy(ec); +#ifndef JENT_CPU_JITTERENTROPY_SECURE_MEMORY + jent_random_data(ec); #endif - return orig_len; + +err: + jent_notime_unsettick(ec); + return ret ? ret : (ssize_t)orig_len; +} + +static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr, + unsigned int flags); + +/** + * Entry function: Obtain entropy for the caller. + * + * This is a service function to jent_read_entropy() with the difference + * that it automatically re-allocates the entropy collector if a health + * test failure is observed. Before reallocation, a new power-on health test + * is performed. The allocation of the new entropy collector automatically + * increases the OSR by one. This is done based on the idea that a health + * test failure indicates that the assumed entropy rate is too high. + * + * Note the function returns with an health test error if the OSR is + * getting too large. If an error is returned by this function, the Jitter RNG + * is not safe to be used on the current system. + * + * @ec [in] Reference to entropy collector - this is a double pointer as + * The entropy collector may be freed and reallocated. + * @data [out] pointer to buffer for storing random data -- buffer must + * already exist + * @len [in] size of the buffer, specifying also the requested number of random + * in bytes + * + * @return see jent_read_entropy() + */ +JENT_PRIVATE_STATIC +ssize_t jent_read_entropy_safe(struct rand_data **ec, char *data, size_t len) +{ + char *p = data; + size_t orig_len = len; + ssize_t ret = 0; + + if (!ec) + return -1; + + while (len > 0) { + unsigned int osr, flags, max_mem_set; + + ret = jent_read_entropy(*ec, p, len); + + switch (ret) { + case -1: + case -4: + return ret; + case -2: + case -3: + case -5: + osr = (*ec)->osr + 1; + flags = (*ec)->flags; + max_mem_set = (*ec)->max_mem_set; + + /* generic arbitrary cutoff */ + if (osr > 20) + return ret; + + /* + * If the caller did not set any specific maximum value + * let the Jitter RNG increase the maximum memory by + * one step. + */ + if (!max_mem_set) + flags = jent_update_memsize(flags); + + /* + * re-allocate entropy collector with higher OSR and + * memory size + */ + jent_entropy_collector_free(*ec); + + /* Perform new health test with updated OSR */ + if (jent_entropy_init_ex(osr, flags)) + return -1; + + *ec = _jent_entropy_collector_alloc(osr, flags); + if (!*ec) + return -1; + + /* Remember whether caller configured memory size */ + (*ec)->max_mem_set = !!max_mem_set; + + break; + + default: + len -= (size_t)ret; + p += (size_t)ret; + } + } + + return (ssize_t)orig_len; } /*************************************************************************** * Initialization logic ***************************************************************************/ -JENT_PRIVATE_STATIC -struct rand_data *jent_entropy_collector_alloc(unsigned int osr, - unsigned int flags) +/* + * Obtain memory size to allocate for memory access variations. + * + * The maximum variations we can get from the memory access is when we allocate + * a bit more memory than we have as data cache. But allocating as much + * memory as we have as data cache might strain the resources on the system + * more than necessary. + * + * On a lot of systems it is not necessary to need so much memory as the + * variations coming from the general Jitter RNG execution commonly provide + * large amount of variations. + * + * Thus, the default is: + * + * min(JENT_MEMORY_SIZE, data cache size) + * + * In case the data cache size cannot be obtained, use JENT_MEMORY_SIZE. + * + * If the caller provides a maximum memory size, use + * min(provided max memory, data cache size). + */ +static inline uint32_t jent_memsize(unsigned int flags) +{ + uint32_t memsize, max_memsize; + + max_memsize = JENT_FLAGS_TO_MAX_MEMSIZE(flags); + + if (max_memsize == 0) { + max_memsize = JENT_MEMORY_SIZE; + } else { + max_memsize = UINT32_C(1) << (max_memsize + + JENT_MAX_MEMSIZE_OFFSET); + } + + /* Allocate memory for adding variations based on memory access */ + memsize = jent_cache_size_roundup(); + + /* Limit the memory as defined by caller */ + memsize = (memsize > max_memsize) ? max_memsize : memsize; + + /* Set a value if none was found */ + if (!memsize) + memsize = JENT_MEMORY_SIZE; + + return memsize; +} + +static int jent_selftest_run = 0; + +static struct rand_data +*jent_entropy_collector_alloc_internal(unsigned int osr, unsigned int flags) { struct rand_data *entropy_collector; + /* + * Requesting disabling and forcing of internal timer + * makes no sense. + */ + if ((flags & JENT_DISABLE_INTERNAL_TIMER) && + (flags & JENT_FORCE_INTERNAL_TIMER)) + return NULL; + + /* Force the self test to be run */ + if (!jent_selftest_run && jent_entropy_init_ex(osr, flags)) + return NULL; + + /* + * If the initial test code concludes to force the internal timer + * and the user requests it not to be used, do not allocate + * the Jitter RNG instance. + */ + if (jent_notime_forced() && (flags & JENT_DISABLE_INTERNAL_TIMER)) + return NULL; + entropy_collector = jent_zalloc(sizeof(struct rand_data)); if (NULL == entropy_collector) return NULL; if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) { - /* Allocate memory for adding variations based on memory - * access + uint32_t memsize = jent_memsize(flags); + + entropy_collector->mem = _gcry_calloc (1, memsize); + +#ifdef JENT_RANDOM_MEMACCESS + /* + * Transform the size into a mask - it is assumed that size is + * a power of 2. */ - entropy_collector->mem = - (unsigned char *)jent_zalloc(JENT_MEMORY_SIZE); - if (NULL == entropy_collector->mem) { - jent_zfree(entropy_collector, sizeof(struct rand_data)); - return NULL; - } - entropy_collector->memblocksize = JENT_MEMORY_BLOCKSIZE; + entropy_collector->memmask = memsize - 1; +#else /* JENT_RANDOM_MEMACCESS */ + entropy_collector->memblocksize = memsize / JENT_MEMORY_BLOCKS; entropy_collector->memblocks = JENT_MEMORY_BLOCKS; + + /* sanity check */ + if (entropy_collector->memblocksize * + entropy_collector->memblocks != memsize) + goto err; + +#endif /* JENT_RANDOM_MEMACCESS */ + + if (entropy_collector->mem == NULL) + goto err; entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS; } /* verify and set the oversampling rate */ - if (0 == osr) - osr = 1; /* minimum sampling rate is 1 */ + if (osr < JENT_MIN_OSR) + osr = JENT_MIN_OSR; entropy_collector->osr = osr; + entropy_collector->flags = flags; - entropy_collector->stir = 1; - if (flags & JENT_DISABLE_STIR) - entropy_collector->stir = 0; - if (flags & JENT_DISABLE_UNBIAS) - entropy_collector->disable_unbias = 1; + if (jent_fips_enabled() || (flags & JENT_FORCE_FIPS)) + entropy_collector->fips_enabled = 1; - /* fill the data pad with non-zero values */ - jent_gen_entropy(entropy_collector); + /* Initialize the APT */ + jent_apt_init(entropy_collector, osr); + + /* Initialize the Lag Predictor Test */ + jent_lag_init(entropy_collector, osr); + + /* Was jent_entropy_init run (establishing the common GCD)? */ + if (jent_gcd_get(&entropy_collector->jent_common_timer_gcd)) { + /* + * It was not. This should probably be an error, but this + * behavior breaks the test code. Set the gcd to a value that + * won't hurt anything. + */ + entropy_collector->jent_common_timer_gcd = 1; + } + + /* + * Use timer-less noise source - note, OSR must be set in + * entropy_collector! + */ + if (!(flags & JENT_DISABLE_INTERNAL_TIMER)) { + if (jent_notime_enable(entropy_collector, flags)) + goto err; + } return entropy_collector; + +err: + if (entropy_collector->mem != NULL) + jent_zfree(entropy_collector->mem, JENT_MEMORY_SIZE); + jent_zfree(entropy_collector, sizeof(struct rand_data)); + return NULL; +} + +static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr, + unsigned int flags) +{ + struct rand_data *ec = jent_entropy_collector_alloc_internal(osr, + flags); + + if (!ec) + return ec; + + /* fill the data pad with non-zero values */ + if (jent_notime_settick(ec)) { + jent_entropy_collector_free(ec); + return NULL; + } + jent_random_data(ec); + jent_notime_unsettick(ec); + + return ec; +} + +JENT_PRIVATE_STATIC +struct rand_data *jent_entropy_collector_alloc(unsigned int osr, + unsigned int flags) +{ + struct rand_data *ec = _jent_entropy_collector_alloc(osr, flags); + + /* Remember that the caller provided a maximum size flag */ + if (ec) + ec->max_mem_set = !!JENT_FLAGS_TO_MAX_MEMSIZE(flags); + + return ec; } JENT_PRIVATE_STATIC void jent_entropy_collector_free(struct rand_data *entropy_collector) { - if (NULL != entropy_collector) { - if (NULL != entropy_collector->mem) { - jent_zfree(entropy_collector->mem, JENT_MEMORY_SIZE); + if (entropy_collector != NULL) { + jent_notime_disable(entropy_collector); + if (entropy_collector->mem != NULL) { + jent_zfree(entropy_collector->mem, + jent_memsize(entropy_collector->flags)); entropy_collector->mem = NULL; } jent_zfree(entropy_collector, sizeof(struct rand_data)); } } -JENT_PRIVATE_STATIC -int jent_entropy_init(void) +int jent_time_entropy_init(unsigned int osr, unsigned int flags) { - int i; - uint64_t delta_sum = 0; - uint64_t old_delta = 0; - int time_backwards = 0; - int count_mod = 0; - int count_stuck = 0; - struct rand_data ec; + struct rand_data *ec; + uint64_t *delta_history; + int i, time_backwards = 0, count_stuck = 0, ret = 0; + unsigned int health_test_result; - memset(&ec, 0, sizeof(ec)); + delta_history = jent_gcd_init(JENT_POWERUP_TESTLOOPCOUNT); + if (!delta_history) + return EMEM; + + if (flags & JENT_FORCE_INTERNAL_TIMER) + jent_notime_force(); + else + flags |= JENT_DISABLE_INTERNAL_TIMER; + + /* + * If the start-up health tests (including the APT and RCT) are not + * run, then the entropy source is not 90B compliant. We could test if + * fips_enabled should be set using the jent_fips_enabled() function, + * but this can be overridden using the JENT_FORCE_FIPS flag, which + * isn't passed in yet. It is better to run the tests on the small + * amount of data that we have, which should not fail unless things + * are really bad. + */ + flags |= JENT_FORCE_FIPS; + ec = jent_entropy_collector_alloc_internal(osr, flags); + if (!ec) { + ret = EMEM; + goto out; + } + + if (jent_notime_settick(ec)) { + ret = EMEM; + goto out; + } + + /* To initialize the prior time. */ + jent_measure_jitter(ec, 0, NULL); /* We could perform statistical tests here, but the problem is * that we only have a few loop counts to do testing. These - * loop counts may show some slight skew and we produce - * false positives. - * - * Moreover, only old systems show potentially problematic - * jitter entropy that could potentially be caught here. But - * the RNG is intended for hardware that is available or widely - * used, but not old systems that are long out of favor. Thus, - * no statistical tests. + * loop counts may show some slight skew leading to false positives. */ /* @@ -664,38 +572,31 @@ int jent_entropy_init(void) * following sanity checks verify that we have a high-resolution * timer. */ - /* - * TESTLOOPCOUNT needs some loops to identify edge systems. 100 is - * definitely too little. - */ -#define TESTLOOPCOUNT 300 #define CLEARCACHE 100 - for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) { - uint64_t time = 0; - uint64_t time2 = 0; - uint64_t delta = 0; - unsigned int lowdelta = 0; - int stuck; + for (i = -CLEARCACHE; i < JENT_POWERUP_TESTLOOPCOUNT; i++) { + uint64_t start_time = 0, end_time = 0, delta = 0; + unsigned int stuck; /* Invoke core entropy collection logic */ - jent_get_nstime(&time); - ec.prev_time = time; - jent_lfsr_time(&ec, time, 0); - jent_get_nstime(&time2); + stuck = jent_measure_jitter(ec, 0, &delta); + end_time = ec->prev_time; + start_time = ec->prev_time - delta; /* test whether timer works */ - if (!time || !time2) - return ENOTIME; - delta = time2 - time; + if (!start_time || !end_time) { + ret = ENOTIME; + goto out; + } + /* * test whether timer is fine grained enough to provide * delta even when called shortly after each other -- this * implies that we also have a high resolution timer */ - if (!delta) - return ECOARSETIME; - - stuck = jent_stuck(&ec, delta); + if (!delta || (end_time == start_time)) { + ret = ECOARSETIME; + goto out; + } /* * up to here we did not modify any variable that will be @@ -704,32 +605,18 @@ int jent_entropy_init(void) * etc. with the goal to clear it to get the worst case * measurements. */ - if (CLEARCACHE > i) + if (i < 0) continue; if (stuck) count_stuck++; /* test whether we have an increasing timer */ - if (!(time2 > time)) + if (!(end_time > start_time)) time_backwards++; - /* use 32 bit value to ensure compilation on 32 bit arches */ - lowdelta = time2 - time; - if (!(lowdelta % 100)) - count_mod++; - - /* - * ensure that we have a varying delta timer which is necessary - * for the calculation of entropy -- perform this check - * only after the first loop is executed as we need to prime - * the old_data value - */ - if (delta > old_delta) - delta_sum += (delta - old_delta); - else - delta_sum += (old_delta - delta); - old_delta = delta; + /* Watch for common adjacent GCD values */ + jent_gcd_add_value(delta_history, delta, i); } /* @@ -739,55 +626,109 @@ int jent_entropy_init(void) * should not fail. The value of 3 should cover the NTP case being * performed during our test run. */ - if (3 < time_backwards) - return ENOMONOTONIC; + if (time_backwards > 3) { + ret = ENOMONOTONIC; + goto out; + } - /* - * Variations of deltas of time must on average be larger - * than 1 to ensure the entropy estimation - * implied with 1 is preserved - */ - if ((delta_sum) <= 1) - return EMINVARVAR; + /* First, did we encounter a health test failure? */ + if ((health_test_result = jent_health_failure(ec))) { + ret = (health_test_result & JENT_RCT_FAILURE) ? ERCT : EHEALTH; + goto out; + } - /* - * Ensure that we have variations in the time stamp below 10 for at least - * 10% of all checks -- on some platforms, the counter increments in - * multiples of 100, but not always - */ - if ((TESTLOOPCOUNT/10 * 9) < count_mod) - return ECOARSETIME; + ret = jent_gcd_analyze(delta_history, JENT_POWERUP_TESTLOOPCOUNT); + if (ret) + goto out; /* * If we have more than 90% stuck results, then this Jitter RNG is * likely to not work well. */ - if (JENT_STUCK_INIT_THRES(TESTLOOPCOUNT) < count_stuck) - return ESTUCK; + if (JENT_STUCK_INIT_THRES(JENT_POWERUP_TESTLOOPCOUNT) < count_stuck) + ret = ESTUCK; + +out: + jent_gcd_fini(delta_history, JENT_POWERUP_TESTLOOPCOUNT); + + if ((flags & JENT_FORCE_INTERNAL_TIMER) && ec) + jent_notime_unsettick(ec); + + jent_entropy_collector_free(ec); - return 0; + return ret; } -/*************************************************************************** - * Statistical test logic not compiled for regular operation - ***************************************************************************/ +static inline int jent_entropy_init_common_pre(void) +{ + int ret; + + jent_notime_block_switch(); + + if (sha3_tester()) + return EHASH; + + ret = jent_gcd_selftest(); + + jent_selftest_run = 1; + + return ret; +} + +static inline int jent_entropy_init_common_post(int ret) +{ + /* Unmark the execution of the self tests if they failed. */ + if (ret) + jent_selftest_run = 0; + + return ret; +} + +JENT_PRIVATE_STATIC +int jent_entropy_init(void) +{ + int ret = jent_entropy_init_common_pre(); + + if (ret) + return ret; + + ret = jent_time_entropy_init(0, JENT_DISABLE_INTERNAL_TIMER); + +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + if (ret) + ret = jent_time_entropy_init(0, JENT_FORCE_INTERNAL_TIMER); +#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ + + return jent_entropy_init_common_post(ret); +} -#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT -/* - * Statistical test: return the time duration for the folding operation. If min - * is set, perform the given number of LFSR ops. Otherwise, allow the - * loop count shuffling to define the number of LFSR ops. - */ JENT_PRIVATE_STATIC -uint64_t jent_lfsr_var_stat(struct rand_data *ec, unsigned int min) +int jent_entropy_init_ex(unsigned int osr, unsigned int flags) { - uint64_t time = 0; - uint64_t time2 = 0; + int ret = jent_entropy_init_common_pre(); + + if (ret) + return ret; + + /* Test without internal timer unless caller does not want it */ + if (!(flags & JENT_FORCE_INTERNAL_TIMER)) + ret = jent_time_entropy_init(osr, + flags | JENT_DISABLE_INTERNAL_TIMER); - jent_get_nstime(&time); - jent_memaccess(ec, min); - jent_lfsr_time(ec, time, min); - jent_get_nstime(&time2); - return ((time2 - time)); +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + /* Test with internal timer unless caller does not want it */ + if (ret && !(flags & JENT_DISABLE_INTERNAL_TIMER)) + ret = jent_time_entropy_init(osr, + flags | JENT_FORCE_INTERNAL_TIMER); +#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ + + return jent_entropy_init_common_post(ret); } -#endif /* CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT */ + +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER +JENT_PRIVATE_STATIC +int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread) +{ + return jent_notime_switch(new_thread); +} +#endif Index: libgcrypt-1.9.4/random/jitterentropy-base.h =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-base.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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. + */ + +#ifndef JITTERENTROPY_BASE_H +#define JITTERENTROPY_BASE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +int jent_time_entropy_init(unsigned int osr, unsigned int flags); + +#ifdef __cplusplus +} +#endif + +#endif /* JITTERENTROPY_BASE_H */ Index: libgcrypt-1.9.4/random/jitterentropy-base-user.h =================================================================== --- libgcrypt-1.9.4.orig/random/jitterentropy-base-user.h +++ libgcrypt-1.9.4/random/jitterentropy-base-user.h @@ -39,6 +39,9 @@ * DAMAGE. */ +#include <fcntl.h> +#include <limits.h> + #ifndef GCRYPT_JITTERENTROPY_BASE_USER_H #define GCRYPT_JITTERENTROPY_BASE_USER_H @@ -131,4 +134,174 @@ jent_fips_enabled(void) } +static inline void jent_memset_secure(void *s, size_t n) +{ + wipememory (s, n); +} + +static inline long jent_ncpu(void) +{ +#ifdef _POSIX_SOURCE + long ncpu = sysconf(_SC_NPROCESSORS_ONLN); + + if (ncpu == -1) + return -errno; + + if (ncpu == 0) + return -EFAULT; + + 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 <sched.h> + +static inline void jent_yield(void) +{ + sched_yield(); +} +#endif + #endif /* GCRYPT_JITTERENTROPY_BASE_USER_H */ Index: libgcrypt-1.9.4/random/jitterentropy-gcd.c =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-gcd.c @@ -0,0 +1,188 @@ +/* Jitter RNG: GCD health test + * + * Copyright (C) 2021, Joshua E. Hill <josh@keypair.us> + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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 "jitterentropy.h" +#include "jitterentropy-gcd.h" + +/* The common divisor for all timestamp deltas */ +static uint64_t jent_common_timer_gcd = 0; + +static inline int jent_gcd_tested(void) +{ + return (jent_common_timer_gcd != 0); +} + +/* A straight forward implementation of the Euclidean algorithm for GCD. */ +static inline uint64_t jent_gcd64(uint64_t a, uint64_t b) +{ + /* Make a greater a than or equal b. */ + if (a < b) { + uint64_t c = a; + a = b; + b = c; + } + + /* Now perform the standard inner-loop for this algorithm.*/ + while (b != 0) { + uint64_t r; + + r = a % b; + + a = b; + b = r; + } + + return a; +} + +static int jent_gcd_analyze_internal(uint64_t *delta_history, size_t nelem, + uint64_t *running_gcd_out, + uint64_t *delta_sum_out) +{ + uint64_t running_gcd, delta_sum = 0; + size_t i; + + if (!delta_history) + return -EAGAIN; + + running_gcd = delta_history[0]; + + /* Now perform the analysis on the accumulated delta data. */ + for (i = 1; i < nelem; i++) { + /* + * ensure that we have a varying delta timer which is necessary + * for the calculation of entropy -- perform this check + * only after the first loop is executed as we need to prime + * the old_data value + */ + if (delta_history[i] >= delta_history[i - 1]) + delta_sum += delta_history[i] - delta_history[i - 1]; + else + delta_sum += delta_history[i - 1] - delta_history[i]; + + /* + * This calculates the gcd of all the delta values. that is + * gcd(delta_1, delta_2, ..., delta_nelem) + + * Some timers increment by a fixed (non-1) amount each step. + * This code checks for such increments, and allows the library + * to output the number of such changes have occurred. + */ + running_gcd = jent_gcd64(delta_history[i], running_gcd); + } + + *running_gcd_out = running_gcd; + *delta_sum_out = delta_sum; + + return 0; +} + +int jent_gcd_analyze(uint64_t *delta_history, size_t nelem) +{ + uint64_t running_gcd, delta_sum; + int ret = jent_gcd_analyze_internal(delta_history, nelem, &running_gcd, + &delta_sum); + + if (ret == -EAGAIN) + return 0; + + /* + * Variations of deltas of time must on average be larger than 1 to + * ensure the entropy estimation implied with 1 is preserved. + */ + if (delta_sum <= nelem - 1) { + ret = EMINVARVAR; + goto out; + } + + /* + * Ensure that we have variations in the time stamp below 100 for at + * least 10% of all checks -- on some platforms, the counter increments + * in multiples of 100, but not always + */ + if (running_gcd >= 100) { + ret = ECOARSETIME; + goto out; + } + + /* Adjust all deltas by the observed (small) common factor. */ + if (!jent_gcd_tested()) + jent_common_timer_gcd = running_gcd; + +out: + return ret; +} + +uint64_t *jent_gcd_init(size_t nelem) +{ + uint64_t *delta_history; + + delta_history = jent_zalloc(nelem * sizeof(uint64_t)); + if (!delta_history) + return NULL; + + return delta_history; +} + +void jent_gcd_fini(uint64_t *delta_history, size_t nelem) +{ + if (delta_history) + jent_zfree(delta_history, + (unsigned int)(nelem * sizeof(uint64_t))); +} + +int jent_gcd_get(uint64_t *value) +{ + if (!jent_gcd_tested()) + return 1; + + *value = jent_common_timer_gcd; + return 0; +} + +int jent_gcd_selftest(void) +{ +#define JENT_GCD_SELFTEST_ELEM 10 +#define JENT_GCD_SELFTEST_EXP 3ULL + uint64_t *gcd = jent_gcd_init(JENT_GCD_SELFTEST_ELEM); + uint64_t running_gcd, delta_sum; + unsigned int i; + int ret = EGCD; + + if (!gcd) + return EMEM; + + for (i = 0; i < JENT_GCD_SELFTEST_ELEM; i++) + jent_gcd_add_value(gcd, i * JENT_GCD_SELFTEST_EXP, i); + + if (jent_gcd_analyze_internal(gcd, JENT_GCD_SELFTEST_ELEM, + &running_gcd, &delta_sum)) + goto out; + + if (running_gcd != JENT_GCD_SELFTEST_EXP) + goto out; + + ret = 0; + +out: + jent_gcd_fini(gcd, JENT_GCD_SELFTEST_ELEM); + return ret; +} Index: libgcrypt-1.9.4/random/jitterentropy-gcd.h =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-gcd.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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. + */ + +#ifndef JITTERENTROPY_GCD_H +#define JITTERENTROPY_GCD_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +int jent_gcd_analyze(uint64_t *delta_history, size_t nelem); +uint64_t *jent_gcd_init(size_t nelem); +void jent_gcd_fini(uint64_t *delta_history, size_t nelem); +int jent_gcd_get(uint64_t *value); +int jent_gcd_selftest(void); + +/* Watch for common adjacent GCD values */ +#define jent_gcd_add_value(delta_history, delta, idx) \ + delta_history[idx] = delta; + +#ifdef __cplusplus +} +#endif + +#endif /* JITTERENTROPY_GCD_H */ Index: libgcrypt-1.9.4/random/jitterentropy.h =================================================================== --- libgcrypt-1.9.4.orig/random/jitterentropy.h +++ libgcrypt-1.9.4/random/jitterentropy.h @@ -42,11 +42,122 @@ #ifndef _JITTERENTROPY_H #define _JITTERENTROPY_H -#ifdef __KERNEL__ -#include "jitterentropy-base-kernel.h" -#else +/*************************************************************************** + * Jitter RNG Configuration Section + * + * You may alter the following options + ***************************************************************************/ + +/* + * Enable timer-less timer support + * + * In case the hardware is identified to not provide a high-resolution time + * stamp, this option enables a built-in high-resolution time stamp mechanism. + * + * The timer-less noise source is based on threads. This noise source requires + * the linking with the POSIX threads library. I.e. the executing environment + * must offer POSIX threads. If this option is disabled, no linking + * with the POSIX threads library is needed. + */ +#undef JENT_CONF_ENABLE_INTERNAL_TIMER + +/* + * Disable the loop shuffle operation + * + * The shuffle operation enlarges the timing of the conditioning function + * by a variable length defined by the LSB of a time stamp. Some mathematicians + * are concerned that this pseudo-random selection of the loop iteration count + * may create some form of dependency between the different loop counts + * and the associated time duration of the conditioning function. It + * also complicates entropy assessment because it effectively combines a bunch + * of shifted/scaled copies the same distribution and masks failures from the + * health testing. + * + * By enabling this flag, the loop shuffle operation is disabled and + * the entropy collection operates in a way that honor the concerns. + * + * By enabling this flag, the time of collecting entropy may be enlarged. + */ +#define JENT_CONF_DISABLE_LOOP_SHUFFLE + +/* + * Shall the LAG predictor health test be enabled? + */ +#define JENT_HEALTH_LAG_PREDICTOR + +/* + * Shall the jent_memaccess use a (statistically) random selection for the + * memory to update? + */ +#define JENT_RANDOM_MEMACCESS + +/*************************************************************************** + * Jitter RNG State Definition Section + ***************************************************************************/ + #include "jitterentropy-base-user.h" -#endif /* __KERNEL__ */ + +#define SHA3_256_SIZE_DIGEST_BITS 256 +#define SHA3_256_SIZE_DIGEST (SHA3_256_SIZE_DIGEST_BITS >> 3) + +/* + * The output 256 bits can receive more than 256 bits of min entropy, + * of course, but the 256-bit output of SHA3-256(M) can only asymptotically + * approach 256 bits of min entropy, not attain that bound. Random maps will + * tend to have output collisions, which reduces the creditable output entropy + * (that is what SP 800-90B Section 3.1.5.1.2 attempts to bound). + * + * The value "64" is justified in Appendix A.4 of the current 90C draft, + * and aligns with NIST's in "epsilon" definition in this document, which is + * that a string can be considered "full entropy" if you can bound the min + * entropy in each bit of output to at least 1-epsilon, where epsilon is + * required to be <= 2^(-32). + */ +#define ENTROPY_SAFETY_FACTOR 64 + +/** + * Function pointer data structure to register an external thread handler + * used for the timer-less mode of the Jitter RNG. + * + * The external caller provides these function pointers to handle the + * management of the timer thread that is spawned by the Jitter RNG. + * + * @var jent_notime_init This function is intended to initialze the threading + * support. All data that is required by the threading code must be + * held in the data structure @param ctx. The Jitter RNG maintains the + * data structure and uses it for every invocation of the following calls. + * + * @var jent_notime_fini This function shall terminate the threading support. + * The function must dispose of all memory and resources used for the + * threading operation. It must also dispose of the @param ctx memory. + * + * @var jent_notime_start This function is called when the Jitter RNG wants + * to start a thread. Besides providing a pointer to the @param ctx + * allocated during initialization time, the Jitter RNG provides a + * pointer to the function the thread shall execute and the argument + * the function shall be invoked with. These two parameters have the + * same purpose as the trailing two parameters of pthread_create(3). + * + * @var jent_notime_stop This function is invoked by the Jitter RNG when the + * thread should be stopped. Note, the Jitter RNG intends to start/stop + * the thread frequently. + * + * An example implementation is found in the Jitter RNG itself with its + * default thread handler of jent_notime_thread_builtin. + * + * If the caller wants to register its own thread handler, it must be done + * with the API call jent_entropy_switch_notime_impl as the first + * call to interact with the Jitter RNG, even before jent_entropy_init. + * After jent_entropy_init is called, changing of the threading implementation + * is not allowed. + */ +struct jent_notime_thread { + int (*jent_notime_init)(void **ctx); + void (*jent_notime_fini)(void *ctx); + int (*jent_notime_start)(void *ctx, + void *(*start_routine) (void *), void *arg); + void (*jent_notime_stop)(void *ctx); +}; /* The entropy pool */ struct rand_data @@ -55,35 +166,179 @@ struct rand_data * of the RNG are marked as SENSITIVE. A user must not * access that information while the RNG executes its loops to * calculate the next random value. */ - uint64_t data; /* SENSITIVE Actual random number */ - uint64_t old_data; /* SENSITIVE Previous random number */ - uint64_t prev_time; /* SENSITIVE Previous time stamp */ -#define DATA_SIZE_BITS ((sizeof(uint64_t)) * 8) - uint64_t last_delta; /* SENSITIVE stuck test */ - int64_t last_delta2; /* SENSITIVE stuck test */ - unsigned int osr; /* Oversample rate */ - int fips_enabled; /* FIPS enabled? */ - unsigned int stir:1; /* Post-processing stirring */ - unsigned int disable_unbias:1; /* Deactivate Von-Neuman unbias */ -#define JENT_MEMORY_BLOCKS 64 -#define JENT_MEMORY_BLOCKSIZE 32 + uint8_t data[SHA3_256_SIZE_DIGEST]; /* SENSITIVE Actual random number */ + uint64_t prev_time; /* SENSITIVE Previous time stamp */ +#define DATA_SIZE_BITS (SHA3_256_SIZE_DIGEST_BITS) + +#ifndef JENT_HEALTH_LAG_PREDICTOR + uint64_t last_delta; /* SENSITIVE stuck test */ + uint64_t last_delta2; /* SENSITIVE stuck test */ +#endif /* JENT_HEALTH_LAG_PREDICTOR */ + + unsigned int flags; /* Flags used to initialize */ + unsigned int osr; /* Oversampling rate */ + +#ifdef JENT_RANDOM_MEMACCESS + /* The step size should be larger than the cacheline size. */ +# ifndef JENT_MEMORY_BITS +# define JENT_MEMORY_BITS 17 +# endif +# ifndef JENT_MEMORY_SIZE +# define JENT_MEMORY_SIZE (UINT32_C(1)<<JENT_MEMORY_BITS) +# endif +#else /* JENT_RANDOM_MEMACCESS */ +# ifndef JENT_MEMORY_BLOCKS +# define JENT_MEMORY_BLOCKS 512 +# endif +# ifndef JENT_MEMORY_BLOCKSIZE +# define JENT_MEMORY_BLOCKSIZE 128 +# endif +# ifndef JENT_MEMORY_SIZE +# define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE) +# endif +#endif /* JENT_RANDOM_MEMACCESS */ + #define JENT_MEMORY_ACCESSLOOPS 128 -#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE) - unsigned char *mem; /* Memory access location with size of - * memblocks * memblocksize */ - unsigned int memlocation; /* Pointer to byte in *mem */ - unsigned int memblocks; /* Number of memory blocks in *mem */ - unsigned int memblocksize; /* Size of one memory block in bytes */ - unsigned int memaccessloops; /* Number of memory accesses per random - * bit generation */ + unsigned char *mem; /* Memory access location with size of + * JENT_MEMORY_SIZE or memsize */ +#ifdef JENT_RANDOM_MEMACCESS + uint32_t memmask; /* Memory mask (size of memory - 1) */ +#else + unsigned int memlocation; /* Pointer to byte in *mem */ + unsigned int memblocks; /* Number of memory blocks in *mem */ + unsigned int memblocksize; /* Size of one memory block in bytes */ +#endif + unsigned int memaccessloops; /* Number of memory accesses per random + * bit generation */ + + /* Repetition Count Test */ + int rct_count; /* Number of stuck values */ + + /* Adaptive Proportion Test for a significance level of 2^-30 */ + unsigned int apt_cutoff; /* Calculated using a corrected version + * of the SP800-90B sec 4.4.2 formula */ +#define JENT_APT_WINDOW_SIZE 512 /* Data window size */ + unsigned int apt_observations; /* Number of collected observations in + * current window. */ + unsigned int apt_count; /* The number of times the reference + * symbol been encountered in the + * window. */ + uint64_t apt_base; /* APT base reference */ + unsigned int health_failure; /* Permanent health failure */ + + unsigned int apt_base_set:1; /* APT base reference set? */ + unsigned int fips_enabled:1; + unsigned int enable_notime:1; /* Use internal high-res timer */ + unsigned int max_mem_set:1; /* Maximum memory configured by user */ + +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + volatile uint8_t notime_interrupt; /* indicator to interrupt ctr */ + volatile uint64_t notime_timer; /* high-res timer mock-up */ + uint64_t notime_prev_timer; /* previous timer value */ + void *notime_thread_ctx; /* register thread data */ +#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ + + uint64_t jent_common_timer_gcd; /* Common divisor for all time deltas */ + +#ifdef JENT_HEALTH_LAG_PREDICTOR + /* Lag predictor test to look for re-occurring patterns. */ + + /* The lag global cutoff selected based on the selection of osr. */ + unsigned int lag_global_cutoff; + + /* The lag local cutoff selected based on the selection of osr. */ + unsigned int lag_local_cutoff; + + /* + * The number of times the lag predictor was correct. Compared to the + * global cutoff. + */ + unsigned int lag_prediction_success_count; + + /* + * The size of the current run of successes. Compared to the local + * cutoff. + */ + unsigned int lag_prediction_success_run; + + /* + * The total number of collected observations since the health test was + * last reset. + */ + unsigned int lag_best_predictor; + + /* + * The total number of collected observations since the health test was + * last reset. + */ + unsigned int lag_observations; + + /* + * This is the size of the window used by the predictor. The predictor + * is reset between windows. + */ +#define JENT_LAG_WINDOW_SIZE (1U<<17) + + /* + * The amount of history to base predictions on. This must be a power + * of 2. Must be 4 or greater. + */ +#define JENT_LAG_HISTORY_SIZE 8 +#define JENT_LAG_MASK (JENT_LAG_HISTORY_SIZE - 1) + + /* The delta history for the lag predictor. */ + uint64_t lag_delta_history[JENT_LAG_HISTORY_SIZE]; + + /* The scoreboard that tracks how successful each predictor lag is. */ + unsigned int lag_scoreboard[JENT_LAG_HISTORY_SIZE]; +#endif /* JENT_HEALTH_LAG_PREDICTOR */ }; /* Flags that can be used to initialize the RNG */ -#define JENT_DISABLE_STIR (1<<0) /* Disable stirring the entropy pool */ -#define JENT_DISABLE_UNBIAS (1<<1) /* Disable the Von-Neuman Unbiaser */ +#define JENT_DISABLE_STIR (1<<0) /* UNUSED */ +#define JENT_DISABLE_UNBIAS (1<<1) /* UNUSED */ #define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more entropy, saves MEMORY_SIZE RAM for entropy collector */ +#define JENT_FORCE_INTERNAL_TIMER (1<<3) /* Force the use of the internal + timer */ +#define JENT_DISABLE_INTERNAL_TIMER (1<<4) /* Disable the potential use of + the internal timer. */ +#define JENT_FORCE_FIPS (1<<5) /* Force FIPS compliant mode + including full SP800-90B + compliance. */ + +/* Flags field limiting the amount of memory to be used for memory access */ +#define JENT_FLAGS_TO_MEMSIZE_SHIFT 28 +#define JENT_FLAGS_TO_MAX_MEMSIZE(val) (val >> JENT_FLAGS_TO_MEMSIZE_SHIFT) +#define JENT_MAX_MEMSIZE_TO_FLAGS(val) (val << JENT_FLAGS_TO_MEMSIZE_SHIFT) +#define JENT_MAX_MEMSIZE_32kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 1)) +#define JENT_MAX_MEMSIZE_64kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 2)) +#define JENT_MAX_MEMSIZE_128kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 3)) +#define JENT_MAX_MEMSIZE_256kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 4)) +#define JENT_MAX_MEMSIZE_512kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 5)) +#define JENT_MAX_MEMSIZE_1MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 6)) +#define JENT_MAX_MEMSIZE_2MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 7)) +#define JENT_MAX_MEMSIZE_4MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 8)) +#define JENT_MAX_MEMSIZE_8MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 9)) +#define JENT_MAX_MEMSIZE_16MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(10)) +#define JENT_MAX_MEMSIZE_32MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(11)) +#define JENT_MAX_MEMSIZE_64MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(12)) +#define JENT_MAX_MEMSIZE_128MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(13)) +#define JENT_MAX_MEMSIZE_256MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(14)) +#define JENT_MAX_MEMSIZE_512MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(15)) +#define JENT_MAX_MEMSIZE_MAX JENT_MAX_MEMSIZE_512MB +#define JENT_MAX_MEMSIZE_MASK JENT_MAX_MEMSIZE_MAX +/* We start at 32kB -> offset is log2(32768) */ +#define JENT_MAX_MEMSIZE_OFFSET 14 + +#ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE +# define JENT_MIN_OSR 3 +#else +# define JENT_MIN_OSR 1 +#endif + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* -- BEGIN Main interface functions -- */ @@ -94,19 +349,21 @@ struct rand_data * * It is allowed to change this value as required for the intended environment. */ -#define JENT_STUCK_INIT_THRES(x) (x/10 * 9) +#define JENT_STUCK_INIT_THRES(x) ((x*9) / 10) #endif #ifdef JENT_PRIVATE_COMPILE # define JENT_PRIVATE_STATIC static #else /* JENT_PRIVATE_COMPILE */ -# define JENT_PRIVATE_STATIC +# define JENT_PRIVATE_STATIC __attribute__((visibility("default"))) #endif /* Number of low bits of the time value that we want to consider */ /* get raw entropy */ JENT_PRIVATE_STATIC ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len); +JENT_PRIVATE_STATIC +ssize_t jent_read_entropy_safe(struct rand_data **ec, char *data, size_t len); /* initialize an instance of the entropy collector */ JENT_PRIVATE_STATIC struct rand_data *jent_entropy_collector_alloc(unsigned int osr, @@ -118,13 +375,47 @@ void jent_entropy_collector_free(struct /* initialization of entropy collector */ JENT_PRIVATE_STATIC int jent_entropy_init(void); +JENT_PRIVATE_STATIC +int jent_entropy_init_ex(unsigned int osr, unsigned int flags); /* return version number of core library */ JENT_PRIVATE_STATIC unsigned int jent_version(void); +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER +/* Set a different thread handling logic for the notimer support */ +JENT_PRIVATE_STATIC +int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread); +#endif + /* -- END of Main interface functions -- */ +/* -- BEGIN timer-less threading support functions to prevent code dupes -- */ + +struct jent_notime_ctx { +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + pthread_attr_t notime_pthread_attr; /* pthreads library */ + pthread_t notime_thread_id; /* pthreads thread ID */ +#endif +}; + +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + +JENT_PRIVATE_STATIC +int jent_notime_init(void **ctx); + +JENT_PRIVATE_STATIC +void jent_notime_fini(void *ctx); + +#else + +static inline int jent_notime_init(void **ctx) { (void)ctx; return 0; } +static inline void jent_notime_fini(void *ctx) { (void)ctx; } + +#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ + +/* -- END timer-less threading support functions to prevent code dupes -- */ + /* -- BEGIN error codes for init function -- */ #define ENOTIME 1 /* Timer service not available */ #define ECOARSETIME 2 /* Timer too coarse for RNG */ @@ -135,6 +426,18 @@ unsigned int jent_version(void); #define EMINVARVAR 6 /* Timer variations of variations is too small */ #define EPROGERR 7 /* Programming error */ #define ESTUCK 8 /* Too many stuck results during init. */ +#define EHEALTH 9 /* Health test failed during initialization */ +#define ERCT 10 /* RCT failed during initialization */ +#define EHASH 11 /* Hash self test failed */ +#define EMEM 12 /* Can't allocate memory for initialization */ +#define EGCD 13 /* GCD self-test failed */ +/* -- END error codes for init function -- */ + +/* -- BEGIN error masks for health tests -- */ +#define JENT_RCT_FAILURE 1 /* Failure in RCT health test. */ +#define JENT_APT_FAILURE 2 /* Failure in APT health test. */ +#define JENT_LAG_FAILURE 4 /* Failure in Lag predictor health test. */ +/* -- END error masks for health tests -- */ /* -- BEGIN statistical test functions only complied with CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT -- */ Index: libgcrypt-1.9.4/random/jitterentropy-health.c =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-health.c @@ -0,0 +1,438 @@ +/* Jitter RNG: Health Tests + * + * Copyright (C) 2021, Joshua E. Hill <josh@keypair.us> + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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 "jitterentropy.h" +#include "jitterentropy-health.h" + +/*************************************************************************** + * Lag Predictor Test + * + * This test is a vendor-defined conditional test that is designed to detect + * a known failure mode where the result becomes mostly deterministic + * Note that (lag_observations & JENT_LAG_MASK) is the index where the next + * value provided will be stored. + ***************************************************************************/ + +#ifdef JENT_HEALTH_LAG_PREDICTOR + +/* + * These cutoffs are configured using an entropy estimate of 1/osr under an + * alpha=2^(-22) for a window size of 131072. The other health tests use + * alpha=2^-30, but operate on much smaller window sizes. This larger selection + * of alpha makes the behavior per-lag-window similar to the APT test. + * + * The global cutoffs are calculated using the + * InverseBinomialCDF(n=(JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE), p=2^(-1/osr); 1-alpha) + * The local cutoffs are somewhat more complicated. For background, see Feller's + * _Introduction to Probability Theory and It's Applications_ Vol. 1, + * Chapter 13, section 7 (in particular see equation 7.11, where x is a root + * of the denominator of equation 7.6). + * + * We'll proceed using the notation of SP 800-90B Section 6.3.8 (which is + * developed in Kelsey-McKay-Turan paper "Predictive Models for Min-entropy + * Estimation".) + * + * Here, we set p=2^(-1/osr), seeking a run of successful guesses (r) with + * probability of less than (1-alpha). That is, it is very very likely + * (probability 1-alpha) that there is _no_ run of length r in a block of size + * JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE. + * + * We have to iteratively look for an appropriate value for the cutoff r. + */ +static const unsigned int jent_lag_global_cutoff_lookup[20] = + { 66443, 93504, 104761, 110875, 114707, 117330, 119237, 120686, 121823, + 122739, 123493, 124124, 124660, 125120, 125520, 125871, 126181, 126457, + 126704, 126926 }; +static const unsigned int jent_lag_local_cutoff_lookup[20] = + { 38, 75, 111, 146, 181, 215, 250, 284, 318, 351, + 385, 419, 452, 485, 518, 551, 584, 617, 650, 683 }; + +void jent_lag_init(struct rand_data *ec, unsigned int osr) +{ + /* + * Establish the lag global and local cutoffs based on the presumed + * entropy rate of 1/osr. + */ + if (osr > ARRAY_SIZE(jent_lag_global_cutoff_lookup)) { + ec->lag_global_cutoff = + jent_lag_global_cutoff_lookup[ + ARRAY_SIZE(jent_lag_global_cutoff_lookup) - 1]; + } else { + ec->lag_global_cutoff = jent_lag_global_cutoff_lookup[osr - 1]; + } + + if (osr > ARRAY_SIZE(jent_lag_local_cutoff_lookup)) { + ec->lag_local_cutoff = + jent_lag_local_cutoff_lookup[ + ARRAY_SIZE(jent_lag_local_cutoff_lookup) - 1]; + } else { + ec->lag_local_cutoff = jent_lag_local_cutoff_lookup[osr - 1]; + } +} + +/** + * Reset the lag counters + * + * @ec [in] Reference to entropy collector + */ +static void jent_lag_reset(struct rand_data *ec) +{ + unsigned int i; + + /* Reset Lag counters */ + ec->lag_prediction_success_count = 0; + ec->lag_prediction_success_run = 0; + ec->lag_best_predictor = 0; //The first guess is basically arbitrary. + ec->lag_observations = 0; + + for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) { + ec->lag_scoreboard[i] = 0; + ec->lag_delta_history[i] = 0; + } +} + +/* + * A macro for accessing the history. Index 0 is the last observed symbol + * index 1 is the symbol observed two inputs ago, etc. + */ +#define JENT_LAG_HISTORY(EC,LOC) \ + ((EC)->lag_delta_history[((EC)->lag_observations - (LOC) - 1) & \ + JENT_LAG_MASK]) + +/** + * Insert a new entropy event into the lag predictor test + * + * @ec [in] Reference to entropy collector + * @current_delta [in] Current time delta + */ +static void jent_lag_insert(struct rand_data *ec, uint64_t current_delta) +{ + uint64_t prediction; + unsigned int i; + + /* Initialize the delta_history */ + if (ec->lag_observations < JENT_LAG_HISTORY_SIZE) { + ec->lag_delta_history[ec->lag_observations] = current_delta; + ec->lag_observations++; + return; + } + + /* + * The history is initialized. First make a guess and examine the + * results. + */ + prediction = JENT_LAG_HISTORY(ec, ec->lag_best_predictor); + + if (prediction == current_delta) { + /* The prediction was correct. */ + ec->lag_prediction_success_count++; + ec->lag_prediction_success_run++; + + if ((ec->lag_prediction_success_run >= ec->lag_local_cutoff) || + (ec->lag_prediction_success_count >= ec->lag_global_cutoff)) + ec->health_failure |= JENT_LAG_FAILURE; + } else { + /* The prediction wasn't correct. End any run of successes.*/ + ec->lag_prediction_success_run = 0; + } + + /* Now update the predictors using the current data. */ + for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) { + if (JENT_LAG_HISTORY(ec, i) == current_delta) { + /* + * The ith predictor (which guesses i + 1 symbols in + * the past) successfully guessed. + */ + ec->lag_scoreboard[i] ++; + + /* + * Keep track of the best predictor (tie goes to the + * shortest lag) + */ + if (ec->lag_scoreboard[i] > + ec->lag_scoreboard[ec->lag_best_predictor]) + ec->lag_best_predictor = i; + } + } + + /* + * Finally, update the lag_delta_history array with the newly input + * value. + */ + ec->lag_delta_history[(ec->lag_observations) & JENT_LAG_MASK] = + current_delta; + ec->lag_observations++; + + /* + * lag_best_predictor now is the index of the predictor with the largest + * number of correct guesses. + * This establishes our next guess. + */ + + /* Do we now need a new window? */ + if (ec->lag_observations >= JENT_LAG_WINDOW_SIZE) + jent_lag_reset(ec); +} + +static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta) +{ + /* Note that delta2_n = delta_n - delta_{n-1} */ + return jent_delta(JENT_LAG_HISTORY(ec, 0), current_delta); +} + +static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2) +{ + /* + * Note that delta3_n = delta2_n - delta2_{n-1} + * = delta2_n - (delta_{n-1} - delta_{n-2}) + */ + return jent_delta(jent_delta(JENT_LAG_HISTORY(ec, 1), + JENT_LAG_HISTORY(ec, 0)), delta2); +} + +#else /* JENT_HEALTH_LAG_PREDICTOR */ + +static inline void jent_lag_insert(struct rand_data *ec, uint64_t current_delta) +{ + (void)ec; + (void)current_delta; +} + +static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta) +{ + uint64_t delta2 = jent_delta(ec->last_delta, current_delta); + + ec->last_delta = current_delta; + return delta2; +} + +static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2) +{ + uint64_t delta3 = jent_delta(ec->last_delta2, delta2); + + ec->last_delta2 = delta2; + return delta3; +} + +#endif /* JENT_HEALTH_LAG_PREDICTOR */ + +/*************************************************************************** + * Adaptive Proportion Test + * + * This test complies with SP800-90B section 4.4.2. + ***************************************************************************/ + +/* + * See the SP 800-90B comment #10b for the corrected cutoff for the SP 800-90B + * APT. + * http://www.untruth.org/~josh/sp80090b/UL%20SP800-90B-final%20comments%20v1.9%2020191212.pdf + * In in the syntax of R, this is C = 2 + qbinom(1 - 2^(-30), 511, 2^(-1/osr)). + * (The original formula wasn't correct because the first symbol must + * necessarily have been observed, so there is no chance of observing 0 of these + * symbols.) + * + * For any value above 14, this yields the maximal allowable value of 512 + * (by FIPS 140-2 IG 7.19 Resolution # 16, we cannot choose a cutoff value that + * renders the test unable to fail). + */ +static const unsigned int jent_apt_cutoff_lookup[15]= + { 325, 422, 459, 477, 488, 494, 499, 502, + 505, 507, 508, 509, 510, 511, 512 }; + +void jent_apt_init(struct rand_data *ec, unsigned int osr) +{ + /* + * Establish the apt_cutoff based on the presumed entropy rate of + * 1/osr. + */ + if (osr >= ARRAY_SIZE(jent_apt_cutoff_lookup)) { + ec->apt_cutoff = jent_apt_cutoff_lookup[ + ARRAY_SIZE(jent_apt_cutoff_lookup) - 1]; + } else { + ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1]; + } +} + +/** + * Reset the APT counter + * + * @ec [in] Reference to entropy collector + */ +static void jent_apt_reset(struct rand_data *ec) +{ + /* When reset, accept the _next_ value input as the new base. */ + ec->apt_base_set = 0; +} + +/** + * Insert a new entropy event into APT + * + * @ec [in] Reference to entropy collector + * @current_delta [in] Current time delta + */ +static void jent_apt_insert(struct rand_data *ec, uint64_t current_delta) +{ + /* Initialize the base reference */ + if (!ec->apt_base_set) { + ec->apt_base = current_delta; // APT Step 1 + ec->apt_base_set = 1; // APT Step 2 + + /* + * Reset APT counter + * Note that we've taken in the first symbol in the window. + */ + ec->apt_count = 1; // B = 1 + ec->apt_observations = 1; + + return; + } + + if (current_delta == ec->apt_base) { + ec->apt_count++; // B = B + 1 + + /* Note, ec->apt_count starts with one. */ + if (ec->apt_count >= ec->apt_cutoff) + ec->health_failure |= JENT_APT_FAILURE; + } + + ec->apt_observations++; + + /* Completed one window, the next symbol input will be new apt_base. */ + if (ec->apt_observations >= JENT_APT_WINDOW_SIZE) + jent_apt_reset(ec); // APT Step 4 +} + +/*************************************************************************** + * Stuck Test and its use as Repetition Count Test + * + * The Jitter RNG uses an enhanced version of the Repetition Count Test + * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical + * back-to-back values, the input to the RCT is the counting of the stuck + * values during the generation of one Jitter RNG output block. + * + * The RCT is applied with an alpha of 2^{-30} compliant to FIPS 140-2 IG 9.8. + * + * During the counting operation, the Jitter RNG always calculates the RCT + * cut-off value of C. If that value exceeds the allowed cut-off value, + * the Jitter RNG output block will be calculated completely but discarded at + * the end. The caller of the Jitter RNG is informed with an error code. + ***************************************************************************/ + +/** + * Repetition Count Test as defined in SP800-90B section 4.4.1 + * + * @ec [in] Reference to entropy collector + * @stuck [in] Indicator whether the value is stuck + */ +static void jent_rct_insert(struct rand_data *ec, int stuck) +{ + /* + * If we have a count less than zero, a previous RCT round identified + * a failure. We will not overwrite it. + */ + if (ec->rct_count < 0) + return; + + if (stuck) { + ec->rct_count++; + + /* + * The cutoff value is based on the following consideration: + * alpha = 2^-30 as recommended in FIPS 140-2 IG 9.8. + * In addition, we require an entropy value H of 1/osr as this + * is the minimum entropy required to provide full entropy. + * Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr + * deltas for inserting them into the entropy pool which should + * then have (close to) DATA_SIZE_BITS bits of entropy in the + * conditioned output. + * + * Note, ec->rct_count (which equals to value B in the pseudo + * code of SP800-90B section 4.4.1) starts with zero. Hence + * we need to subtract one from the cutoff value as calculated + * following SP800-90B. Thus C = ceil(-log_2(alpha)/H) = 30*osr. + */ + if ((unsigned int)ec->rct_count >= (30 * ec->osr)) { + ec->rct_count = -1; + ec->health_failure |= JENT_RCT_FAILURE; + } + } else { + ec->rct_count = 0; + } +} + +/** + * Stuck test by checking the: + * 1st derivative of the jitter measurement (time delta) + * 2nd derivative of the jitter measurement (delta of time deltas) + * 3rd derivative of the jitter measurement (delta of delta of time deltas) + * + * All values must always be non-zero. + * + * @ec [in] Reference to entropy collector + * @current_delta [in] Jitter time delta + * + * @return + * 0 jitter measurement not stuck (good bit) + * 1 jitter measurement stuck (reject bit) + */ +unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta) +{ + uint64_t delta2 = jent_delta2(ec, current_delta); + uint64_t delta3 = jent_delta3(ec, delta2); + + /* + * Insert the result of the comparison of two back-to-back time + * deltas. + */ + jent_apt_insert(ec, current_delta); + jent_lag_insert(ec, current_delta); + + if (!current_delta || !delta2 || !delta3) { + /* RCT with a stuck bit */ + jent_rct_insert(ec, 1); + return 1; + } + + /* RCT with a non-stuck bit */ + jent_rct_insert(ec, 0); + + return 0; +} + +/** + * Report any health test failures + * + * @ec [in] Reference to entropy collector + * + * @return a bitmask indicating which tests failed + * 0 No health test failure + * 1 RCT failure + * 2 APT failure + * 4 Lag predictor test failure + */ +unsigned int jent_health_failure(struct rand_data *ec) +{ + /* Test is only enabled in FIPS mode */ + if (!ec->fips_enabled) + return 0; + + return ec->health_failure; +} Index: libgcrypt-1.9.4/random/jitterentropy-health.h =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-health.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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. + */ + +#ifndef JITTERENTROPY_HEALTH_H +#define JITTERENTROPY_HEALTH_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +static inline uint64_t jent_delta(uint64_t prev, uint64_t next) +{ + return (next - prev); +} + +#ifdef JENT_HEALTH_LAG_PREDICTOR +void jent_lag_init(struct rand_data *ec, unsigned int osr); +#else /* JENT_HEALTH_LAG_PREDICTOR */ +static inline void jent_lag_init(struct rand_data *ec, unsigned int osr) +{ + (void)ec; + (void)osr; +} +#endif /* JENT_HEALTH_LAG_PREDICTOR */ + +void jent_apt_init(struct rand_data *ec, unsigned int osr); +unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta); +unsigned int jent_health_failure(struct rand_data *ec); + +#ifdef __cplusplus +} +#endif + +#endif /* JITTERENTROPY_HEALTH_H */ Index: libgcrypt-1.9.4/random/jitterentropy-noise.c =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-noise.c @@ -0,0 +1,387 @@ +/* Jitter RNG: Noise Sources + * + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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 "jitterentropy-noise.h" +#include "jitterentropy-health.h" +#include "jitterentropy-timer.h" +#include "jitterentropy-sha3.h" + +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) + +/*************************************************************************** + * Noise sources + ***************************************************************************/ + +/** + * Update of the loop count used for the next round of + * an entropy collection. + * + * @ec [in] entropy collector struct -- may be NULL + * @bits [in] is the number of low bits of the timer to consider + * @min [in] is the number of bits we shift the timer value to the right at + * the end to make sure we have a guaranteed minimum value + * + * @return Newly calculated loop counter + */ +static uint64_t jent_loop_shuffle(struct rand_data *ec, + unsigned int bits, unsigned int min) +{ +#ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE + + (void)ec; + (void)bits; + + return (UINT64_C(1)<<min); + +#else /* JENT_CONF_DISABLE_LOOP_SHUFFLE */ + + uint64_t time = 0; + uint64_t shuffle = 0; + uint64_t mask = (UINT64_C(1)<<bits) - 1; + unsigned int i = 0; + + /* + * Mix the current state of the random number into the shuffle + * calculation to balance that shuffle a bit more. + */ + if (ec) { + jent_get_nstime_internal(ec, &time); + time ^= ec->data[0]; + } + + /* + * We fold the time value as much as possible to ensure that as many + * bits of the time stamp are included as possible. + */ + for (i = 0; ((DATA_SIZE_BITS + bits - 1) / bits) > i; i++) { + shuffle ^= time & mask; + time = time >> bits; + } + + /* + * We add a lower boundary value to ensure we have a minimum + * RNG loop count. + */ + return (shuffle + (UINT64_C(1)<<min)); + +#endif /* JENT_CONF_DISABLE_LOOP_SHUFFLE */ +} + +/** + * CPU Jitter noise source -- this is the noise source based on the CPU + * execution time jitter + * + * This function injects the individual bits of the time value into the + * entropy pool using a hash. + * + * @ec [in] entropy collector struct -- may be NULL + * @time [in] time stamp to be injected + * @loop_cnt [in] if a value not equal to 0 is set, use the given value as + * number of loops to perform the hash operation + * @stuck [in] Is the time stamp identified as stuck? + * + * Output: + * updated hash context + */ +static void jent_hash_time(struct rand_data *ec, uint64_t time, + uint64_t loop_cnt, unsigned int stuck) +{ + HASH_CTX_ON_STACK(ctx); + uint8_t itermediary[SHA3_256_SIZE_DIGEST]; + uint64_t j = 0; + uint64_t hash_loop_cnt; +#define MAX_HASH_LOOP 3 +#define MIN_HASH_LOOP 0 + + /* Ensure that macros cannot overflow jent_loop_shuffle() */ + BUILD_BUG_ON((MAX_HASH_LOOP + MIN_HASH_LOOP) > 63); + hash_loop_cnt = + jent_loop_shuffle(ec, MAX_HASH_LOOP, MIN_HASH_LOOP); + + sha3_256_init(&ctx); + + /* + * testing purposes -- allow test app to set the counter, not + * needed during runtime + */ + if (loop_cnt) + hash_loop_cnt = loop_cnt; + + /* + * This loop basically slows down the SHA-3 operation depending + * on the hash_loop_cnt. Each iteration of the loop generates the + * same result. + */ + for (j = 0; j < hash_loop_cnt; j++) { + sha3_update(&ctx, ec->data, SHA3_256_SIZE_DIGEST); + sha3_update(&ctx, (uint8_t *)&time, sizeof(uint64_t)); + sha3_update(&ctx, (uint8_t *)&j, sizeof(uint64_t)); + + /* + * If the time stamp is stuck, do not finally insert the value + * into the entropy pool. Although this operation should not do + * any harm even when the time stamp has no entropy, SP800-90B + * requires that any conditioning operation to have an identical + * amount of input data according to section 3.1.5. + */ + + /* + * The sha3_final operations re-initialize the context for the + * next loop iteration. + */ + if (stuck || (j < hash_loop_cnt - 1)) + sha3_final(&ctx, itermediary); + else + sha3_final(&ctx, ec->data); + } + + jent_memset_secure(&ctx, SHA_MAX_CTX_SIZE); + jent_memset_secure(itermediary, sizeof(itermediary)); +} + +#define MAX_ACC_LOOP_BIT 7 +#define MIN_ACC_LOOP_BIT 0 +#ifdef JENT_RANDOM_MEMACCESS + +static inline uint32_t uint32rotl(const uint32_t x, int k) +{ + return (x << k) | (x >> (32 - k)); +} + +static inline uint32_t xoshiro128starstar(uint32_t *s) +{ + const uint32_t result = uint32rotl(s[1] * 5, 7) * 9; + const uint32_t t = s[1] << 9; + + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + + s[2] ^= t; + + s[3] = uint32rotl(s[3], 11); + + return result; +} + +static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) +{ + uint64_t i = 0; + union { + uint32_t u[4]; + uint8_t b[sizeof(uint32_t) * 4]; + } prngState = { .u = {0x8e93eec0, 0xce65608a, 0xa8d46b46, 0xe83cef69} }; + uint32_t addressMask; + uint64_t acc_loop_cnt; + + if (NULL == ec || NULL == ec->mem) + return; + + addressMask = ec->memmask; + + /* Ensure that macros cannot overflow jent_loop_shuffle() */ + BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63); + acc_loop_cnt = + jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); + + /* + * Mix the current data into prngState + * + * Any time you see a PRNG in a noise source, you should be concerned. + * + * The PRNG doesn't directly produce the raw noise, it just adjusts the + * location being updated. The timing of the update is part of the raw + * sample. The main thing this process gets you isn't better + * "per-update: timing, it gets you mostly independent "per-update" + * timing, so we can now benefit from the Central Limit Theorem! + */ + for (i = 0; i < sizeof(prngState); i++) + prngState.b[i] ^= ec->data[i]; + + /* + * testing purposes -- allow test app to set the counter, not + * needed during runtime + */ + if (loop_cnt) + acc_loop_cnt = loop_cnt; + + for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { + /* Take PRNG output to find the memory location to update. */ + unsigned char *tmpval = ec->mem + + (xoshiro128starstar(prngState.u) & + addressMask); + + /* + * memory access: just add 1 to one byte, + * wrap at 255 -- memory access implies read + * from and write to memory location + */ + *tmpval = (unsigned char)((*tmpval + 1) & 0xff); + } +} + +#else /* JENT_RANDOM_MEMACCESS */ + +/** + * Memory Access noise source -- this is a noise source based on variations in + * memory access times + * + * This function performs memory accesses which will add to the timing + * variations due to an unknown amount of CPU wait states that need to be + * added when accessing memory. The memory size should be larger than the L1 + * caches as outlined in the documentation and the associated testing. + * + * The L1 cache has a very high bandwidth, albeit its access rate is usually + * slower than accessing CPU registers. Therefore, L1 accesses only add minimal + * variations as the CPU has hardly to wait. Starting with L2, significant + * variations are added because L2 typically does not belong to the CPU any more + * and therefore a wider range of CPU wait states is necessary for accesses. + * L3 and real memory accesses have even a wider range of wait states. However, + * to reliably access either L3 or memory, the ec->mem memory must be quite + * large which is usually not desirable. + * + * @ec [in] Reference to the entropy collector with the memory access data -- if + * the reference to the memory block to be accessed is NULL, this noise + * source is disabled + * @loop_cnt [in] if a value not equal to 0 is set, use the given value as + * number of loops to perform the hash operation + */ +static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) +{ + unsigned int wrap = 0; + uint64_t i = 0; + + /* Ensure that macros cannot overflow jent_loop_shuffle() */ + BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63); + uint64_t acc_loop_cnt = + jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); + + if (NULL == ec || NULL == ec->mem) + return; + wrap = ec->memblocksize * ec->memblocks; + + /* + * testing purposes -- allow test app to set the counter, not + * needed during runtime + */ + if (loop_cnt) + acc_loop_cnt = loop_cnt; + for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { + unsigned char *tmpval = ec->mem + ec->memlocation; + /* + * memory access: just add 1 to one byte, + * wrap at 255 -- memory access implies read + * from and write to memory location + */ + *tmpval = (unsigned char)((*tmpval + 1) & 0xff); + /* + * Addition of memblocksize - 1 to pointer + * with wrap around logic to ensure that every + * memory location is hit evenly + */ + ec->memlocation = ec->memlocation + ec->memblocksize - 1; + ec->memlocation = ec->memlocation % wrap; + } +} + +#endif /* JENT_RANDOM_MEMACCESS */ + +/*************************************************************************** + * Start of entropy processing logic + ***************************************************************************/ + +/** + * This is the heart of the entropy generation: calculate time deltas and + * use the CPU jitter in the time deltas. The jitter is injected into the + * entropy pool. + * + * WARNING: ensure that ->prev_time is primed before using the output + * of this function! This can be done by calling this function + * and not using its result. + * + * @ec [in] Reference to entropy collector + * @loop_cnt [in] see jent_hash_time + * @ret_current_delta [out] Test interface: return time delta - may be NULL + * + * @return: result of stuck test + */ +unsigned int jent_measure_jitter(struct rand_data *ec, + uint64_t loop_cnt, + uint64_t *ret_current_delta) +{ + uint64_t time = 0; + uint64_t current_delta = 0; + unsigned int stuck; + + /* Invoke one noise source before time measurement to add variations */ + jent_memaccess(ec, loop_cnt); + + /* + * Get time stamp and calculate time delta to previous + * invocation to measure the timing variations + */ + jent_get_nstime_internal(ec, &time); + current_delta = jent_delta(ec->prev_time, time) / + ec->jent_common_timer_gcd; + ec->prev_time = time; + + /* Check whether we have a stuck measurement. */ + stuck = jent_stuck(ec, current_delta); + + /* Now call the next noise sources which also injects the data */ + jent_hash_time(ec, current_delta, loop_cnt, stuck); + + /* return the raw entropy value */ + if (ret_current_delta) + *ret_current_delta = current_delta; + + return stuck; +} + +/** + * Generator of one 256 bit random number + * Function fills rand_data->data + * + * @ec [in] Reference to entropy collector + */ +void jent_random_data(struct rand_data *ec) +{ + unsigned int k = 0, safety_factor = ENTROPY_SAFETY_FACTOR; + + if (!ec->fips_enabled) + safety_factor = 0; + + /* priming of the ->prev_time value */ + jent_measure_jitter(ec, 0, NULL); + + while (1) { + /* If a stuck measurement is received, repeat measurement */ + if (jent_measure_jitter(ec, 0, NULL)) + continue; + + /* + * We multiply the loop value with ->osr to obtain the + * oversampling rate requested by the caller + */ + if (++k >= ((DATA_SIZE_BITS + safety_factor) * ec->osr)) + break; + } +} Index: libgcrypt-1.9.4/random/jitterentropy-noise.h =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-noise.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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. + */ + +#ifndef JITTERENTROPY_NOISE_H +#define JITTERENTROPY_NOISE_H + +#include "jitterentropy.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +unsigned int jent_measure_jitter(struct rand_data *ec, + uint64_t loop_cnt, + uint64_t *ret_current_delta); +void jent_random_data(struct rand_data *ec); + +#ifdef __cplusplus +} +#endif + +#endif /* JITTERENTROPY_NOISE_H */ Index: libgcrypt-1.9.4/random/jitterentropy-sha3.c =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-sha3.c @@ -0,0 +1,382 @@ +/* Jitter RNG: SHA-3 Implementation + * + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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 "jitterentropy-sha3.h" + +/*************************************************************************** + * Message Digest Implementation + ***************************************************************************/ + +/* + * Conversion of Little-Endian representations in byte streams - the data + * representation in the integer values is the host representation. + */ +static inline uint32_t ptr_to_le32(const uint8_t *p) +{ + return (uint32_t)p[0] | (uint32_t)p[1] << 8 | + (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24; +} + +static inline uint64_t ptr_to_le64(const uint8_t *p) +{ + return (uint64_t)ptr_to_le32(p) | (uint64_t)ptr_to_le32(p + 4) << 32; +} + +static inline void le32_to_ptr(uint8_t *p, const uint32_t value) +{ + p[0] = (uint8_t)(value); + p[1] = (uint8_t)(value >> 8); + p[2] = (uint8_t)(value >> 16); + p[3] = (uint8_t)(value >> 24); +} + +static inline void le64_to_ptr(uint8_t *p, const uint64_t value) +{ + le32_to_ptr(p + 4, (uint32_t)(value >> 32)); + le32_to_ptr(p, (uint32_t)(value)); +} + +/*********************************** Keccak ***********************************/ +/* state[x + y*5] */ +#define A(x, y) (x + 5 * y) + +static inline void keccakp_theta(uint64_t s[25]) +{ + uint64_t C[5], D[5]; + + /* Step 1 */ + C[0] = s[A(0, 0)] ^ s[A(0, 1)] ^ s[A(0, 2)] ^ s[A(0, 3)] ^ s[A(0, 4)]; + C[1] = s[A(1, 0)] ^ s[A(1, 1)] ^ s[A(1, 2)] ^ s[A(1, 3)] ^ s[A(1, 4)]; + C[2] = s[A(2, 0)] ^ s[A(2, 1)] ^ s[A(2, 2)] ^ s[A(2, 3)] ^ s[A(2, 4)]; + C[3] = s[A(3, 0)] ^ s[A(3, 1)] ^ s[A(3, 2)] ^ s[A(3, 3)] ^ s[A(3, 4)]; + C[4] = s[A(4, 0)] ^ s[A(4, 1)] ^ s[A(4, 2)] ^ s[A(4, 3)] ^ s[A(4, 4)]; + + /* Step 2 */ + D[0] = C[4] ^ rol64(C[1], 1); + D[1] = C[0] ^ rol64(C[2], 1); + D[2] = C[1] ^ rol64(C[3], 1); + D[3] = C[2] ^ rol64(C[4], 1); + D[4] = C[3] ^ rol64(C[0], 1); + + /* Step 3 */ + s[A(0, 0)] ^= D[0]; + s[A(1, 0)] ^= D[1]; + s[A(2, 0)] ^= D[2]; + s[A(3, 0)] ^= D[3]; + s[A(4, 0)] ^= D[4]; + + s[A(0, 1)] ^= D[0]; + s[A(1, 1)] ^= D[1]; + s[A(2, 1)] ^= D[2]; + s[A(3, 1)] ^= D[3]; + s[A(4, 1)] ^= D[4]; + + s[A(0, 2)] ^= D[0]; + s[A(1, 2)] ^= D[1]; + s[A(2, 2)] ^= D[2]; + s[A(3, 2)] ^= D[3]; + s[A(4, 2)] ^= D[4]; + + s[A(0, 3)] ^= D[0]; + s[A(1, 3)] ^= D[1]; + s[A(2, 3)] ^= D[2]; + s[A(3, 3)] ^= D[3]; + s[A(4, 3)] ^= D[4]; + + s[A(0, 4)] ^= D[0]; + s[A(1, 4)] ^= D[1]; + s[A(2, 4)] ^= D[2]; + s[A(3, 4)] ^= D[3]; + s[A(4, 4)] ^= D[4]; +} + +static inline void keccakp_rho(uint64_t s[25]) +{ + /* Step 1 */ + /* s[A(0, 0)] = s[A(0, 0)]; */ + +#define RHO_ROL(t) (((t + 1) * (t + 2) / 2) % 64) + /* Step 3 */ + s[A(1, 0)] = rol64(s[A(1, 0)], RHO_ROL(0)); + s[A(0, 2)] = rol64(s[A(0, 2)], RHO_ROL(1)); + s[A(2, 1)] = rol64(s[A(2, 1)], RHO_ROL(2)); + s[A(1, 2)] = rol64(s[A(1, 2)], RHO_ROL(3)); + s[A(2, 3)] = rol64(s[A(2, 3)], RHO_ROL(4)); + s[A(3, 3)] = rol64(s[A(3, 3)], RHO_ROL(5)); + s[A(3, 0)] = rol64(s[A(3, 0)], RHO_ROL(6)); + s[A(0, 1)] = rol64(s[A(0, 1)], RHO_ROL(7)); + s[A(1, 3)] = rol64(s[A(1, 3)], RHO_ROL(8)); + s[A(3, 1)] = rol64(s[A(3, 1)], RHO_ROL(9)); + s[A(1, 4)] = rol64(s[A(1, 4)], RHO_ROL(10)); + s[A(4, 4)] = rol64(s[A(4, 4)], RHO_ROL(11)); + s[A(4, 0)] = rol64(s[A(4, 0)], RHO_ROL(12)); + s[A(0, 3)] = rol64(s[A(0, 3)], RHO_ROL(13)); + s[A(3, 4)] = rol64(s[A(3, 4)], RHO_ROL(14)); + s[A(4, 3)] = rol64(s[A(4, 3)], RHO_ROL(15)); + s[A(3, 2)] = rol64(s[A(3, 2)], RHO_ROL(16)); + s[A(2, 2)] = rol64(s[A(2, 2)], RHO_ROL(17)); + s[A(2, 0)] = rol64(s[A(2, 0)], RHO_ROL(18)); + s[A(0, 4)] = rol64(s[A(0, 4)], RHO_ROL(19)); + s[A(4, 2)] = rol64(s[A(4, 2)], RHO_ROL(20)); + s[A(2, 4)] = rol64(s[A(2, 4)], RHO_ROL(21)); + s[A(4, 1)] = rol64(s[A(4, 1)], RHO_ROL(22)); + s[A(1, 1)] = rol64(s[A(1, 1)], RHO_ROL(23)); +} + +static inline void keccakp_pi(uint64_t s[25]) +{ + uint64_t t = s[A(4, 4)]; + + /* Step 1 */ + /* s[A(0, 0)] = s[A(0, 0)]; */ + s[A(4, 4)] = s[A(1, 4)]; + s[A(1, 4)] = s[A(3, 1)]; + s[A(3, 1)] = s[A(1, 3)]; + s[A(1, 3)] = s[A(0, 1)]; + s[A(0, 1)] = s[A(3, 0)]; + s[A(3, 0)] = s[A(3, 3)]; + s[A(3, 3)] = s[A(2, 3)]; + s[A(2, 3)] = s[A(1, 2)]; + s[A(1, 2)] = s[A(2, 1)]; + s[A(2, 1)] = s[A(0, 2)]; + s[A(0, 2)] = s[A(1, 0)]; + s[A(1, 0)] = s[A(1, 1)]; + s[A(1, 1)] = s[A(4, 1)]; + s[A(4, 1)] = s[A(2, 4)]; + s[A(2, 4)] = s[A(4, 2)]; + s[A(4, 2)] = s[A(0, 4)]; + s[A(0, 4)] = s[A(2, 0)]; + s[A(2, 0)] = s[A(2, 2)]; + s[A(2, 2)] = s[A(3, 2)]; + s[A(3, 2)] = s[A(4, 3)]; + s[A(4, 3)] = s[A(3, 4)]; + s[A(3, 4)] = s[A(0, 3)]; + s[A(0, 3)] = s[A(4, 0)]; + s[A(4, 0)] = t; +} + +static inline void keccakp_chi(uint64_t s[25]) +{ + uint64_t t0[5], t1[5]; + + t0[0] = s[A(0, 0)]; + t0[1] = s[A(0, 1)]; + t0[2] = s[A(0, 2)]; + t0[3] = s[A(0, 3)]; + t0[4] = s[A(0, 4)]; + + t1[0] = s[A(1, 0)]; + t1[1] = s[A(1, 1)]; + t1[2] = s[A(1, 2)]; + t1[3] = s[A(1, 3)]; + t1[4] = s[A(1, 4)]; + + s[A(0, 0)] ^= ~s[A(1, 0)] & s[A(2, 0)]; + s[A(0, 1)] ^= ~s[A(1, 1)] & s[A(2, 1)]; + s[A(0, 2)] ^= ~s[A(1, 2)] & s[A(2, 2)]; + s[A(0, 3)] ^= ~s[A(1, 3)] & s[A(2, 3)]; + s[A(0, 4)] ^= ~s[A(1, 4)] & s[A(2, 4)]; + + s[A(1, 0)] ^= ~s[A(2, 0)] & s[A(3, 0)]; + s[A(1, 1)] ^= ~s[A(2, 1)] & s[A(3, 1)]; + s[A(1, 2)] ^= ~s[A(2, 2)] & s[A(3, 2)]; + s[A(1, 3)] ^= ~s[A(2, 3)] & s[A(3, 3)]; + s[A(1, 4)] ^= ~s[A(2, 4)] & s[A(3, 4)]; + + s[A(2, 0)] ^= ~s[A(3, 0)] & s[A(4, 0)]; + s[A(2, 1)] ^= ~s[A(3, 1)] & s[A(4, 1)]; + s[A(2, 2)] ^= ~s[A(3, 2)] & s[A(4, 2)]; + s[A(2, 3)] ^= ~s[A(3, 3)] & s[A(4, 3)]; + s[A(2, 4)] ^= ~s[A(3, 4)] & s[A(4, 4)]; + + s[A(3, 0)] ^= ~s[A(4, 0)] & t0[0]; + s[A(3, 1)] ^= ~s[A(4, 1)] & t0[1]; + s[A(3, 2)] ^= ~s[A(4, 2)] & t0[2]; + s[A(3, 3)] ^= ~s[A(4, 3)] & t0[3]; + s[A(3, 4)] ^= ~s[A(4, 4)] & t0[4]; + + s[A(4, 0)] ^= ~t0[0] & t1[0]; + s[A(4, 1)] ^= ~t0[1] & t1[1]; + s[A(4, 2)] ^= ~t0[2] & t1[2]; + s[A(4, 3)] ^= ~t0[3] & t1[3]; + s[A(4, 4)] ^= ~t0[4] & t1[4]; +} + +static const uint64_t keccakp_iota_vals[] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, + 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, + 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, + 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, + 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL +}; + +static inline void keccakp_iota(uint64_t s[25], unsigned int round) +{ + s[0] ^= keccakp_iota_vals[round]; +} + +static inline void keccakp_1600(uint64_t s[25]) +{ + unsigned int round; + + for (round = 0; round < 24; round++) { + keccakp_theta(s); + keccakp_rho(s); + keccakp_pi(s); + keccakp_chi(s); + keccakp_iota(s, round); + } +} + +/*********************************** SHA-3 ************************************/ + +static inline void sha3_init(struct sha_ctx *ctx) +{ + unsigned int i; + + for (i = 0; i < 25; i++) + ctx->state[i] = 0; + ctx->msg_len = 0; +} + +void sha3_256_init(struct sha_ctx *ctx) +{ + sha3_init(ctx); + ctx->r = SHA3_256_SIZE_BLOCK; + ctx->rword = SHA3_256_SIZE_BLOCK / sizeof(uint64_t); + ctx->digestsize = SHA3_256_SIZE_DIGEST; +} + +static inline void sha3_fill_state(struct sha_ctx *ctx, const uint8_t *in) +{ + unsigned int i; + + for (i = 0; i < ctx->rword; i++) { + ctx->state[i] ^= ptr_to_le64(in); + in += 8; + } +} + +void sha3_update(struct sha_ctx *ctx, const uint8_t *in, size_t inlen) +{ + size_t partial = ctx->msg_len % ctx->r; + + ctx->msg_len += inlen; + + /* Sponge absorbing phase */ + + /* Check if we have a partial block stored */ + if (partial) { + size_t todo = ctx->r - partial; + + /* + * If the provided data is small enough to fit in the partial + * buffer, copy it and leave it unprocessed. + */ + if (inlen < todo) { + memcpy(ctx->partial + partial, in, inlen); + return; + } + + /* + * The input data is large enough to fill the entire partial + * block buffer. Thus, we fill it and transform it. + */ + memcpy(ctx->partial + partial, in, todo); + inlen -= todo; + in += todo; + + sha3_fill_state(ctx, ctx->partial); + keccakp_1600(ctx->state); + } + + /* Perform a transformation of full block-size messages */ + for (; inlen >= ctx->r; inlen -= ctx->r, in += ctx->r) { + sha3_fill_state(ctx, in); + keccakp_1600(ctx->state); + } + + /* If we have data left, copy it into the partial block buffer */ + memcpy(ctx->partial, in, inlen); +} + +void sha3_final(struct sha_ctx *ctx, uint8_t *digest) +{ + size_t partial = ctx->msg_len % ctx->r; + unsigned int i; + + /* Final round in sponge absorbing phase */ + + /* Fill the unused part of the partial buffer with zeros */ + memset(ctx->partial + partial, 0, ctx->r - partial); + + /* + * Add the leading and trailing bit as well as the 01 bits for the + * SHA-3 suffix. + */ + ctx->partial[partial] = 0x06; + ctx->partial[ctx->r - 1] |= 0x80; + + /* Final transformation */ + sha3_fill_state(ctx, ctx->partial); + keccakp_1600(ctx->state); + + /* + * Sponge squeeze phase - the digest size is always smaller as the + * state size r which implies we only have one squeeze round. + */ + for (i = 0; i < ctx->digestsize / 8; i++, digest += 8) + le64_to_ptr(digest, ctx->state[i]); + + /* Add remaining 4 bytes if we use SHA3-224 */ + if (ctx->digestsize % 8) + le32_to_ptr(digest, (uint32_t)(ctx->state[i])); + + memset(ctx->partial, 0, ctx->r); + sha3_init(ctx); +} + +int sha3_tester(void) +{ + HASH_CTX_ON_STACK(ctx); + static const uint8_t msg_256[] = { 0x5E, 0x5E, 0xD6 }; + static const uint8_t exp_256[] = { 0xF1, 0x6E, 0x66, 0xC0, 0x43, 0x72, + 0xB4, 0xA3, 0xE1, 0xE3, 0x2E, 0x07, + 0xC4, 0x1C, 0x03, 0x40, 0x8A, 0xD5, + 0x43, 0x86, 0x8C, 0xC4, 0x0E, 0xC5, + 0x5E, 0x00, 0xBB, 0xBB, 0xBD, 0xF5, + 0x91, 0x1E }; + uint8_t act[SHA3_256_SIZE_DIGEST] = { 0 }; + unsigned int i; + + sha3_256_init(&ctx); + sha3_update(&ctx, msg_256, 3); + sha3_final(&ctx, act); + + for (i = 0; i < SHA3_256_SIZE_DIGEST; i++) { + if (exp_256[i] != act[i]) + return 1; + } + + return 0; +} Index: libgcrypt-1.9.4/random/jitterentropy-sha3.h =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-sha3.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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. + */ + +#ifndef JITTERENTROPY_SHA3_H +#define JITTERENTROPY_SHA3_H + +#include "jitterentropy.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SHA3_SIZE_BLOCK(bits) ((1600 - 2 * bits) >> 3) +#define SHA3_256_SIZE_BLOCK SHA3_SIZE_BLOCK(SHA3_256_SIZE_DIGEST_BITS) +#define SHA3_MAX_SIZE_BLOCK SHA3_256_SIZE_BLOCK + +struct sha_ctx { + uint64_t state[25]; + size_t msg_len; + unsigned int r; + unsigned int rword; + unsigned int digestsize; + uint8_t partial[SHA3_MAX_SIZE_BLOCK]; +}; + +#define SHA_MAX_CTX_SIZE (sizeof(struct sha_ctx)) +#define HASH_CTX_ON_STACK(name) \ + struct sha_ctx name + +void sha3_256_init(struct sha_ctx *ctx); +void sha3_update(struct sha_ctx *ctx, const uint8_t *in, size_t inlen); +void sha3_final(struct sha_ctx *ctx, uint8_t *digest); +int sha3_tester(void); + +#ifdef __cplusplus +} +#endif + +#endif /* JITTERENTROPY_SHA3_H */ Index: libgcrypt-1.9.4/random/jitterentropy-timer.c =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-timer.c @@ -0,0 +1,234 @@ +/* Jitter RNG: Internal timer implementation + * + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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 "jitterentropy-base.h" +#include "jitterentropy-timer.h" + +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + +/*************************************************************************** + * Thread handler + ***************************************************************************/ + +JENT_PRIVATE_STATIC +int jent_notime_init(void **ctx) +{ + struct jent_notime_ctx *thread_ctx; + long ncpu = jent_ncpu(); + + if (ncpu < 0) + return (int)ncpu; + + /* We need at least two CPUs to enable the timer thread */ + if (ncpu < 2) + return -EOPNOTSUPP; + + thread_ctx = calloc(1, sizeof(struct jent_notime_ctx)); + if (!thread_ctx) + return -errno; + + *ctx = thread_ctx; + + return 0; +} + +JENT_PRIVATE_STATIC +void jent_notime_fini(void *ctx) +{ + struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; + + if (thread_ctx) + free(thread_ctx); +} + +static int jent_notime_start(void *ctx, + void *(*start_routine) (void *), void *arg) +{ + struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; + int ret; + + if (!thread_ctx) + return -EINVAL; + + ret = -pthread_attr_init(&thread_ctx->notime_pthread_attr); + if (ret) + return ret; + + return -pthread_create(&thread_ctx->notime_thread_id, + &thread_ctx->notime_pthread_attr, + start_routine, arg); +} + +static void jent_notime_stop(void *ctx) +{ + struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; + + pthread_join(thread_ctx->notime_thread_id, NULL); + pthread_attr_destroy(&thread_ctx->notime_pthread_attr); +} + +static struct jent_notime_thread jent_notime_thread_builtin = { + .jent_notime_init = jent_notime_init, + .jent_notime_fini = jent_notime_fini, + .jent_notime_start = jent_notime_start, + .jent_notime_stop = jent_notime_stop +}; + +/*************************************************************************** + * Timer-less timer replacement + * + * If there is no high-resolution hardware timer available, we create one + * ourselves. This logic is only used when the initialization identifies + * that no suitable time source is available. + ***************************************************************************/ + +static int jent_force_internal_timer = 0; +static int jent_notime_switch_blocked = 0; + +void jent_notime_block_switch(void) +{ + jent_notime_switch_blocked = 1; +} + +static struct jent_notime_thread *notime_thread = &jent_notime_thread_builtin; + +/** + * Timer-replacement loop + * + * @brief The measurement loop triggers the read of the value from the + * counter function. It conceptually acts as the low resolution + * samples timer from a ring oscillator. + */ +static void *jent_notime_sample_timer(void *arg) +{ + struct rand_data *ec = (struct rand_data *)arg; + + ec->notime_timer = 0; + + while (1) { + if (ec->notime_interrupt) + return NULL; + + ec->notime_timer++; + } + + return NULL; +} + +/* + * Enable the clock: spawn a new thread that holds a counter. + * + * Note, although creating a thread is expensive, we do that every time a + * caller wants entropy from us and terminate the thread afterwards. This + * is to ensure an attacker cannot easily identify the ticking thread. + */ +int jent_notime_settick(struct rand_data *ec) +{ + if (!ec->enable_notime || !notime_thread) + return 0; + + ec->notime_interrupt = 0; + ec->notime_prev_timer = 0; + ec->notime_timer = 0; + + return notime_thread->jent_notime_start(ec->notime_thread_ctx, + jent_notime_sample_timer, ec); +} + +void jent_notime_unsettick(struct rand_data *ec) +{ + if (!ec->enable_notime || !notime_thread) + return; + + ec->notime_interrupt = 1; + notime_thread->jent_notime_stop(ec->notime_thread_ctx); +} + +void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out) +{ + if (ec->enable_notime) { + /* + * Allow the counting thread to be initialized and guarantee + * that it ticked since last time we looked. + * + * Note, we do not use an atomic operation here for reading + * jent_notime_timer since if this integer is garbled, it even + * adds to entropy. But on most architectures, read/write + * of an uint64_t should be atomic anyway. + */ + while (ec->notime_timer == ec->notime_prev_timer) + jent_yield(); + + ec->notime_prev_timer = ec->notime_timer; + *out = ec->notime_prev_timer; + } else { + jent_get_nstime(out); + } +} + +static inline int jent_notime_enable_thread(struct rand_data *ec) +{ + if (notime_thread) + return notime_thread->jent_notime_init(&ec->notime_thread_ctx); + return 0; +} + +void jent_notime_disable(struct rand_data *ec) +{ + if (notime_thread) + notime_thread->jent_notime_fini(ec->notime_thread_ctx); +} + +int jent_notime_enable(struct rand_data *ec, unsigned int flags) +{ + /* Use internal timer */ + if (jent_force_internal_timer || (flags & JENT_FORCE_INTERNAL_TIMER)) { + /* Self test not run yet */ + if (!jent_force_internal_timer && + jent_time_entropy_init(flags | JENT_FORCE_INTERNAL_TIMER, + ec->osr)) + return EHEALTH; + + ec->enable_notime = 1; + return jent_notime_enable_thread(ec); + } + + return 0; +} + +int jent_notime_switch(struct jent_notime_thread *new_thread) +{ + if (jent_notime_switch_blocked) + return -EAGAIN; + notime_thread = new_thread; + return 0; +} + +void jent_notime_force(void) +{ + jent_force_internal_timer = 1; +} + +int jent_notime_forced(void) +{ + return jent_force_internal_timer; +} + +#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ Index: libgcrypt-1.9.4/random/jitterentropy-timer.h =================================================================== --- /dev/null +++ libgcrypt-1.9.4/random/jitterentropy-timer.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * 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. + */ + +#ifndef JITTERENTROPY_TIMER_H +#define JITTERENTROPY_TIMER_H + +#include "jitterentropy.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + +void jent_notime_block_switch(void); +int jent_notime_settick(struct rand_data *ec); +void jent_notime_unsettick(struct rand_data *ec); +void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out); +int jent_notime_enable(struct rand_data *ec, unsigned int flags); +void jent_notime_disable(struct rand_data *ec); +int jent_notime_switch(struct jent_notime_thread *new_thread); +void jent_notime_force(void); +int jent_notime_forced(void); + +#else /* JENT_CONF_ENABLE_INTERNAL_TIMER */ + +static inline void jent_notime_block_switch(void) { } + +static inline int jent_notime_settick(struct rand_data *ec) +{ + (void)ec; + return 0; +} + +static inline void jent_notime_unsettick(struct rand_data *ec) { (void)ec; } + +static inline void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out) +{ + (void)ec; + jent_get_nstime(out); +} + +static inline int jent_notime_enable(struct rand_data *ec, unsigned int flags) +{ + (void)ec; + + /* If we force the timer-less noise source, we return an error */ + if (flags & JENT_FORCE_INTERNAL_TIMER) + return EHEALTH; + + return 0; +} + +static inline void jent_notime_disable(struct rand_data *ec) +{ + (void)ec; +} + +static inline int jent_notime_switch(struct jent_notime_thread *new_thread) +{ + (void)new_thread; + return -EOPNOTSUPP; +} + +static inline void jent_notime_force(void) { } + +static inline int jent_notime_forced(void) { return 0; } + +#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ + +#ifdef __cplusplus +} +#endif + +#endif /* JITTERENTROPY-TIMER_H */ Index: libgcrypt-1.9.4/random/Makefile.am =================================================================== --- libgcrypt-1.9.4.orig/random/Makefile.am +++ libgcrypt-1.9.4/random/Makefile.am @@ -50,9 +50,14 @@ rndegd.c \ rndunix.c \ rndw32.c \ rndw32ce.c \ +jitterentropy-gcd.c jitterentropy-gcd.h \ +jitterentropy-health.c jitterentropy-health.h \ +jitterentropy-noise.c jitterentropy-noise.h \ +jitterentropy-sha3.c jitterentropy-sha3.h \ +jitterentropy-timer.c jitterentropy-timer.h \ +jitterentropy-base.h \ jitterentropy-base.c jitterentropy.h jitterentropy-base-user.h - # The rndjent module needs to be compiled without optimization. */ if ENABLE_O_FLAG_MUNGING o_flag_munging = sed -e 's/-O\([1-9sg][1-9sg]*\)/-O0/g' -e 's/-Ofast/-O0/g' @@ -61,9 +66,19 @@ o_flag_munging = cat endif rndjent.o: $(srcdir)/rndjent.c jitterentropy-base-user.h \ + $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ + $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ + $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ + $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ + $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h `echo $(COMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` rndjent.lo: $(srcdir)/rndjent.c jitterentropy-base-user.h \ + $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ + $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ + $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ + $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ + $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h `echo $(LTCOMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` Index: libgcrypt-1.9.4/random/Makefile.in =================================================================== --- libgcrypt-1.9.4.orig/random/Makefile.in +++ libgcrypt-1.9.4/random/Makefile.in @@ -156,6 +156,11 @@ am__depfiles_remade = ./$(DEPDIR)/jitter ./$(DEPDIR)/random-csprng.Plo ./$(DEPDIR)/random-daemon.Plo \ ./$(DEPDIR)/random-drbg.Plo ./$(DEPDIR)/random-system.Plo \ ./$(DEPDIR)/random.Plo ./$(DEPDIR)/rndegd.Plo \ + ./$(DEPDIR)/jitterentropy-gcd.Plo \ + ./$(DEPDIR)/jitterentropy-health.Plo \ + ./$(DEPDIR)/jitterentropy-noise.Plo \ + ./$(DEPDIR)/jitterentropy-sha3.Plo \ + ./$(DEPDIR)/jitterentropy-timer.Plo \ ./$(DEPDIR)/rndhw.Plo ./$(DEPDIR)/rndjent.Plo \ ./$(DEPDIR)/rndlinux.Plo ./$(DEPDIR)/rndunix.Plo \ ./$(DEPDIR)/rndw32.Plo ./$(DEPDIR)/rndw32ce.Plo @@ -391,6 +396,12 @@ rndegd.c \ rndunix.c \ rndw32.c \ rndw32ce.c \ +jitterentropy-gcd.c jitterentropy-gcd.h \ +jitterentropy-health.c jitterentropy-health.h \ +jitterentropy-noise.c jitterentropy-noise.h \ +jitterentropy-sha3.c jitterentropy-sha3.h \ +jitterentropy-timer.c jitterentropy-timer.h \ +jitterentropy-base.h \ jitterentropy-base.c jitterentropy.h jitterentropy-base-user.h @ENABLE_O_FLAG_MUNGING_FALSE@o_flag_munging = cat @@ -452,6 +463,11 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-base.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-gcd.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-health.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-noise.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-sha3.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-timer.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-csprng.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-daemon.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-drbg.Plo@am__quote@ # am--include-marker @@ -624,6 +640,11 @@ clean-am: clean-generic clean-libtool cl distclean: distclean-am -rm -f ./$(DEPDIR)/jitterentropy-base.Plo + -rm -f ./$(DEPDIR)/jitterentropy-gcd.Plo + -rm -f ./$(DEPDIR)/jitterentropy-health.Plo + -rm -f ./$(DEPDIR)/jitterentropy-noise.Plo + -rm -f ./$(DEPDIR)/jitterentropy-sha3.Plo + -rm -f ./$(DEPDIR)/jitterentropy-timer.Plo -rm -f ./$(DEPDIR)/random-csprng.Plo -rm -f ./$(DEPDIR)/random-daemon.Plo -rm -f ./$(DEPDIR)/random-drbg.Plo @@ -682,6 +703,11 @@ installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/jitterentropy-base.Plo + -rm -f ./$(DEPDIR)/jitterentropy-gcd.Plo + -rm -f ./$(DEPDIR)/jitterentropy-health.Plo + -rm -f ./$(DEPDIR)/jitterentropy-noise.Plo + -rm -f ./$(DEPDIR)/jitterentropy-sha3.Plo + -rm -f ./$(DEPDIR)/jitterentropy-timer.Plo -rm -f ./$(DEPDIR)/random-csprng.Plo -rm -f ./$(DEPDIR)/random-daemon.Plo -rm -f ./$(DEPDIR)/random-drbg.Plo @@ -732,10 +758,20 @@ uninstall-am: rndjent.o: $(srcdir)/rndjent.c jitterentropy-base-user.h \ + $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ + $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ + $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ + $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ + $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h `echo $(COMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` rndjent.lo: $(srcdir)/rndjent.c jitterentropy-base-user.h \ + $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ + $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ + $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ + $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ + $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h `echo $(LTCOMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` Index: libgcrypt-1.9.4/random/random-csprng.c =================================================================== --- libgcrypt-1.9.4.orig/random/random-csprng.c +++ libgcrypt-1.9.4/random/random-csprng.c @@ -357,6 +357,17 @@ _gcry_rngcsprng_close_fds (void) _gcry_rndlinux_gather_random (NULL, 0, 0, 0); pool_filled = 0; /* Force re-open on next use. */ #endif + pool_writepos = 0; + pool_readpos = 0; + pool_filled = 0; + pool_filled_counter = 0; + did_initial_extra_seeding = 0; + pool_balance = 0; + just_mixed = 0; + xfree (rndpool); + xfree (keypool); + rndpool = NULL; + keypool = NULL; unlock_pool (); } Index: libgcrypt-1.9.4/random/random-drbg.c =================================================================== --- libgcrypt-1.9.4.orig/random/random-drbg.c +++ libgcrypt-1.9.4/random/random-drbg.c @@ -1860,16 +1860,23 @@ _gcry_rngdrbg_reinit (const char *flagst return ret; } -/* Try to close the FDs of the random gather module. This is - * currently only implemented for rndlinux. */ +/* Release resources used by this DRBG module. That is, close the FDs + * of the random gather module (if any), and release memory used. + */ void _gcry_rngdrbg_close_fds (void) { -#if USE_RNDLINUX drbg_lock (); +#if USE_RNDLINUX _gcry_rndlinux_gather_random (NULL, 0, 0, 0); - drbg_unlock (); #endif + if (drbg_state) + { + drbg_uninstantiate (drbg_state); + xfree (drbg_state); + drbg_state = NULL; + } + drbg_unlock (); } /* Print some statistics about the RNG. */ Index: libgcrypt-1.9.4/random/rndjent.c =================================================================== --- libgcrypt-1.9.4.orig/random/rndjent.c +++ libgcrypt-1.9.4/random/rndjent.c @@ -43,6 +43,8 @@ #ifdef HAVE_STDINT_H # include <stdint.h> #endif +#include <unistd.h> +#include <errno.h> #include "types.h" #include "g10lib.h" @@ -84,7 +86,14 @@ #define JENT_PRIVATE_COMPILE 1 #include "jitterentropy-base.c" - +#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER +#include <pthread.h> +#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, @@ -291,7 +300,7 @@ _gcry_rndjent_poll (void (*add)(const vo size_t n = length < sizeof(buffer)? length : sizeof (buffer); jent_rng_totalcalls++; - rc = jent_read_entropy (jent_rng_collector, buffer, n); + 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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor