Coverage Report

Created: 2022-12-08 06:09

/src/libgcrypt/random/jitterentropy-noise.c
Line
Count
Source (jump to first uncovered line)
1
/* Jitter RNG: Noise Sources
2
 *
3
 * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de>
4
 *
5
 * License: see LICENSE file in root directory
6
 *
7
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
8
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
9
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
10
 * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
11
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
12
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
13
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
14
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
15
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
16
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
17
 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
18
 * DAMAGE.
19
 */
20
21
#include "jitterentropy-noise.h"
22
#include "jitterentropy-health.h"
23
#include "jitterentropy-timer.h"
24
#include "jitterentropy-sha3.h"
25
26
0
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
27
28
/***************************************************************************
29
 * Noise sources
30
 ***************************************************************************/
31
32
/**
33
 * Update of the loop count used for the next round of
34
 * an entropy collection.
35
 *
36
 * @ec [in] entropy collector struct -- may be NULL
37
 * @bits [in] is the number of low bits of the timer to consider
38
 * @min [in] is the number of bits we shift the timer value to the right at
39
 *       the end to make sure we have a guaranteed minimum value
40
 *
41
 * @return Newly calculated loop counter
42
 */
43
static uint64_t jent_loop_shuffle(struct rand_data *ec,
44
          unsigned int bits, unsigned int min)
45
0
{
46
0
#ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE
47
48
0
  (void)ec;
49
0
  (void)bits;
50
51
0
  return (UINT64_C(1)<<min);
52
53
#else /* JENT_CONF_DISABLE_LOOP_SHUFFLE */
54
55
  uint64_t time = 0;
56
  uint64_t shuffle = 0;
57
  uint64_t mask = (UINT64_C(1)<<bits) - 1;
58
  unsigned int i = 0;
59
60
  /*
61
   * Mix the current state of the random number into the shuffle
62
   * calculation to balance that shuffle a bit more.
63
   */
64
  if (ec) {
65
    jent_get_nstime_internal(ec, &time);
66
    time ^= ec->data[0];
67
  }
68
69
  /*
70
   * We fold the time value as much as possible to ensure that as many
71
   * bits of the time stamp are included as possible.
72
   */
73
  for (i = 0; ((DATA_SIZE_BITS + bits - 1) / bits) > i; i++) {
74
    shuffle ^= time & mask;
75
    time = time >> bits;
76
  }
77
78
  /*
79
   * We add a lower boundary value to ensure we have a minimum
80
   * RNG loop count.
81
   */
82
  return (shuffle + (UINT64_C(1)<<min));
83
84
#endif /* JENT_CONF_DISABLE_LOOP_SHUFFLE */
85
0
}
86
87
/**
88
 * CPU Jitter noise source -- this is the noise source based on the CPU
89
 *            execution time jitter
90
 *
91
 * This function injects the individual bits of the time value into the
92
 * entropy pool using a hash.
93
 *
94
 * @ec [in] entropy collector struct -- may be NULL
95
 * @time [in] time stamp to be injected
96
 * @loop_cnt [in] if a value not equal to 0 is set, use the given value as
97
 *      number of loops to perform the hash operation
98
 * @stuck [in] Is the time stamp identified as stuck?
99
 *
100
 * Output:
101
 * updated hash context
102
 */
103
static void jent_hash_time(struct rand_data *ec, uint64_t time,
104
         uint64_t loop_cnt, unsigned int stuck)
