]> git.ipfire.org Git - thirdparty/openwrt.git/blob
d0ae1258f86d23c99c2189c561abe4735ad6e66b
[thirdparty/openwrt.git] /
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
5
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
10 of the Jitter RNG.
11
12 For this patch, the caller still uses one hard-coded OSR. A subsequent
13 patch allows this value to be configured.
14
15 In addition, the power-up self test is adjusted as follows:
16
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.
21
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.
27
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.
30
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.
34
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>
38 ---
39 crypto/jitterentropy-kcapi.c | 4 +-
40 crypto/jitterentropy.c | 233 ++++++++++++++++++-----------------
41 crypto/jitterentropy.h | 3 +-
42 3 files changed, 123 insertions(+), 117 deletions(-)
43
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);
48 rng->sdesc = sdesc;
49
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) {
53 ret = -ENOMEM;
54 goto err;
55 @@ -334,7 +334,7 @@ static int __init jent_mod_init(void)
56
57 desc->tfm = tfm;
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);
63 if (ret) {
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 */
70 +
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 */
78
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 {
96 * zero). */
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 */
102
103 /*
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 ***************************************************************************/
107
108 /*
109 + * See the SP 800-90B comment #10b for the corrected cutoff for the SP 800-90B
110 + * APT.
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
115 + * symbols.)
116 + *
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
119 + * values.
120 + *
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).
124 + */
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]))
132 +
133 +static void jent_apt_init(struct rand_data *ec, unsigned int osr)
134 +{
135 + /*
136 + * Establish the apt_cutoff based on the presumed entropy rate of
137 + * 1/osr.
138 + */
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];
144 + } else {
145 + ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1];
146 + ec->apt_cutoff_permanent =
147 + jent_apt_cutoff_permanent_lookup[osr - 1];
148 + }
149 +}
150 +/*
151 * Reset the APT counter
152 *
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)
157 {
158 - return (ec->apt_count >= JENT_APT_CUTOFF_PERMANENT) ? 1 : 0;
159 + return (ec->apt_count >= ec->apt_cutoff_permanent) ? 1 : 0;
160 }
161
162 static int jent_apt_failure(struct rand_data *ec)
163 {
164 - return (ec->apt_count >= JENT_APT_CUTOFF) ? 1 : 0;
165 + return (ec->apt_count >= ec->apt_cutoff) ? 1 : 0;
166 }
167
168 /***************************************************************************
169 @@ -275,15 +315,28 @@ static int jent_stuck(struct rand_data *
170 return 0;
171 }
172
173 -/* RCT health test failure detection */
174 +/*
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.
182 + *
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.
187 + */
188 static int jent_rct_permanent_failure(struct rand_data *ec)
189 {
190 - return (ec->rct_count >= JENT_RCT_CUTOFF_PERMANENT) ? 1 : 0;
191 + return (ec->rct_count >= (60 * ec->osr)) ? 1 : 0;
192 }
193
194 static int jent_rct_failure(struct rand_data *ec)
195 {
196 - return (ec->rct_count >= JENT_RCT_CUTOFF) ? 1 : 0;
197 + return (ec->rct_count >= (30 * ec->osr)) ? 1 : 0;
198 }
199
200 /* Report of health test failures */
201 @@ -448,7 +501,7 @@ static void jent_memaccess(struct rand_d
202 *
203 * @return result of stuck test
204 */
205 -static int jent_measure_jitter(struct rand_data *ec)
206 +static int jent_measure_jitter(struct rand_data *ec, __u64 *ret_current_delta)
207 {
208 __u64 time = 0;
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))
212 stuck = 1;
213
214 + /* return the raw entropy value */
215 + if (ret_current_delta)
216 + *ret_current_delta = current_delta;
217 +
218 return stuck;
219 }
220
221 @@ -489,11 +546,11 @@ static void jent_gen_entropy(struct rand
222 safety_factor = JENT_ENTROPY_SAFETY_FACTOR;
223
224 /* priming of the ->prev_time value */
225 - jent_measure_jitter(ec);
226 + jent_measure_jitter(ec, NULL);
227
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))
232 continue;
233
234 /*
235 @@ -554,7 +611,8 @@ int jent_read_entropy(struct rand_data *
236 * Perform startup health tests and return permanent
237 * error if it fails.
238 */
239 - if (jent_entropy_init(ec->hash_state))
240 + if (jent_entropy_init(ec->osr, ec->flags,
241 + ec->hash_state))
242 return -3;
243
244 return -2;
245 @@ -604,11 +662,15 @@ struct rand_data *jent_entropy_collector
246
247 /* verify and set the oversampling rate */
248 if (osr == 0)
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;
253
254 entropy_collector->hash_state = hash_state;
255
256 + /* Initialize the APT */
257 + jent_apt_init(entropy_collector, osr);
258 +
259 /* fill the data pad with non-zero values */
260 jent_gen_entropy(entropy_collector);
261
262 @@ -622,20 +684,14 @@ void jent_entropy_collector_free(struct
263 jent_zfree(entropy_collector);
264 }
265
266 -int jent_entropy_init(void *hash_state)
267 +int jent_entropy_init(unsigned int osr, unsigned int flags, void *hash_state)
268 {
269 - int i;
270 - __u64 delta_sum = 0;
271 - __u64 old_delta = 0;
272 - unsigned int nonstuck = 0;
273 - int time_backwards = 0;
274 - int count_mod = 0;
275 - int count_stuck = 0;
276 - struct rand_data ec = { 0 };
277 -
278 - /* Required for RCT */
279 - ec.osr = 1;
280 - ec.hash_state = hash_state;
281 + struct rand_data *ec;
282 + int i, time_backwards = 0, ret = 0;
283 +
284 + ec = jent_entropy_collector_alloc(osr, flags, hash_state);
285 + if (!ec)
286 + return JENT_EMEM;
287
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++) {
294 - __u64 time = 0;
295 - __u64 time2 = 0;
296 - __u64 delta = 0;
297 - unsigned int lowdelta = 0;
298 - int stuck;
299 + __u64 start_time = 0, end_time = 0, delta = 0;
300
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;
309
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;
316 + goto out;
317 + }
318 +
319 /*
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
323 */
324 - if (!delta)
325 - return JENT_ECOARSETIME;
326 -
327 - stuck = jent_stuck(&ec, delta);
328 + if (!delta || (end_time == start_time)) {
329 + ret = JENT_ECOARSETIME;
330 + goto out;
331 + }
332
333 /*
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)
336 if (i < CLEARCACHE)
337 continue;
338
339 - if (stuck)
340 - count_stuck++;
341 - else {
342 - nonstuck++;
343 -
344 - /*
345 - * Ensure that the APT succeeded.
346 - *
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.
351 - */
352 - if ((nonstuck % JENT_APT_WINDOW_SIZE) == 0) {
353 - jent_apt_reset(&ec,
354 - delta & JENT_APT_WORD_MASK);
355 - }
356 - }
357 -
358 - /* Validate health test result */
359 - if (jent_health_failure(&ec))
360 - return JENT_EHEALTH;
361 -
362 /* test whether we have an increasing timer */
363 - if (!(time2 > time))
364 + if (!(end_time > start_time))
365 time_backwards++;
366 -
367 - /* use 32 bit value to ensure compilation on 32 bit arches */
368 - lowdelta = time2 - time;
369 - if (!(lowdelta % 100))
370 - count_mod++;
371 -
372 - /*
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
377 - */
378 - if (delta > old_delta)
379 - delta_sum += (delta - old_delta);
380 - else
381 - delta_sum += (old_delta - delta);
382 - old_delta = delta;
383 }
384
385 /*
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.
389 */
390 - if (time_backwards > 3)
391 - return JENT_ENOMONOTONIC;
392 -
393 - /*
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
397 - */
398 - if ((delta_sum) <= 1)
399 - return JENT_EVARVAR;
400 + if (time_backwards > 3) {
401 + ret = JENT_ENOMONOTONIC;
402 + goto out;
403 + }
404
405 - /*
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
409 - */
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)) {
414 + ret = JENT_ERCT;
415 + goto out;
416 + }
417 + if (jent_apt_failure(ec)) {
418 + ret = JENT_EHEALTH;
419 + goto out;
420 + }
421
422 - /*
423 - * If we have more than 90% stuck results, then this Jitter RNG is
424 - * likely to not work well.
425 - */
426 - if ((TESTLOOPCOUNT/10 * 9) < count_stuck)
427 - return JENT_ESTUCK;
428 +out:
429 + jent_entropy_collector_free(ec);
430
431 - return 0;
432 + return ret;
433 }
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);
438
439 struct rand_data;
440 -extern int jent_entropy_init(void *hash_state);
441 +extern int jent_entropy_init(unsigned int osr, unsigned int flags,
442 + void *hash_state);
443 extern int jent_read_entropy(struct rand_data *ec, unsigned char *data,
444 unsigned int len);
445