Coverage Report

Created: 2022-12-08 06:10

/src/libgcrypt/random/jitterentropy-health.c
Line
Count
Source (jump to first uncovered line)
1
/* Jitter RNG: Health Tests
2
 *
3
 * Copyright (C) 2021, Joshua E. Hill <josh@keypair.us>
4
 * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de>
5
 *
6
 * License: see LICENSE file in root directory
7
 *
8
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
9
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
10
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
11
 * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
12
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
13
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
14
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
15
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
16
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
18
 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
19
 * DAMAGE.
20
 */
21
22
#include "jitterentropy.h"
23
#include "jitterentropy-health.h"
24
25
/***************************************************************************
26
 * Lag Predictor Test
27
 *
28
 * This test is a vendor-defined conditional test that is designed to detect
29
 * a known failure mode where the result becomes mostly deterministic
30
 * Note that (lag_observations & JENT_LAG_MASK) is the index where the next
31
 * value provided will be stored.
32
 ***************************************************************************/
33
34
#ifdef JENT_HEALTH_LAG_PREDICTOR
35
36
/*
37
 * These cutoffs are configured using an entropy estimate of 1/osr under an
38
 * alpha=2^(-22) for a window size of 131072. The other health tests use
39
 * alpha=2^-30, but operate on much smaller window sizes. This larger selection
40
 * of alpha makes the behavior per-lag-window similar to the APT test.
41
 *
42
 * The global cutoffs are calculated using the
43
 * InverseBinomialCDF(n=(JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE), p=2^(-1/osr); 1-alpha)
44
 * The local cutoffs are somewhat more complicated. For background, see Feller's
45
 * _Introduction to Probability Theory and It's Applications_ Vol. 1,
46
 * Chapter 13, section 7 (in particular see equation 7.11, where x is a root
47
 * of the denominator of equation 7.6).
48
 *
49
 * We'll proceed using the notation of SP 800-90B Section 6.3.8 (which is
50
 * developed in Kelsey-McKay-Turan paper "Predictive Models for Min-entropy
51
 * Estimation".)
52
 *
53
 * Here, we set p=2^(-1/osr), seeking a run of successful guesses (r) with
54
 * probability of less than (1-alpha). That is, it is very very likely
55
 * (probability 1-alpha) that there is _no_ run of length r in a block of size
56
 * JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE.
57
 *
58
 * We have to iteratively look for an appropriate value for the cutoff r.
59
 */
60
static const unsigned int jent_lag_global_cutoff_lookup[20] =
61
  { 66443,  93504, 104761, 110875, 114707, 117330, 119237, 120686, 121823,
62
   122739, 123493, 124124, 124660, 125120, 125520, 125871, 126181, 126457,
63
   126704, 126926 };
64
static const unsigned int jent_lag_local_cutoff_lookup[20] =
65
  {  38,  75, 111, 146, 181, 215, 250, 284, 318, 351,
66
    385, 419, 452, 485, 518, 551, 584, 617, 650, 683 };
67
68
void jent_lag_init(struct rand_data *ec, unsigned int osr)
69
0
{
70
  /*
71
   * Establish the lag global and local cutoffs based on the presumed
72
   * entropy rate of 1/osr.
73
   */
74
0
  if (osr > ARRAY_SIZE(jent_lag_global_cutoff_lookup)) {
75
0
    ec->lag_global_cutoff =
76
0
      jent_lag_global_cutoff_lookup[
77
0
        ARRAY_SIZE(jent_lag_global_cutoff_lookup) - 1];
78
0
  } else {
79
0
    ec->lag_global_cutoff = jent_lag_global_cutoff_lookup[osr - 1];
80
0
  }
81
82
0
  if (osr > ARRAY_SIZE(jent_lag_local_cutoff_lookup)) {
83
0
    ec->lag_local_cutoff =
84
0
      jent_lag_local_cutoff_lookup[
85
0
        ARRAY_SIZE(jent_lag_local_cutoff_lookup) - 1];
86
0
  } else {
87
0
    ec->lag_local_cutoff = jent_lag_local_cutoff_lookup[osr - 1];
88
0
  }
89
0
}
90
91
/**
92
 * Reset the lag counters
93
 *
94
 * @ec [in] Reference to entropy collector
95
 */
96
static void jent_lag_reset(struct rand_data *ec)
97
0
{
98
0
  unsigned int i;
99
100
  /* Reset Lag counters */
101
0
  ec->lag_prediction_success_count = 0;
102
0
  ec->lag_prediction_success_run = 0;
103
0
  ec->lag_best_predictor = 0; //The first guess is basically arbitrary.
104
0
  ec->lag_observations = 0;
105
106
0
  for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) {
107
0
    ec->lag_scoreboard[i] = 0;
108
0
    ec->lag_delta_history[i] = 0;
109
0
  }
110
0
}
111
112
/*
113
 * A macro for accessing the history. Index 0 is the last observed symbol
114
 * index 1 is the symbol observed two inputs ago, etc.
115
 */
116
#define JENT_LAG_HISTORY(EC,LOC)                 \
117
0
  ((EC)->lag_delta_history[((EC)->lag_observations - (LOC) - 1) &        \
118
0
   JENT_LAG_MASK])
119
120
/**
121
 * Insert a new entropy event into the lag predictor test
122
 *
123
 * @ec [in] Reference to entropy collector
124
 * @current_delta [in] Current time delta
125
 */
126
static void jent_lag_insert(struct rand_data *ec, uint64_t current_delta)
127
0
{
128
0
  uint64_t prediction;
129
0
  unsigned int i;
130
131
  /* Initialize the delta_history */
132
0
  if (ec->lag_observations < JENT_LAG_HISTORY_SIZE) {
133
0
    ec->lag_delta_history[ec->lag_observations] = current_delta;
134
0
    ec->lag_observations++;
135
0
    return;
136
0
  }
137
138
  /*
139
   * The history is initialized. First make a guess and examine the
140
   * results.
141
   */
142
0
  prediction = JENT_LAG_HISTORY(ec, ec->lag_best_predictor);
143
144
0
  if (prediction == current_delta) {
145
    /* The prediction was correct. */
146
0
    ec->lag_prediction_success_count++;
147
0
    ec->lag_prediction_success_run++;
148
149
0
    if ((ec->lag_prediction_success_run >= ec->lag_local_cutoff) ||
150
0
        (ec->lag_prediction_success_count >= ec->lag_global_cutoff))
151
0
      ec->health_failure |= JENT_LAG_FAILURE;
152
0
  } else {
153
    /* The prediction wasn't correct. End any run of successes.*/
154
0
    ec->lag_prediction_success_run = 0;
155
0
  }
156
157
  /* Now update the predictors using the current data. */
158
0
  for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) {
159
0
    if (JENT_LAG_HISTORY(ec, i) == current_delta) {
160
      /*
161
       * The ith predictor (which guesses i + 1 symbols in
162
       * the past) successfully guessed.
163
       */
164
0
      ec->lag_scoreboard[i] ++;
165
166
      /*
167
       * Keep track of the best predictor (tie goes to the
168
       * shortest lag)
169
       */
170
0
      if (ec->lag_scoreboard[i] >
171
0
          ec->lag_scoreboard[ec->lag_best_predictor])
172
0
        ec->lag_best_predictor = i;
173
0
    }
174
0
  }
175
176
  /*
177
   * Finally, update the lag_delta_history array with the newly input
178
   * value.
179
   */
180
0
  ec->lag_delta_history[(ec->lag_observations) & JENT_LAG_MASK] =
181
0
                current_delta;
182
0
  ec->lag_observations++;
183
184
  /*
185
   * lag_best_predictor now is the index of the predictor with the largest
186
   * number of correct guesses.
187
   * This establishes our next guess.
188
   */
189
190
  /* Do we now need a new window? */
191
0
  if (ec->lag_observations >= JENT_LAG_WINDOW_SIZE)
192
0
    jent_lag_reset(ec);
