summaryrefslogtreecommitdiff
path: root/crypto/jitterentropy.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/jitterentropy.c')
-rw-r--r--crypto/jitterentropy.c562
1 files changed, 266 insertions, 296 deletions
diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c
index a11b3208760f..3f93cdc9a7af 100644
--- a/crypto/jitterentropy.c
+++ b/crypto/jitterentropy.c
@@ -2,7 +2,7 @@
* Non-physical true random number generator based on timing jitter --
* Jitter RNG standalone code.
*
- * Copyright Stephan Mueller <smueller@chronox.de>, 2015 - 2020
+ * Copyright Stephan Mueller <smueller@chronox.de>, 2015 - 2023
*
* Design
* ======
@@ -47,7 +47,7 @@
/*
* This Jitterentropy RNG is based on the jitterentropy library
- * version 2.2.0 provided at https://www.chronox.de/jent.html
+ * version 3.4.0 provided at https://www.chronox.de/jent.html
*/
#ifdef __OPTIMIZE__
@@ -57,25 +57,28 @@
typedef unsigned long long __u64;
typedef long long __s64;
typedef unsigned int __u32;
+typedef unsigned char u8;
#define NULL ((void *) 0)
/* The entropy pool */
struct rand_data {
+ /* SHA3-256 is used as conditioner */
+#define DATA_SIZE_BITS 256
/* all data values that are vital to maintain the security
* 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. */
- __u64 data; /* SENSITIVE Actual random number */
- __u64 old_data; /* SENSITIVE Previous random number */
- __u64 prev_time; /* SENSITIVE Previous time stamp */
-#define DATA_SIZE_BITS ((sizeof(__u64)) * 8)
- __u64 last_delta; /* SENSITIVE stuck test */
- __s64 last_delta2; /* SENSITIVE stuck test */
- unsigned int osr; /* Oversample rate */
-#define JENT_MEMORY_BLOCKS 64
-#define JENT_MEMORY_BLOCKSIZE 32
+ void *hash_state; /* SENSITIVE hash state entropy pool */
+ __u64 prev_time; /* SENSITIVE Previous time stamp */
+ __u64 last_delta; /* SENSITIVE stuck test */
+ __s64 last_delta2; /* SENSITIVE stuck test */
+
+ unsigned int flags; /* Flags used to initialize */
+ unsigned int osr; /* Oversample rate */
#define JENT_MEMORY_ACCESSLOOPS 128
-#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
+#define JENT_MEMORY_SIZE \
+ (CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS * \
+ CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE)
unsigned char *mem; /* Memory access location with size of
* memblocks * memblocksize */
unsigned int memlocation; /* Pointer to byte in *mem */
@@ -85,10 +88,11 @@ struct rand_data {
* bit generation */
/* Repetition Count Test */
- int rct_count; /* Number of stuck values */
+ unsigned int rct_count; /* Number of stuck values */
- /* Adaptive Proportion Test for a significance level of 2^-30 */
-#define JENT_APT_CUTOFF 325 /* Taken from SP800-90B sec 4.4.2 */
+ /* Adaptive Proportion Test cutoff values */
+ unsigned int apt_cutoff; /* Intermittent health test failure */
+ unsigned int apt_cutoff_permanent; /* Permanent health test failure */
#define JENT_APT_WINDOW_SIZE 512 /* Data window size */
/* LSB of time stamp to process */
#define JENT_APT_LSB 16
@@ -96,9 +100,9 @@ struct rand_data {
unsigned int apt_observations; /* Number of collected observations */
unsigned int apt_count; /* APT counter */
unsigned int apt_base; /* APT base reference */
- unsigned int apt_base_set:1; /* APT base reference set? */
+ unsigned int health_failure; /* Record health failure */
- unsigned int health_failure:1; /* Permanent health failure */
+ unsigned int apt_base_set:1; /* APT base reference set? */
};
/* Flags that can be used to initialize the RNG */
@@ -115,8 +119,35 @@ struct rand_data {
* zero). */
#define JENT_ESTUCK 8 /* Too many stuck results during init. */
#define JENT_EHEALTH 9 /* Health test failed during initialization */
-#define JENT_ERCT 10 /* RCT failed during initialization */
+#define JENT_ERCT 10 /* RCT failed during initialization */
+#define JENT_EHASH 11 /* Hash self test failed */
+#define JENT_EMEM 12 /* Can't allocate memory for initialization */
+
+#define JENT_RCT_FAILURE 1 /* Failure in RCT health test. */
+#define JENT_APT_FAILURE 2 /* Failure in APT health test. */
+#define JENT_PERMANENT_FAILURE_SHIFT 16
+#define JENT_PERMANENT_FAILURE(x) (x << JENT_PERMANENT_FAILURE_SHIFT)
+#define JENT_RCT_FAILURE_PERMANENT JENT_PERMANENT_FAILURE(JENT_RCT_FAILURE)
+#define JENT_APT_FAILURE_PERMANENT JENT_PERMANENT_FAILURE(JENT_APT_FAILURE)
+
+/*
+ * The output n bits can receive more than n bits of min entropy, of course,
+ * but the fixed output of the conditioning function can only asymptotically
+ * approach the output size 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 JENT_ENTROPY_SAFETY_FACTOR 64
+#include <linux/array_size.h>
+#include <linux/fips.h>
+#include <linux/minmax.h>
#include "jitterentropy.h"
/***************************************************************************
@@ -125,7 +156,48 @@ struct rand_data {
* 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.
+ * https://www.untruth.org/~josh/sp80090b/UL%20SP800-90B-final%20comments%20v1.9%2020191212.pdf
+ * 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 the alpha < 2^-53, R cannot be used as it uses a float data type without
+ * arbitrary precision. A SageMath script is used to calculate those cutoff
+ * values.
+ *
+ * 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 };
+static const unsigned int jent_apt_cutoff_permanent_lookup[15] = {
+ 355, 447, 479, 494, 502, 507, 510, 512,
+ 512, 512, 512, 512, 512, 512, 512 };
+
+static 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];
+ ec->apt_cutoff_permanent = jent_apt_cutoff_permanent_lookup[
+ ARRAY_SIZE(jent_apt_cutoff_permanent_lookup) - 1];
+ } else {
+ ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1];
+ ec->apt_cutoff_permanent =
+ jent_apt_cutoff_permanent_lookup[osr - 1];
+ }
+}
+/*
* Reset the APT counter
*
* @ec [in] Reference to entropy collector
@@ -138,7 +210,7 @@ static void jent_apt_reset(struct rand_data *ec, unsigned int delta_masked)
ec->apt_observations = 0;
}
-/**
+/*
* Insert a new entropy event into APT
*
* @ec [in] Reference to entropy collector
@@ -156,8 +228,11 @@ static void jent_apt_insert(struct rand_data *ec, unsigned int delta_masked)
if (delta_masked == ec->apt_base) {
ec->apt_count++;
- if (ec->apt_count >= JENT_APT_CUTOFF)
- ec->health_failure = 1;
+ /* Note, ec->apt_count starts with one. */
+ if (ec->apt_count >= ec->apt_cutoff_permanent)
+ ec->health_failure |= JENT_APT_FAILURE_PERMANENT;
+ else if (ec->apt_count >= ec->apt_cutoff)
+ ec->health_failure |= JENT_APT_FAILURE;
}
ec->apt_observations++;
@@ -182,7 +257,7 @@ static void jent_apt_insert(struct rand_data *ec, unsigned int delta_masked)
* 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
@@ -190,55 +265,38 @@ static void jent_apt_insert(struct rand_data *ec, unsigned int delta_masked)
*/
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
+ * alpha = 2^-30 or 2^-60 as recommended in SP800-90B.
+ * 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 64 * OSR deltas for inserting them into
- * the entropy pool which should then have (close to) 64 bits
- * of 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.
+ * following SP800-90B. Thus C = ceil(-log_2(alpha)/H) = 30*osr
+ * or 60*osr.
*/
- if ((unsigned int)ec->rct_count >= (31 * ec->osr)) {
+ if ((unsigned int)ec->rct_count >= (60 * ec->osr)) {
+ ec->rct_count = -1;
+ ec->health_failure |= JENT_RCT_FAILURE_PERMANENT;
+ } else if ((unsigned int)ec->rct_count >= (30 * ec->osr)) {
ec->rct_count = -1;
- ec->health_failure = 1;
+ ec->health_failure |= JENT_RCT_FAILURE;
}
} else {
+ /* Reset RCT */
ec->rct_count = 0;
}
}
-/**
- * Is there an RCT health test failure?
- *
- * @ec [in] Reference to entropy collector
- *
- * @return
- * 0 No health test failure
- * 1 Permanent health test failure
- */
-static int jent_rct_failure(struct rand_data *ec)
-{
- if (ec->rct_count < 0)
- return 1;
- return 0;
-}
-
static inline __u64 jent_delta(__u64 prev, __u64 next)
{
#define JENT_UINT64_MAX (__u64)(~((__u64) 0))
@@ -246,7 +304,7 @@ static inline __u64 jent_delta(__u64 prev, __u64 next)
(JENT_UINT64_MAX - prev + 1 + next);
}
-/**
+/*
* Stuck test by checking the:
* 1st derivative of the jitter measurement (time delta)
* 2nd derivative of the jitter measurement (delta of time deltas)
@@ -265,7 +323,6 @@ static int jent_stuck(struct rand_data *ec, __u64 current_delta)
{
__u64 delta2 = jent_delta(ec->last_delta, current_delta);
__u64 delta3 = jent_delta(ec->last_delta2, delta2);
- unsigned int delta_masked = current_delta & JENT_APT_WORD_MASK;
ec->last_delta = current_delta;
ec->last_delta2 = delta2;
@@ -274,7 +331,7 @@ static int jent_stuck(struct rand_data *ec, __u64 current_delta)
* Insert the result of the comparison of two back-to-back time
* deltas.
*/
- jent_apt_insert(ec, delta_masked);
+ jent_apt_insert(ec, current_delta);
if (!current_delta || !delta2 || !delta3) {
/* RCT with a stuck bit */
@@ -288,19 +345,22 @@ static int jent_stuck(struct rand_data *ec, __u64 current_delta)
return 0;
}
-/**
+/*
* Report any health test failures
*
* @ec [in] Reference to entropy collector
*
- * @return
- * 0 No health test failure
- * 1 Permanent health test failure
+ * @return a bitmask indicating which tests failed
+ * 0 No health test failure
+ * 1 RCT failure
+ * 2 APT failure
+ * 1<<JENT_PERMANENT_FAILURE_SHIFT RCT permanent failure
+ * 2<<JENT_PERMANENT_FAILURE_SHIFT APT permanent failure
*/
-static int jent_health_failure(struct rand_data *ec)
+static unsigned int jent_health_failure(struct rand_data *ec)
{
/* Test is only enabled in FIPS mode */
- if (!jent_fips_enabled())
+ if (!fips_enabled)
return 0;
return ec->health_failure;
@@ -310,20 +370,18 @@ static int jent_health_failure(struct rand_data *ec)
* Noise sources
***************************************************************************/
-/**
+/*
* 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 __u64 jent_loop_shuffle(struct rand_data *ec,
- unsigned int bits, unsigned int min)
+static __u64 jent_loop_shuffle(unsigned int bits, unsigned int min)
{
__u64 time = 0;
__u64 shuffle = 0;
@@ -331,12 +389,7 @@ static __u64 jent_loop_shuffle(struct rand_data *ec,
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.
@@ -353,89 +406,40 @@ static __u64 jent_loop_shuffle(struct rand_data *ec,
return (shuffle + (1<<min));
}
-/**
+/*
* 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.
+ * entropy pool using a hash.
*
- * 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.
- *
- * @ec [in] entropy collector struct
- * @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 folding
- * @stuck [in] Is the time stamp identified as stuck?
+ * ec [in] entropy collector
+ * time [in] time stamp to be injected
+ * stuck [in] Is the time stamp identified as stuck?
*
* Output:
- * updated ec->data
- *
- * @return Number of loops the folding operation is performed
+ * updated hash context in the entropy collector or error code
*/
-static void jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt,
- int stuck)
+static int jent_condition_data(struct rand_data *ec, __u64 time, int stuck)
{
- unsigned int i;
- __u64 j = 0;
- __u64 new = 0;
-#define MAX_FOLD_LOOP_BIT 4
-#define MIN_FOLD_LOOP_BIT 0
- __u64 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++) {
- __u64 tmp = time << (DATA_SIZE_BITS - i);
-
- tmp = tmp >> (DATA_SIZE_BITS - 1);
-
- /*
- * 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.
- */
- tmp ^= ((new >> 63) & 1);
- tmp ^= ((new >> 60) & 1);
- tmp ^= ((new >> 55) & 1);
- tmp ^= ((new >> 30) & 1);
- tmp ^= ((new >> 27) & 1);
- tmp ^= ((new >> 22) & 1);
- new <<= 1;
- new ^= tmp;
- }
- }
-
- /*
- * 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 (SP800-90B considers the LFSR to be a
- * conditioning operation) to have an identical amount of input
- * data according to section 3.1.5.
- */
- if (!stuck)
- ec->data = new;
+#define SHA3_HASH_LOOP (1<<3)
+ struct {
+ int rct_count;
+ unsigned int apt_observations;
+ unsigned int apt_count;
+ unsigned int apt_base;
+ } addtl = {
+ ec->rct_count,
+ ec->apt_observations,
+ ec->apt_count,
+ ec->apt_base
+ };
+
+ return jent_hash_time(ec->hash_state, time, (u8 *)&addtl, sizeof(addtl),
+ SHA3_HASH_LOOP, stuck);
}
-/**
+/*
* Memory Access noise source -- this is a noise source based on variations in
* memory access times
*
@@ -466,7 +470,7 @@ static void jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
#define MAX_ACC_LOOP_BIT 7
#define MIN_ACC_LOOP_BIT 0
__u64 acc_loop_cnt =
- jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT);
+ jent_loop_shuffle(MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT);
if (NULL == ec || NULL == ec->mem)
return;
@@ -500,7 +504,7 @@ static void jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
/***************************************************************************
* 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.
@@ -513,7 +517,7 @@ static void jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
*
* @return result of stuck test
*/
-static int jent_measure_jitter(struct rand_data *ec)
+static int jent_measure_jitter(struct rand_data *ec, __u64 *ret_current_delta)
{
__u64 time = 0;
__u64 current_delta = 0;
@@ -534,39 +538,47 @@ static int jent_measure_jitter(struct rand_data *ec)
stuck = jent_stuck(ec, current_delta);
/* Now call the next noise sources which also injects the data */
- jent_lfsr_time(ec, current_delta, 0, stuck);
+ if (jent_condition_data(ec, current_delta, stuck))
+ stuck = 1;
+
+ /* return the raw entropy value */
+ if (ret_current_delta)
+ *ret_current_delta = current_delta;
return stuck;
}
-/**
+/*
* Generator of one 64 bit random number
- * Function fills rand_data->data
+ * Function fills rand_data->hash_state
*
* @ec [in] Reference to entropy collector
*/
static void jent_gen_entropy(struct rand_data *ec)
{
- unsigned int k = 0;
+ unsigned int k = 0, safety_factor = 0;
+
+ if (fips_enabled)
+ safety_factor = JENT_ENTROPY_SAFETY_FACTOR;
/* priming of the ->prev_time value */
- jent_measure_jitter(ec);
+ jent_measure_jitter(ec, NULL);
- while (1) {
+ while (!jent_health_failure(ec)) {
/* If a stuck measurement is received, repeat measurement */
- if (jent_measure_jitter(ec))
+ if (jent_measure_jitter(ec, NULL))
continue;
/*
* We multiply the loop value with ->osr to obtain the
* oversampling rate requested by the caller
*/
- if (++k >= (DATA_SIZE_BITS * ec->osr))
+ if (++k >= ((DATA_SIZE_BITS + safety_factor) * ec->osr))
break;
}
}
-/**
+/*
* Entry function: Obtain entropy for the caller.
*
* This function invokes the entropy gathering logic as often to generate
@@ -585,9 +597,9 @@ static void jent_gen_entropy(struct rand_data *ec)
* @return 0 when request is fulfilled or an error
*
* The following error codes can occur:
- * -1 entropy_collector is NULL
- * -2 RCT failed
- * -3 APT test failed
+ * -1 entropy_collector is NULL or the generation failed
+ * -2 Intermittent health failure
+ * -3 Permanent health failure
*/
int jent_read_entropy(struct rand_data *ec, unsigned char *data,
unsigned int len)
@@ -598,50 +610,38 @@ int jent_read_entropy(struct rand_data *ec, unsigned char *data,
return -1;
while (len > 0) {
- unsigned int tocopy;
+ unsigned int tocopy, health_test_result;
jent_gen_entropy(ec);
- if (jent_health_failure(ec)) {
- int ret;
-
- if (jent_rct_failure(ec))
- ret = -2;
- else
- ret = -3;
-
+ health_test_result = jent_health_failure(ec);
+ if (health_test_result > JENT_PERMANENT_FAILURE_SHIFT) {
/*
- * Re-initialize the noise source
- *
- * If the health test fails, the Jitter RNG remains
- * in failure state and will return a health failure
- * during next invocation.
+ * At this point, the Jitter RNG instance is considered
+ * as a failed instance. There is no rerun of the
+ * startup test any more, because the caller
+ * is assumed to not further use this instance.
*/
- if (jent_entropy_init())
- return ret;
-
- /* Set APT to initial state */
- jent_apt_reset(ec, 0);
- ec->apt_base_set = 0;
-
- /* Set RCT to initial state */
- ec->rct_count = 0;
-
- /* Re-enable Jitter RNG */
- ec->health_failure = 0;
-
+ return -3;
+ } else if (health_test_result) {
/*
- * Return the health test failure status to the
- * caller as the generated value is not appropriate.
+ * Perform startup health tests and return permanent
+ * error if it fails.
*/
- return ret;
+ if (jent_entropy_init(0, 0, NULL, ec)) {
+ /* Mark the permanent error */
+ ec->health_failure &=
+ JENT_RCT_FAILURE_PERMANENT |
+ JENT_APT_FAILURE_PERMANENT;
+ return -3;
+ }
+
+ return -2;
}
- if ((DATA_SIZE_BITS / 8) < len)
- tocopy = (DATA_SIZE_BITS / 8);
- else
- tocopy = len;
- jent_memcpy(p, &ec->data, tocopy);
+ tocopy = min(DATA_SIZE_BITS / 8, len);
+ if (jent_read_random_block(ec->hash_state, p, tocopy))
+ return -1;
len -= tocopy;
p += tocopy;
@@ -655,7 +655,8 @@ int jent_read_entropy(struct rand_data *ec, unsigned char *data,
***************************************************************************/
struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
- unsigned int flags)
+ unsigned int flags,
+ void *hash_state)
{
struct rand_data *entropy_collector;
@@ -667,20 +668,28 @@ struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
/* Allocate memory for adding variations based on memory
* access
*/
- entropy_collector->mem = jent_zalloc(JENT_MEMORY_SIZE);
+ entropy_collector->mem = jent_kvzalloc(JENT_MEMORY_SIZE);
if (!entropy_collector->mem) {
jent_zfree(entropy_collector);
return NULL;
}
- entropy_collector->memblocksize = JENT_MEMORY_BLOCKSIZE;
- entropy_collector->memblocks = JENT_MEMORY_BLOCKS;
+ entropy_collector->memblocksize =
+ CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE;
+ entropy_collector->memblocks =
+ CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS;
entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS;
}
/* verify and set the oversampling rate */
if (osr == 0)
- osr = 1; /* minimum sampling rate is 1 */
+ osr = 1; /* H_submitter = 1 / osr */
entropy_collector->osr = osr;
+ entropy_collector->flags = flags;
+
+ entropy_collector->hash_state = hash_state;
+
+ /* Initialize the APT */
+ jent_apt_init(entropy_collector, osr);
/* fill the data pad with non-zero values */
jent_gen_entropy(entropy_collector);
@@ -690,24 +699,39 @@ struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
void jent_entropy_collector_free(struct rand_data *entropy_collector)
{
- jent_zfree(entropy_collector->mem);
+ jent_kvzfree(entropy_collector->mem, JENT_MEMORY_SIZE);
entropy_collector->mem = NULL;
jent_zfree(entropy_collector);
}
-int jent_entropy_init(void)
+int jent_entropy_init(unsigned int osr, unsigned int flags, void *hash_state,
+ struct rand_data *p_ec)
{
- int i;
- __u64 delta_sum = 0;
- __u64 old_delta = 0;
- unsigned int nonstuck = 0;
- int time_backwards = 0;
- int count_mod = 0;
- int count_stuck = 0;
- struct rand_data ec = { 0 };
-
- /* Required for RCT */
- ec.osr = 1;
+ /*
+ * If caller provides an allocated ec, reuse it which implies that the
+ * health test entropy data is used to further still the available
+ * entropy pool.
+ */
+ struct rand_data *ec = p_ec;
+ int i, time_backwards = 0, ret = 0, ec_free = 0;
+ unsigned int health_test_result;
+
+ if (!ec) {
+ ec = jent_entropy_collector_alloc(osr, flags, hash_state);
+ if (!ec)
+ return JENT_EMEM;
+ ec_free = 1;
+ } else {
+ /* Reset the APT */
+ jent_apt_reset(ec, 0);
+ /* Ensure that a new APT base is obtained */
+ ec->apt_base_set = 0;
+ /* Reset the RCT */
+ ec->rct_count = 0;
+ /* Reset intermittent, leave permanent health test result */
+ ec->health_failure &= (~JENT_RCT_FAILURE);
+ ec->health_failure &= (~JENT_APT_FAILURE);
+ }
/* We could perform statistical tests here, but the problem is
* that we only have a few loop counts to do testing. These
@@ -736,31 +760,28 @@ int jent_entropy_init(void)
#define TESTLOOPCOUNT 1024
#define CLEARCACHE 100
for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) {
- __u64 time = 0;
- __u64 time2 = 0;
- __u64 delta = 0;
- unsigned int lowdelta = 0;
- int stuck;
+ __u64 start_time = 0, end_time = 0, delta = 0;
/* Invoke core entropy collection logic */
- jent_get_nstime(&time);
- ec.prev_time = time;
- jent_lfsr_time(&ec, time, 0, 0);
- jent_get_nstime(&time2);
+ jent_measure_jitter(ec, &delta);
+ end_time = ec->prev_time;
+ start_time = ec->prev_time - delta;
/* test whether timer works */
- if (!time || !time2)
- return JENT_ENOTIME;
- delta = jent_delta(time, time2);
+ if (!start_time || !end_time) {
+ ret = JENT_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 JENT_ECOARSETIME;
-
- stuck = jent_stuck(&ec, delta);
+ if (!delta || (end_time == start_time)) {
+ ret = JENT_ECOARSETIME;
+ goto out;
+ }
/*
* up to here we did not modify any variable that will be
@@ -772,51 +793,9 @@ int jent_entropy_init(void)
if (i < CLEARCACHE)
continue;
- if (stuck)
- count_stuck++;
- else {
- nonstuck++;
-
- /*
- * Ensure that the APT succeeded.
- *
- * With the check below that count_stuck must be less
- * than 10% of the overall generated raw entropy values
- * it is guaranteed that the APT is invoked at
- * floor((TESTLOOPCOUNT * 0.9) / 64) == 14 times.
- */
- if ((nonstuck % JENT_APT_WINDOW_SIZE) == 0) {
- jent_apt_reset(&ec,
- delta & JENT_APT_WORD_MASK);
- if (jent_health_failure(&ec))
- return JENT_EHEALTH;
- }
- }
-
- /* Validate RCT */
- if (jent_rct_failure(&ec))
- return JENT_ERCT;
-
/* 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;
}
/*
@@ -826,31 +805,22 @@ int jent_entropy_init(void)
* should not fail. The value of 3 should cover the NTP case being
* performed during our test run.
*/
- if (time_backwards > 3)
- return JENT_ENOMONOTONIC;
-
- /*
- * 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 JENT_EVARVAR;
+ if (time_backwards > 3) {
+ ret = JENT_ENOMONOTONIC;
+ 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 JENT_ECOARSETIME;
+ /* Did we encounter a health test failure? */
+ health_test_result = jent_health_failure(ec);
+ if (health_test_result) {
+ ret = (health_test_result & JENT_RCT_FAILURE) ? JENT_ERCT :
+ JENT_EHEALTH;
+ goto out;
+ }
- /*
- * If we have more than 90% stuck results, then this Jitter RNG is
- * likely to not work well.
- */
- if ((TESTLOOPCOUNT/10 * 9) < count_stuck)
- return JENT_ESTUCK;
+out:
+ if (ec_free)
+ jent_entropy_collector_free(ec);
- return 0;
+ return ret;
}