diff options
Diffstat (limited to 'random/jitterentropy-base.c')
-rw-r--r-- | random/jitterentropy-base.c | 1055 |
1 files changed, 497 insertions, 558 deletions
diff --git a/random/jitterentropy-base.c b/random/jitterentropy-base.c index a5cf160b..30109dc1 100644 --- a/random/jitterentropy-base.c +++ b/random/jitterentropy-base.c @@ -1,7 +1,7 @@ /* * Non-physical true random number generator based on timing jitter. * - * Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2017 + * Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2021 * * Design * ====== @@ -11,29 +11,9 @@ * Interface * ========= * - * See documentation in doc/ folder. - * - * 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. + * See documentation in jitterentropy(3) man page. * - * 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,412 +91,55 @@ 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); + unsigned int global_max = JENT_FLAGS_TO_MAX_MEMSIZE( + JENT_MAX_MEMSIZE_MAX); + unsigned int max; - if (NULL == ec || NULL == ec->mem) - return 0; - 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; + 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; + max = jent_log2_simple(JENT_MEMORY_SIZE); + /* Adjust offset */ + max = (max > JENT_MAX_MEMSIZE_OFFSET) ? + max - JENT_MAX_MEMSIZE_OFFSET : 0; + } else { + max++; } - return i; -} -/*************************************************************************** - * Start of entropy processing logic - ***************************************************************************/ + max = (max > global_max) ? global_max : max; -/** - * 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; + /* Clear out the max size */ + flags &= ~JENT_MAX_MEMSIZE_MASK; + /* Set the freshly calculated max size */ + flags |= JENT_MAX_MEMSIZE_TO_FLAGS(max); - if (!current_delta || !delta2 || !delta3) - return 1; - - return 0; + return flags; } -/** - * 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; -} +/*************************************************************************** + * Random Number Generation + ***************************************************************************/ /** * Entry function: Obtain entropy for the caller. @@ -515,34 +151,50 @@ static int jent_fips_test(struct rand_data *ec) * 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); @@ -570,92 +222,348 @@ ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len) * call reduces the speed of the RNG by up to half */ #ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY - jent_gen_entropy(ec); + 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 = (unsigned char *)jent_zalloc(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; + + 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; - memset(&ec, 0, sizeof(ec)); + /* + * 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,107 @@ 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); - return 0; + jent_entropy_collector_free(ec); + + 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); +} + +JENT_PRIVATE_STATIC +int jent_entropy_init_ex(unsigned int osr, unsigned int flags) +{ + 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); + +#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); +} -#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_switch_notime_impl(struct jent_notime_thread *new_thread) { - uint64_t time = 0; - uint64_t time2 = 0; - - jent_get_nstime(&time); - jent_memaccess(ec, min); - jent_lfsr_time(ec, time, min); - jent_get_nstime(&time2); - return ((time2 - time)); + return jent_notime_switch(new_thread); } -#endif /* CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT */ |