1 From 04597c8dd6c4b55e946fec50dc3b14a5d9d54501 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Stephan=20M=C3=BCller?= <smueller@chronox.de>
3 Date: Thu, 21 Sep 2023 13:48:11 +0200
4 Subject: [PATCH] crypto: jitter - add RCT/APT support for different OSRs
6 The oversampling rate (OSR) value specifies the heuristically implied
7 entropy in the recorded data - H_submitter = 1/osr. A different entropy
8 estimate implies a different APT/RCT cutoff value. This change adds
9 support for OSRs 1 through 15. This OSR can be selected by the caller
12 For this patch, the caller still uses one hard-coded OSR. A subsequent
13 patch allows this value to be configured.
15 In addition, the power-up self test is adjusted as follows:
17 * It allows the caller to provide an oversampling rate that should be
18 tested with - commonly it should be the same as used for the actual
19 runtime operation. This makes the power-up testing therefore consistent
20 with the runtime operation.
22 * It calls now jent_measure_jitter (i.e. collects the full entropy
23 that can possibly be harvested by the Jitter RNG) instead of only
24 jent_condition_data (which only returns the entropy harvested from
25 the conditioning component). This should now alleviate reports where
26 the Jitter RNG initialization thinks there is too little entropy.
28 * The power-up test now solely relies on the (enhanced) APT and RCT
29 test that is used as a health test at runtime.
31 The code allowing the different OSRs as well as the power-up test
32 changes are present in the user space version of the Jitter RNG 3.4.1
33 and thus was already in production use for some time.
35 Reported-by "Ospan, Abylay" <aospan@amazon.com>
36 Signed-off-by: Stephan Mueller <smueller@chronox.de>
37 Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
39 crypto/jitterentropy-kcapi.c | 4 +-
40 crypto/jitterentropy.c | 233 ++++++++++++++++++-----------------
41 crypto/jitterentropy.h | 3 +-
42 3 files changed, 123 insertions(+), 117 deletions(-)
44 --- a/crypto/jitterentropy-kcapi.c
45 +++ b/crypto/jitterentropy-kcapi.c
46 @@ -245,7 +245,7 @@ static int jent_kcapi_init(struct crypto
47 crypto_shash_init(sdesc);
50 - rng->entropy_collector = jent_entropy_collector_alloc(1, 0, sdesc);
51 + rng->entropy_collector = jent_entropy_collector_alloc(0, 0, sdesc);
52 if (!rng->entropy_collector) {
55 @@ -334,7 +334,7 @@ static int __init jent_mod_init(void)
58 crypto_shash_init(desc);
59 - ret = jent_entropy_init(desc);
60 + ret = jent_entropy_init(0, 0, desc);
61 shash_desc_zero(desc);
62 crypto_free_shash(tfm);
64 --- a/crypto/jitterentropy.c
65 +++ b/crypto/jitterentropy.c
66 @@ -72,6 +72,8 @@ struct rand_data {
67 __u64 prev_time; /* SENSITIVE Previous time stamp */
68 __u64 last_delta; /* SENSITIVE stuck test */
69 __s64 last_delta2; /* SENSITIVE stuck test */
71 + unsigned int flags; /* Flags used to initialize */
72 unsigned int osr; /* Oversample rate */
73 #define JENT_MEMORY_BLOCKS 64
74 #define JENT_MEMORY_BLOCKSIZE 32
75 @@ -88,16 +90,9 @@ struct rand_data {
76 /* Repetition Count Test */
77 unsigned int rct_count; /* Number of stuck values */
79 - /* Intermittent health test failure threshold of 2^-30 */
80 - /* From an SP800-90B perspective, this RCT cutoff value is equal to 31. */
81 - /* However, our RCT implementation starts at 1, so we subtract 1 here. */
82 -#define JENT_RCT_CUTOFF (31 - 1) /* Taken from SP800-90B sec 4.4.1 */
83 -#define JENT_APT_CUTOFF 325 /* Taken from SP800-90B sec 4.4.2 */
84 - /* Permanent health test failure threshold of 2^-60 */
85 - /* From an SP800-90B perspective, this RCT cutoff value is equal to 61. */
86 - /* However, our RCT implementation starts at 1, so we subtract 1 here. */
87 -#define JENT_RCT_CUTOFF_PERMANENT (61 - 1)
88 -#define JENT_APT_CUTOFF_PERMANENT 355
89 + /* Adaptive Proportion Test cutoff values */
90 + unsigned int apt_cutoff; /* Intermittent health test failure */
91 + unsigned int apt_cutoff_permanent; /* Permanent health test failure */
92 #define JENT_APT_WINDOW_SIZE 512 /* Data window size */
93 /* LSB of time stamp to process */
94 #define JENT_APT_LSB 16
95 @@ -122,6 +117,9 @@ struct rand_data {
97 #define JENT_ESTUCK 8 /* Too many stuck results during init. */
98 #define JENT_EHEALTH 9 /* Health test failed during initialization */
99 +#define JENT_ERCT 10 /* RCT failed during initialization */
100 +#define JENT_EHASH 11 /* Hash self test failed */
101 +#define JENT_EMEM 12 /* Can't allocate memory for initialization */
104 * The output n bits can receive more than n bits of min entropy, of course,
105 @@ -148,6 +146,48 @@ struct rand_data {
106 ***************************************************************************/
109 + * See the SP 800-90B comment #10b for the corrected cutoff for the SP 800-90B
111 + * http://www.untruth.org/~josh/sp80090b/UL%20SP800-90B-final%20comments%20v1.9%2020191212.pdf
112 + * In in the syntax of R, this is C = 2 + qbinom(1 − 2^(−30), 511, 2^(-1/osr)).
113 + * (The original formula wasn't correct because the first symbol must
114 + * necessarily have been observed, so there is no chance of observing 0 of these
117 + * For the alpha < 2^-53, R cannot be used as it uses a float data type without
118 + * arbitrary precision. A SageMath script is used to calculate those cutoff
121 + * For any value above 14, this yields the maximal allowable value of 512
122 + * (by FIPS 140-2 IG 7.19 Resolution # 16, we cannot choose a cutoff value that
123 + * renders the test unable to fail).
125 +static const unsigned int jent_apt_cutoff_lookup[15] = {
126 + 325, 422, 459, 477, 488, 494, 499, 502,
127 + 505, 507, 508, 509, 510, 511, 512 };
128 +static const unsigned int jent_apt_cutoff_permanent_lookup[15] = {
129 + 355, 447, 479, 494, 502, 507, 510, 512,
130 + 512, 512, 512, 512, 512, 512, 512 };
131 +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
133 +static void jent_apt_init(struct rand_data *ec, unsigned int osr)
136 + * Establish the apt_cutoff based on the presumed entropy rate of
139 + if (osr >= ARRAY_SIZE(jent_apt_cutoff_lookup)) {
140 + ec->apt_cutoff = jent_apt_cutoff_lookup[
141 + ARRAY_SIZE(jent_apt_cutoff_lookup) - 1];
142 + ec->apt_cutoff_permanent = jent_apt_cutoff_permanent_lookup[
143 + ARRAY_SIZE(jent_apt_cutoff_permanent_lookup) - 1];
145 + ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1];
146 + ec->apt_cutoff_permanent =
147 + jent_apt_cutoff_permanent_lookup[osr - 1];
151 * Reset the APT counter
153 * @ec [in] Reference to entropy collector
154 @@ -187,12 +227,12 @@ static void jent_apt_insert(struct rand_
155 /* APT health test failure detection */
156 static int jent_apt_permanent_failure(struct rand_data *ec)
158 - return (ec->apt_count >= JENT_APT_CUTOFF_PERMANENT) ? 1 : 0;
159 + return (ec->apt_count >= ec->apt_cutoff_permanent) ? 1 : 0;
162 static int jent_apt_failure(struct rand_data *ec)
164 - return (ec->apt_count >= JENT_APT_CUTOFF) ? 1 : 0;
165 + return (ec->apt_count >= ec->apt_cutoff) ? 1 : 0;
168 /***************************************************************************
169 @@ -275,15 +315,28 @@ static int jent_stuck(struct rand_data *
173 -/* RCT health test failure detection */
175 + * The cutoff value is based on the following consideration:
176 + * alpha = 2^-30 or 2^-60 as recommended in SP800-90B.
177 + * In addition, we require an entropy value H of 1/osr as this is the minimum
178 + * entropy required to provide full entropy.
179 + * Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr deltas for
180 + * inserting them into the entropy pool which should then have (close to)
181 + * DATA_SIZE_BITS bits of entropy in the conditioned output.
183 + * Note, ec->rct_count (which equals to value B in the pseudo code of SP800-90B
184 + * section 4.4.1) starts with zero. Hence we need to subtract one from the
185 + * cutoff value as calculated following SP800-90B. Thus
186 + * C = ceil(-log_2(alpha)/H) = 30*osr or 60*osr.
188 static int jent_rct_permanent_failure(struct rand_data *ec)
190 - return (ec->rct_count >= JENT_RCT_CUTOFF_PERMANENT) ? 1 : 0;
191 + return (ec->rct_count >= (60 * ec->osr)) ? 1 : 0;
194 static int jent_rct_failure(struct rand_data *ec)
196 - return (ec->rct_count >= JENT_RCT_CUTOFF) ? 1 : 0;
197 + return (ec->rct_count >= (30 * ec->osr)) ? 1 : 0;
200 /* Report of health test failures */
201 @@ -448,7 +501,7 @@ static void jent_memaccess(struct rand_d
203 * @return result of stuck test
205 -static int jent_measure_jitter(struct rand_data *ec)
206 +static int jent_measure_jitter(struct rand_data *ec, __u64 *ret_current_delta)
209 __u64 current_delta = 0;
210 @@ -472,6 +525,10 @@ static int jent_measure_jitter(struct ra
211 if (jent_condition_data(ec, current_delta, stuck))
214 + /* return the raw entropy value */
215 + if (ret_current_delta)
216 + *ret_current_delta = current_delta;
221 @@ -489,11 +546,11 @@ static void jent_gen_entropy(struct rand
222 safety_factor = JENT_ENTROPY_SAFETY_FACTOR;
224 /* priming of the ->prev_time value */
225 - jent_measure_jitter(ec);
226 + jent_measure_jitter(ec, NULL);
228 while (!jent_health_failure(ec)) {
229 /* If a stuck measurement is received, repeat measurement */
230 - if (jent_measure_jitter(ec))
231 + if (jent_measure_jitter(ec, NULL))
235 @@ -554,7 +611,8 @@ int jent_read_entropy(struct rand_data *
236 * Perform startup health tests and return permanent
239 - if (jent_entropy_init(ec->hash_state))
240 + if (jent_entropy_init(ec->osr, ec->flags,
245 @@ -604,11 +662,15 @@ struct rand_data *jent_entropy_collector
247 /* verify and set the oversampling rate */
249 - osr = 1; /* minimum sampling rate is 1 */
250 + osr = 1; /* H_submitter = 1 / osr */
251 entropy_collector->osr = osr;
252 + entropy_collector->flags = flags;
254 entropy_collector->hash_state = hash_state;
256 + /* Initialize the APT */
257 + jent_apt_init(entropy_collector, osr);
259 /* fill the data pad with non-zero values */
260 jent_gen_entropy(entropy_collector);
262 @@ -622,20 +684,14 @@ void jent_entropy_collector_free(struct
263 jent_zfree(entropy_collector);
266 -int jent_entropy_init(void *hash_state)
267 +int jent_entropy_init(unsigned int osr, unsigned int flags, void *hash_state)
270 - __u64 delta_sum = 0;
271 - __u64 old_delta = 0;
272 - unsigned int nonstuck = 0;
273 - int time_backwards = 0;
275 - int count_stuck = 0;
276 - struct rand_data ec = { 0 };
278 - /* Required for RCT */
280 - ec.hash_state = hash_state;
281 + struct rand_data *ec;
282 + int i, time_backwards = 0, ret = 0;
284 + ec = jent_entropy_collector_alloc(osr, flags, hash_state);
288 /* We could perform statistical tests here, but the problem is
289 * that we only have a few loop counts to do testing. These
290 @@ -664,31 +720,28 @@ int jent_entropy_init(void *hash_state)
291 #define TESTLOOPCOUNT 1024
292 #define CLEARCACHE 100
293 for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) {
297 - unsigned int lowdelta = 0;
299 + __u64 start_time = 0, end_time = 0, delta = 0;
301 /* Invoke core entropy collection logic */
302 - jent_get_nstime(&time);
303 - ec.prev_time = time;
304 - jent_condition_data(&ec, time, 0);
305 - jent_get_nstime(&time2);
306 + jent_measure_jitter(ec, &delta);
307 + end_time = ec->prev_time;
308 + start_time = ec->prev_time - delta;
310 /* test whether timer works */
311 - if (!time || !time2)
312 - return JENT_ENOTIME;
313 - delta = jent_delta(time, time2);
314 + if (!start_time || !end_time) {
315 + ret = JENT_ENOTIME;
320 * test whether timer is fine grained enough to provide
321 * delta even when called shortly after each other -- this
322 * implies that we also have a high resolution timer
325 - return JENT_ECOARSETIME;
327 - stuck = jent_stuck(&ec, delta);
328 + if (!delta || (end_time == start_time)) {
329 + ret = JENT_ECOARSETIME;
334 * up to here we did not modify any variable that will be
335 @@ -700,49 +753,9 @@ int jent_entropy_init(void *hash_state)
345 - * Ensure that the APT succeeded.
347 - * With the check below that count_stuck must be less
348 - * than 10% of the overall generated raw entropy values
349 - * it is guaranteed that the APT is invoked at
350 - * floor((TESTLOOPCOUNT * 0.9) / 64) == 14 times.
352 - if ((nonstuck % JENT_APT_WINDOW_SIZE) == 0) {
353 - jent_apt_reset(&ec,
354 - delta & JENT_APT_WORD_MASK);
358 - /* Validate health test result */
359 - if (jent_health_failure(&ec))
360 - return JENT_EHEALTH;
362 /* test whether we have an increasing timer */
363 - if (!(time2 > time))
364 + if (!(end_time > start_time))
367 - /* use 32 bit value to ensure compilation on 32 bit arches */
368 - lowdelta = time2 - time;
369 - if (!(lowdelta % 100))
373 - * ensure that we have a varying delta timer which is necessary
374 - * for the calculation of entropy -- perform this check
375 - * only after the first loop is executed as we need to prime
376 - * the old_data value
378 - if (delta > old_delta)
379 - delta_sum += (delta - old_delta);
381 - delta_sum += (old_delta - delta);
386 @@ -752,31 +765,23 @@ int jent_entropy_init(void *hash_state)
387 * should not fail. The value of 3 should cover the NTP case being
388 * performed during our test run.
390 - if (time_backwards > 3)
391 - return JENT_ENOMONOTONIC;
394 - * Variations of deltas of time must on average be larger
395 - * than 1 to ensure the entropy estimation
396 - * implied with 1 is preserved
398 - if ((delta_sum) <= 1)
399 - return JENT_EVARVAR;
400 + if (time_backwards > 3) {
401 + ret = JENT_ENOMONOTONIC;
406 - * Ensure that we have variations in the time stamp below 10 for at
407 - * least 10% of all checks -- on some platforms, the counter increments
408 - * in multiples of 100, but not always
410 - if ((TESTLOOPCOUNT/10 * 9) < count_mod)
411 - return JENT_ECOARSETIME;
412 + /* Did we encounter a health test failure? */
413 + if (jent_rct_failure(ec)) {
417 + if (jent_apt_failure(ec)) {
418 + ret = JENT_EHEALTH;
423 - * If we have more than 90% stuck results, then this Jitter RNG is
424 - * likely to not work well.
426 - if ((TESTLOOPCOUNT/10 * 9) < count_stuck)
427 - return JENT_ESTUCK;
429 + jent_entropy_collector_free(ec);
434 --- a/crypto/jitterentropy.h
435 +++ b/crypto/jitterentropy.h
436 @@ -9,7 +9,8 @@ extern int jent_hash_time(void *hash_sta
437 int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len);
440 -extern int jent_entropy_init(void *hash_state);
441 +extern int jent_entropy_init(unsigned int osr, unsigned int flags,
443 extern int jent_read_entropy(struct rand_data *ec, unsigned char *data,