193
0
}
194
195
static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta)
196
0
{
197
  /* Note that delta2_n = delta_n - delta_{n-1} */
198
0
  return jent_delta(JENT_LAG_HISTORY(ec, 0), current_delta);
199
0
}
200
201
static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2)
202
0
{
203
  /*
204
   * Note that delta3_n = delta2_n - delta2_{n-1}
205
   *          = delta2_n - (delta_{n-1} - delta_{n-2})
206
   */
207
0
  return jent_delta(jent_delta(JENT_LAG_HISTORY(ec, 1),
208
0
             JENT_LAG_HISTORY(ec, 0)), delta2);
209
0
}
210
211
#else /* JENT_HEALTH_LAG_PREDICTOR */
212
213
static inline void jent_lag_insert(struct rand_data *ec, uint64_t current_delta)
214
{
215
  (void)ec;
216
  (void)current_delta;
217
}
218
219
static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta)
220
{
221
  uint64_t delta2 = jent_delta(ec->last_delta, current_delta);
222
223
  ec->last_delta = current_delta;
224
  return delta2;
225
}
226
227
static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2)
228
{
229
  uint64_t delta3 = jent_delta(ec->last_delta2, delta2);
230
231
  ec->last_delta2 = delta2;
232
  return delta3;
233
}
234
235
#endif /* JENT_HEALTH_LAG_PREDICTOR */
236
237
/***************************************************************************
238
 * Adaptive Proportion Test
239
 *
240
 * This test complies with SP800-90B section 4.4.2.
241
 ***************************************************************************/
242
243
/*
244
 * See the SP 800-90B comment #10b for the corrected cutoff for the SP 800-90B
245
 * APT.
246
 * http://www.untruth.org/~josh/sp80090b/UL%20SP800-90B-final%20comments%20v1.9%2020191212.pdf
247
 * In in the syntax of R, this is C = 2 + qbinom(1 - 2^(-30), 511, 2^(-1/osr)).
248
 * (The original formula wasn't correct because the first symbol must
249
 * necessarily have been observed, so there is no chance of observing 0 of these
250
 * symbols.)
251
 *
252
 * For any value above 14, this yields the maximal allowable value of 512
253
 * (by FIPS 140-2 IG 7.19 Resolution # 16, we cannot choose a cutoff value that
254
 * renders the test unable to fail).
255
 */
256
static const unsigned int jent_apt_cutoff_lookup[15]=
257
  { 325, 422, 459, 477, 488, 494, 499, 502,
258
    505, 507, 508, 509, 510, 511, 512 };
259
260
void jent_apt_init(struct rand_data *ec, unsigned int osr)
261
0
{
262
  /*
263
   * Establish the apt_cutoff based on the presumed entropy rate of
264
   * 1/osr.
265
   */
266
0
  if (osr >= ARRAY_SIZE(jent_apt_cutoff_lookup)) {
267
0
    ec->apt_cutoff = jent_apt_cutoff_lookup[
268
0
          ARRAY_SIZE(jent_apt_cutoff_lookup) - 1];
269
0
  } else {
270
0
    ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1];
271
0
  }
272
0
}
273
274
/**
275
 * Reset the APT counter
276
 *
277
 * @ec [in] Reference to entropy collector
278
 */
279
static void jent_apt_reset(struct rand_data *ec)
280
0
{
281
  /* When reset, accept the _next_ value input as the new base. */
282
0
  ec->apt_base_set = 0;
283
0
}
284
285
/**
286
 * Insert a new entropy event into APT
287
 *
288
 * @ec [in] Reference to entropy collector
289
 * @current_delta [in] Current time delta
290
 */
291
static void jent_apt_insert(struct rand_data *ec, uint64_t current_delta)
292
0
{
293
  /* Initialize the base reference */
294
0
  if (!ec->apt_base_set) {
295
0
    ec->apt_base = current_delta; // APT Step 1
296
0
    ec->apt_base_set = 1;   // APT Step 2
297
298
    /*
299
     * Reset APT counter
300
     * Note that we've taken in the first symbol in the window.
301
     */
302
0
    ec->apt_count = 1;    // B = 1
303
0
    ec->apt_observations = 1;
304
305
0
    return;
306
0
  }
307
308
0
  if (current_delta == ec->apt_base) {
309
0
    ec->apt_count++;    // B = B + 1
310
311
    /* Note, ec->apt_count starts with one. */
312
0
    if (ec->apt_count >= ec->apt_cutoff)
313
0
      ec->health_failure |= JENT_APT_FAILURE;
314
0
  }
315
316
0
  ec->apt_observations++;
317
318
  /* Completed one window, the next symbol input will be new apt_base. */
319
0
  if (ec->apt_observations >= JENT_APT_WINDOW_SIZE)
320
0
    jent_apt_reset(ec);   // APT Step 4
321
0
}
322
323
/***************************************************************************
324
 * Stuck Test and its use as Repetition Count Test
325
 *
326
 * The Jitter RNG uses an enhanced version of the Repetition Count Test
327
 * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical
328
 * back-to-back values, the input to the RCT is the counting of the stuck
329
 * values during the generation of one Jitter RNG output block.
330
 *
331
 * The RCT is applied with an alpha of 2^{-30} compliant to FIPS 140-2 IG 9.8.
332
 *
333
 * During the counting operation, the Jitter RNG always calculates the RCT
334
 * cut-off value of C. If that value exceeds the allowed cut-off value,
335
 * the Jitter RNG output block will be calculated completely but discarded at
336
 * the end. The caller of the Jitter RNG is informed with an error code.
337
 ***************************************************************************/