105
0
{
106
0
  HASH_CTX_ON_STACK(ctx);
107
0
  uint8_t itermediary[SHA3_256_SIZE_DIGEST];
108
0
  uint64_t j = 0;
109
0
  uint64_t hash_loop_cnt;
110
0
#define MAX_HASH_LOOP 3
111
0
#define MIN_HASH_LOOP 0
112
113
  /* Ensure that macros cannot overflow jent_loop_shuffle() */
114
0
  BUILD_BUG_ON((MAX_HASH_LOOP + MIN_HASH_LOOP) > 63);
115
0
  hash_loop_cnt =
116
0
    jent_loop_shuffle(ec, MAX_HASH_LOOP, MIN_HASH_LOOP);
117
118
0
  sha3_256_init(&ctx);
119
120
  /*
121
   * testing purposes -- allow test app to set the counter, not
122
   * needed during runtime
123
   */
124
0
  if (loop_cnt)
125
0
    hash_loop_cnt = loop_cnt;
126
127
  /*
128
   * This loop basically slows down the SHA-3 operation depending
129
   * on the hash_loop_cnt. Each iteration of the loop generates the
130
   * same result.
131
   */
132
0
  for (j = 0; j < hash_loop_cnt; j++) {
133
0
    sha3_update(&ctx, ec->data, SHA3_256_SIZE_DIGEST);
134
0
    sha3_update(&ctx, (uint8_t *)&time, sizeof(uint64_t));
135
0
    sha3_update(&ctx, (uint8_t *)&j, sizeof(uint64_t));
136
137
    /*
138
     * If the time stamp is stuck, do not finally insert the value
139
     * into the entropy pool. Although this operation should not do
140
     * any harm even when the time stamp has no entropy, SP800-90B
141
     * requires that any conditioning operation to have an identical
142
     * amount of input data according to section 3.1.5.
143
     */
144
145
    /*
146
     * The sha3_final operations re-initialize the context for the
147
     * next loop iteration.
148
     */
149
0
    if (stuck || (j < hash_loop_cnt - 1))
150
0
      sha3_final(&ctx, itermediary);
151
0
    else
152
0
      sha3_final(&ctx, ec->data);
153
0
  }
154
155
0
  jent_memset_secure(&ctx, SHA_MAX_CTX_SIZE);
156
0
  jent_memset_secure(itermediary, sizeof(itermediary));
157
0
}
158
159
0
#define MAX_ACC_LOOP_BIT 7
160
0
#define MIN_ACC_LOOP_BIT 0
161
#ifdef JENT_RANDOM_MEMACCESS
162
163
static inline uint32_t uint32rotl(const uint32_t x, int k)
164
0
{
165
0
  return (x << k) | (x >> (32 - k));
166
0
}
167
168
static inline uint32_t xoshiro128starstar(uint32_t *s)
169
0
{
170
0
  const uint32_t result = uint32rotl(s[1] * 5, 7) * 9;
171
0
  const uint32_t t = s[1] << 9;
172
173
0
  s[2] ^= s[0];
174
0
  s[3] ^= s[1];
175
0
  s[1] ^= s[2];
176
0
  s[0] ^= s[3];
177
178
0
  s[2] ^= t;
179
180
0
  s[3] = uint32rotl(s[3], 11);
181
182
0
  return result;
183
0
}
184
185
static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt)
186
0
{
187
0
  uint64_t i = 0;
188
0
  union {
189
0
    uint32_t u[4];
190
0
    uint8_t b[sizeof(uint32_t) * 4];
191
0
  } prngState = { .u = {0x8e93eec0, 0xce65608a, 0xa8d46b46, 0xe83cef69} };
192
0
  uint32_t addressMask;
193
0
        uint64_t acc_loop_cnt;
194
195
0
  if (NULL == ec || NULL == ec->mem)
196
0
    return;
197
198
0
  addressMask =  ec->memmask;
199
200
  /* Ensure that macros cannot overflow jent_loop_shuffle() */
201
0
  BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63);
202
0
  acc_loop_cnt =
203
0
    jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT);
204
205
  /*
206
   * Mix the current data into prngState
207
   *
208
   * Any time you see a PRNG in a noise source, you should be concerned.
209
   *
210
   * The PRNG doesn't directly produce the raw noise, it just adjusts the
211
   * location being updated. The timing of the update is part of the raw
212
   * sample. The main thing this process gets you isn't better
213
   * "per-update: timing, it gets you mostly independent "per-update"
214
   * timing, so we can now benefit from the Central Limit Theorem!
215
   */
216
0
  for (i = 0; i < sizeof(prngState); i++)
217
0
    prngState.b[i] ^= ec->data[i];
218
219
  /*
220
   * testing purposes -- allow test app to set the counter, not
221
   * needed during runtime
222
   */
223
0
  if (loop_cnt)
224
0
    acc_loop_cnt = loop_cnt;
225
226
0
  for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) {
227
    /* Take PRNG output to find the memory location to update. */
228
0
    unsigned char *tmpval = ec->mem +
229
0
          (xoshiro128starstar(prngState.u) &
230
0
           addressMask);
231
232
    /*
233
     * memory access: just add 1 to one byte,
234
     * wrap at 255 -- memory access implies read
235
     * from and write to memory location
236
     */
237
0
    *tmpval = (unsigned char)((*tmpval + 1) & 0xff);
238
0
  }
239
0
}
240
241
#else /* JENT_RANDOM_MEMACCESS */
242
243
/**
244
 * Memory Access noise source -- this is a noise source based on variations in
245
 *         memory access times
246
 *
247
 * This function performs memory accesses which will add to the timing
248
 * variations due to an unknown amount of CPU wait states that need to be
249
 * added when accessing memory. The memory size should be larger than the L1
250
 * caches as outlined in the documentation and the associated testing.
251
 *
252
 * The L1 cache has a very high bandwidth, albeit its access rate is  usually
253
 * slower than accessing CPU registers. Therefore, L1 accesses only add minimal
254
 * variations as the CPU has hardly to wait. Starting with L2, significant
255
 * variations are added because L2 typically does not belong to the CPU any more
256
 * and therefore a wider range of CPU wait states is necessary for accesses.
257
 * L3 and real memory accesses have even a wider range of wait states. However,
258
 * to reliably access either L3 or memory, the ec->mem memory must be quite
259
 * large which is usually not desirable.
260
 *
261
 * @ec [in] Reference to the entropy collector with the memory access data -- if
262
 *      the reference to the memory block to be accessed is NULL, this noise
263
 *      source is disabled
264
 * @loop_cnt [in] if a value not equal to 0 is set, use the given value as
265
 *      number of loops to perform the hash operation
266
 */
267
static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt)
268
{
269
  unsigned int wrap = 0;
270
  uint64_t i = 0;
271
272
  /* Ensure that macros cannot overflow jent_loop_shuffle() */
273
  BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63);
274
  uint64_t acc_loop_cnt =
275
    jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT);
276
277
  if (NULL == ec || NULL == ec->mem)
278
    return;
279
  wrap = ec->memblocksize * ec->memblocks;
280
281
  /*
282
   * testing purposes -- allow test app to set the counter, not
283
   * needed during runtime
284
   */
285
  if (loop_cnt)
286
    acc_loop_cnt = loop_cnt;
287
  for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) {
288
    unsigned char *tmpval = ec->mem + ec->memlocation;
289
    /*
290
     * memory access: just add 1 to one byte,
291
     * wrap at 255 -- memory access implies read
292
     * from and write to memory location
293
     */
294
    *tmpval = (unsigned char)((*tmpval + 1) & 0xff);
295
    /*
296
     * Addition of memblocksize - 1 to pointer
297
     * with wrap around logic to ensure that every
298
     * memory location is hit evenly
299
     */
300
    ec->memlocation = ec->memlocation + ec->memblocksize - 1;
301
    ec->memlocation = ec->memlocation % wrap;
302
  }
303
}
304
305
#endif /* JENT_RANDOM_MEMACCESS */
306
307
/***************************************************************************
308
 * Start of entropy processing logic
309
 ***************************************************************************/
310
311
/**
312
 * This is the heart of the entropy generation: calculate time deltas and
313
 * use the CPU jitter in the time deltas. The jitter is injected into the
314
 * entropy pool.
315
 *
316
 * WARNING: ensure that ->prev_time is primed before using the output
317
 *      of this function! This can be done by calling this function
318
 *      and not using its result.
319
 *
320
 * @ec [in] Reference to entropy collector
321
 * @loop_cnt [in] see jent_hash_time
322
 * @ret_current_delta [out] Test interface: return time delta - may be NULL
323
 *
324
 * @return: result of stuck test
325
 */
326
unsigned int jent_measure_jitter(struct rand_data *ec,
327
         uint64_t loop_cnt,
328
         uint64_t *ret_current_delta)
329
0
{
330
0
  uint64_t time = 0;
331
0
  uint64_t current_delta = 0;
332
0
  unsigned int stuck;
333
334
  /* Invoke one noise source before time measurement to add variations */
335
0
  jent_memaccess(ec, loop_cnt);
336
337
  /*
338
   * Get time stamp and calculate time delta to previous
339
   * invocation to measure the timing variations
340
   */
341
0
  jent_get_nstime_internal(ec, &time);
342
0
  current_delta = jent_delta(ec->prev_time, time) /
343
0
            ec->jent_common_timer_gcd;
344
0
  ec->prev_time = time;
345
346
  /* Check whether we have a stuck measurement. */
347
0
  stuck = jent_stuck(ec, current_delta);
348
349
  /* Now call the next noise sources which also injects the data */
350
0
  jent_hash_time(ec, current_delta, loop_cnt, stuck);
351
352
  /* return the raw entropy value */
353
0
  if (ret_current_delta)
354
0
    *ret_current_delta = current_delta;
355
356
0
  return stuck;
357
0
}
358
359
/**
360
 * Generator of one 256 bit random number
361
 * Function fills rand_data->data
362
 *
363
 * @ec [in] Reference to entropy collector
364
 */
365
void jent_random_data(struct rand_data *ec)
366
0
{
367
0
  unsigned int k = 0, safety_factor = ENTROPY_SAFETY_FACTOR;
368
369
0
  if (!ec->fips_enabled)
370
0
    safety_factor = 0;
371
372
  /* priming of the ->prev_time value */
373
0
  jent_measure_jitter(ec, 0, NULL);
374
375
0
  while (1) {
376
    /* If a stuck measurement is received, repeat measurement */
377
0
    if (jent_measure_jitter(ec, 0, NULL))
378
0
      continue;
379
380
    /*
381
     * We multiply the loop value with ->osr to obtain the
382
     * oversampling rate requested by the caller
383
     */
384
0
    if (++k >= ((DATA_SIZE_BITS + safety_factor) * ec->osr))
385
0
      break;
386
0
  }
387
0
}