338
339
/**
340
 * Repetition Count Test as defined in SP800-90B section 4.4.1
341
 *
342
 * @ec [in] Reference to entropy collector
343
 * @stuck [in] Indicator whether the value is stuck
344
 */
345
static void jent_rct_insert(struct rand_data *ec, int stuck)
346
0
{
347
  /*
348
   * If we have a count less than zero, a previous RCT round identified
349
   * a failure. We will not overwrite it.
350
   */
351
0
  if (ec->rct_count < 0)
352
0
    return;
353
354
0
  if (stuck) {
355
0
    ec->rct_count++;
356
357
    /*
358
     * The cutoff value is based on the following consideration:
359
     * alpha = 2^-30 as recommended in FIPS 140-2 IG 9.8.
360
     * In addition, we require an entropy value H of 1/osr as this
361
     * is the minimum entropy required to provide full entropy.
362
     * Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr
363
     * deltas for inserting them into the entropy pool which should
364
     * then have (close to) DATA_SIZE_BITS bits of entropy in the
365
     * conditioned output.
366
     *
367
     * Note, ec->rct_count (which equals to value B in the pseudo
368
     * code of SP800-90B section 4.4.1) starts with zero. Hence
369
     * we need to subtract one from the cutoff value as calculated
370
     * following SP800-90B. Thus C = ceil(-log_2(alpha)/H) = 30*osr.
371
     */
372
0
    if ((unsigned int)ec->rct_count >= (30 * ec->osr)) {
373
0
      ec->rct_count = -1;
374
0
      ec->health_failure |= JENT_RCT_FAILURE;
375
0
    }
376
0
  } else {
377
0
    ec->rct_count = 0;
378
0
  }
379
0
}
380
381
/**
382
 * Stuck test by checking the:
383
 *  1st derivative of the jitter measurement (time delta)
384
 *  2nd derivative of the jitter measurement (delta of time deltas)
385
 *  3rd derivative of the jitter measurement (delta of delta of time deltas)
386
 *
387
 * All values must always be non-zero.
388
 *
389
 * @ec [in] Reference to entropy collector
390
 * @current_delta [in] Jitter time delta
391
 *
392
 * @return
393
 *  0 jitter measurement not stuck (good bit)
394
 *  1 jitter measurement stuck (reject bit)
395
 */
396
unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta)
397
0
{
398
0
  uint64_t delta2 = jent_delta2(ec, current_delta);
399
0
  uint64_t delta3 = jent_delta3(ec, delta2);
400
401
  /*
402
   * Insert the result of the comparison of two back-to-back time
403
   * deltas.
404
   */
405
0
  jent_apt_insert(ec, current_delta);
406
0
  jent_lag_insert(ec, current_delta);
407
408
0
  if (!current_delta || !delta2 || !delta3) {
409
    /* RCT with a stuck bit */
410
0
    jent_rct_insert(ec, 1);
411
0
    return 1;
412
0
  }
413
414
  /* RCT with a non-stuck bit */
415
0
  jent_rct_insert(ec, 0);
416
417
0
  return 0;
418
0
}
419
420
/**
421
 * Report any health test failures
422
 *
423
 * @ec [in] Reference to entropy collector
424
 *
425
 * @return a bitmask indicating which tests failed
426
 *  0 No health test failure
427
 *  1 RCT failure
428
 *  2 APT failure
429
 *  4 Lag predictor test failure
430
 */
431
unsigned int jent_health_failure(struct rand_data *ec)
432
0
{
433
  /* Test is only enabled in FIPS mode */
434
0
  if (!ec->fips_enabled)
435
0
    return 0;
436
437
0
  return ec->health_failure;
438
0
}