1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 *
4 * LibTomCrypt is a library that provides various cryptographic
5 * algorithms in a highly modular and flexible manner.
6 *
7 * The library is free for all purposes without any express
8 * guarantee it works.
9 */
10 #include "tomcrypt_private.h"
11
12 #ifdef LTC_FORTUNA_RESEED_RATELIMIT_TIMED
13 #if defined(_WIN32)
14 #include <windows.h>
15 #elif defined(LTC_CLOCK_GETTIME)
16 #include <time.h> /* struct timespec + clock_gettime */
17 #else
18 #include <sys/time.h> /* struct timeval + gettimeofday */
19 #endif
20 #endif
21
22 /**
23 @file fortuna.c
24 Fortuna PRNG, Tom St Denis
25 */
26
27 /* Implementation of Fortuna by Tom St Denis
28
29 We deviate slightly here for reasons of simplicity [and to fit in the API]. First all "sources"
30 in the AddEntropy function are fixed to 0. Second since no reliable timer is provided
31 we reseed automatically when len(pool0) >= 64 or every LTC_FORTUNA_WD calls to the read function */
32
33 #ifdef LTC_FORTUNA
34
35 /* requries LTC_SHA256 and AES */
36 #if !(defined(LTC_RIJNDAEL) && defined(LTC_SHA256))
37 #error LTC_FORTUNA requires LTC_SHA256 and LTC_RIJNDAEL (AES)
38 #endif
39
40 #ifndef LTC_FORTUNA_POOLS
41 #warning LTC_FORTUNA_POOLS was not previously defined (old headers?)
42 #define LTC_FORTUNA_POOLS 32
43 #endif
44
45 #if LTC_FORTUNA_POOLS < 4 || LTC_FORTUNA_POOLS > 32
46 #error LTC_FORTUNA_POOLS must be in [4..32]
47 #endif
48
49 const struct ltc_prng_descriptor fortuna_desc = {
50 "fortuna",
51 64,
52 &fortuna_start,
53 &fortuna_add_entropy,
54 &fortuna_ready,
55 &fortuna_read,
56 &fortuna_done,
57 &fortuna_export,
58 &fortuna_import,
59 &fortuna_test
60 };
61
62 /* update the IV */
_fortuna_update_iv(prng_state * prng)63 static void _fortuna_update_iv(prng_state *prng)
64 {
65 int x;
66 unsigned char *IV;
67 /* update IV */
68 IV = prng->u.fortuna.IV;
69 for (x = 0; x < 16; x++) {
70 IV[x] = (IV[x] + 1) & 255;
71 if (IV[x] != 0) break;
72 }
73 }
74
75 #ifdef LTC_FORTUNA_RESEED_RATELIMIT_TIMED
76 /* get the current time in 100ms steps */
_fortuna_current_time(void)77 static ulong64 _fortuna_current_time(void)
78 {
79 ulong64 cur_time;
80 #if defined(_WIN32)
81 FILETIME CurrentTime;
82 ULARGE_INTEGER ul;
83 GetSystemTimeAsFileTime(&CurrentTime);
84 ul.LowPart = CurrentTime.dwLowDateTime;
85 ul.HighPart = CurrentTime.dwHighDateTime;
86 cur_time = ul.QuadPart; /* now we have 100ns intervals since 1 January 1601 */
87 cur_time -= CONST64(116444736000000000); /* subtract 100ns intervals between 1601-1970 */
88 cur_time /= 10; /* 100ns intervals > microseconds */
89 #elif defined(LTC_CLOCK_GETTIME)
90 struct timespec ts;
91 clock_gettime(CLOCK_MONOTONIC, &ts);
92 cur_time = (ulong64)(ts.tv_sec) * 1000000 + (ulong64)(ts.tv_nsec) / 1000; /* get microseconds */
93 #else
94 struct timeval tv;
95 gettimeofday(&tv, NULL);
96 cur_time = (ulong64)(tv.tv_sec) * 1000000 + (ulong64)(tv.tv_usec); /* get microseconds */
97 #endif
98 return cur_time / 100;
99 }
100 #endif
101
102 /* reseed the PRNG */
_fortuna_reseed(prng_state * prng)103 static int _fortuna_reseed(prng_state *prng)
104 {
105 unsigned char tmp[MAXBLOCKSIZE];
106 hash_state md;
107 ulong64 reset_cnt;
108 int err, x;
109
110 #ifdef LTC_FORTUNA_RESEED_RATELIMIT_TIMED
111 ulong64 now = _fortuna_current_time();
112 if (now == prng->u.fortuna.wd) {
113 return CRYPT_OK;
114 }
115 #else
116 if (++prng->u.fortuna.wd < LTC_FORTUNA_WD) {
117 return CRYPT_OK;
118 }
119 #endif
120
121 /* new K == LTC_SHA256(K || s) where s == LTC_SHA256(P0) || LTC_SHA256(P1) ... */
122 sha256_init(&md);
123 if ((err = sha256_process(&md, prng->u.fortuna.K, 32)) != CRYPT_OK) {
124 sha256_done(&md, tmp);
125 return err;
126 }
127
128 reset_cnt = prng->u.fortuna.reset_cnt + 1;
129
130 for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
131 if (x == 0 || ((reset_cnt >> (x-1)) & 1) == 0) {
132 /* terminate this hash */
133 if ((err = sha256_done(&prng->u.fortuna.pool[x], tmp)) != CRYPT_OK) {
134 sha256_done(&md, tmp);
135 return err;
136 }
137 /* add it to the string */
138 if ((err = sha256_process(&md, tmp, 32)) != CRYPT_OK) {
139 sha256_done(&md, tmp);
140 return err;
141 }
142 /* reset this pool */
143 if ((err = sha256_init(&prng->u.fortuna.pool[x])) != CRYPT_OK) {
144 sha256_done(&md, tmp);
145 return err;
146 }
147 } else {
148 break;
149 }
150 }
151
152 /* finish key */
153 if ((err = sha256_done(&md, prng->u.fortuna.K)) != CRYPT_OK) {
154 return err;
155 }
156 if ((err = rijndael_setup(prng->u.fortuna.K, 32, 0, &prng->u.fortuna.skey)) != CRYPT_OK) {
157 return err;
158 }
159 _fortuna_update_iv(prng);
160
161 /* reset/update internals */
162 prng->u.fortuna.pool0_len = 0;
163 #ifdef LTC_FORTUNA_RESEED_RATELIMIT_TIMED
164 prng->u.fortuna.wd = now;
165 #else
166 prng->u.fortuna.wd = 0;
167 #endif
168 prng->u.fortuna.reset_cnt = reset_cnt;
169
170
171 #ifdef LTC_CLEAN_STACK
172 zeromem(&md, sizeof(md));
173 zeromem(tmp, sizeof(tmp));
174 #endif
175
176 return CRYPT_OK;
177 }
178
179 /**
180 "Update Seed File"-compliant update of K
181
182 @param in The PRNG state
183 @param inlen Size of the state
184 @param prng The PRNG to import
185 @return CRYPT_OK if successful
186 */
fortuna_update_seed(const unsigned char * in,unsigned long inlen,prng_state * prng)187 int fortuna_update_seed(const unsigned char *in, unsigned long inlen, prng_state *prng)
188 {
189 int err;
190 unsigned char tmp[MAXBLOCKSIZE];
191 hash_state md;
192
193 LTC_MUTEX_LOCK(&prng->lock);
194 /* new K = LTC_SHA256(K || in) */
195 sha256_init(&md);
196 if ((err = sha256_process(&md, prng->u.fortuna.K, 32)) != CRYPT_OK) {
197 sha256_done(&md, tmp);
198 goto LBL_UNLOCK;
199 }
200 if ((err = sha256_process(&md, in, inlen)) != CRYPT_OK) {
201 sha256_done(&md, tmp);
202 goto LBL_UNLOCK;
203 }
204 /* finish key */
205 if ((err = sha256_done(&md, prng->u.fortuna.K)) != CRYPT_OK) {
206 goto LBL_UNLOCK;
207 }
208 _fortuna_update_iv(prng);
209
210 LBL_UNLOCK:
211 LTC_MUTEX_UNLOCK(&prng->lock);
212 #ifdef LTC_CLEAN_STACK
213 zeromem(&md, sizeof(md));
214 #endif
215
216 return err;
217 }
218
219 /**
220 Start the PRNG
221 @param prng [out] The PRNG state to initialize
222 @return CRYPT_OK if successful
223 */
fortuna_start(prng_state * prng)224 int fortuna_start(prng_state *prng)
225 {
226 int err, x, y;
227 unsigned char tmp[MAXBLOCKSIZE];
228
229 LTC_ARGCHK(prng != NULL);
230 prng->ready = 0;
231
232 /* initialize the pools */
233 for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
234 if ((err = sha256_init(&prng->u.fortuna.pool[x])) != CRYPT_OK) {
235 for (y = 0; y < x; y++) {
236 sha256_done(&prng->u.fortuna.pool[y], tmp);
237 }
238 return err;
239 }
240 }
241 prng->u.fortuna.pool_idx = prng->u.fortuna.pool0_len = prng->u.fortuna.wd = 0;
242 prng->u.fortuna.reset_cnt = 0;
243
244 /* reset bufs */
245 zeromem(prng->u.fortuna.K, 32);
246 if ((err = rijndael_setup(prng->u.fortuna.K, 32, 0, &prng->u.fortuna.skey)) != CRYPT_OK) {
247 for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
248 sha256_done(&prng->u.fortuna.pool[x], tmp);
249 }
250 return err;
251 }
252 zeromem(prng->u.fortuna.IV, 16);
253
254 LTC_MUTEX_INIT(&prng->lock)
255
256 return CRYPT_OK;
257 }
258
_fortuna_add(unsigned long source,unsigned long pool,const unsigned char * in,unsigned long inlen,prng_state * prng)259 static int _fortuna_add(unsigned long source, unsigned long pool, const unsigned char *in, unsigned long inlen, prng_state *prng)
260 {
261 unsigned char tmp[2];
262 int err;
263
264 /* ensure inlen <= 32 */
265 if (inlen > 32) {
266 inlen = 32;
267 }
268
269 /* add s || length(in) || in to pool[pool_idx] */
270 tmp[0] = (unsigned char)source;
271 tmp[1] = (unsigned char)inlen;
272
273 if ((err = sha256_process(&prng->u.fortuna.pool[pool], tmp, 2)) != CRYPT_OK) {
274 return err;
275 }
276 if ((err = sha256_process(&prng->u.fortuna.pool[pool], in, inlen)) != CRYPT_OK) {
277 return err;
278 }
279 if (pool == 0) {
280 prng->u.fortuna.pool0_len += inlen;
281 }
282 return CRYPT_OK; /* success */
283 }
284
285 /**
286 Add random event to the PRNG state as proposed by the original paper.
287 @param source The source this random event comes from (0 .. 255)
288 @param pool The pool where to add the data to (0 .. LTC_FORTUNA_POOLS)
289 @param in The data to add
290 @param inlen Length of the data to add
291 @param prng PRNG state to update
292 @return CRYPT_OK if successful
293 */
fortuna_add_random_event(unsigned long source,unsigned long pool,const unsigned char * in,unsigned long inlen,prng_state * prng)294 int fortuna_add_random_event(unsigned long source, unsigned long pool, const unsigned char *in, unsigned long inlen, prng_state *prng)
295 {
296 int err;
297
298 LTC_ARGCHK(prng != NULL);
299 LTC_ARGCHK(in != NULL);
300 LTC_ARGCHK(inlen > 0);
301 LTC_ARGCHK(source <= 255);
302 LTC_ARGCHK(pool < LTC_FORTUNA_POOLS);
303
304 LTC_MUTEX_LOCK(&prng->lock);
305
306 err = _fortuna_add(source, pool, in, inlen, prng);
307
308 LTC_MUTEX_UNLOCK(&prng->lock);
309
310 return err;
311 }
312
313 /**
314 Add entropy to the PRNG state
315 @param in The data to add
316 @param inlen Length of the data to add
317 @param prng PRNG state to update
318 @return CRYPT_OK if successful
319 */
fortuna_add_entropy(const unsigned char * in,unsigned long inlen,prng_state * prng)320 int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
321 {
322 int err;
323
324 LTC_ARGCHK(prng != NULL);
325 LTC_ARGCHK(in != NULL);
326 LTC_ARGCHK(inlen > 0);
327
328 LTC_MUTEX_LOCK(&prng->lock);
329
330 err = _fortuna_add(0, prng->u.fortuna.pool_idx, in, inlen, prng);
331
332 if (err == CRYPT_OK) {
333 ++(prng->u.fortuna.pool_idx);
334 prng->u.fortuna.pool_idx %= LTC_FORTUNA_POOLS;
335 }
336
337 LTC_MUTEX_UNLOCK(&prng->lock);
338
339 return err;
340 }
341
342 /**
343 Make the PRNG ready to read from
344 @param prng The PRNG to make active
345 @return CRYPT_OK if successful
346 */
fortuna_ready(prng_state * prng)347 int fortuna_ready(prng_state *prng)
348 {
349 int err;
350 LTC_ARGCHK(prng != NULL);
351
352 LTC_MUTEX_LOCK(&prng->lock);
353 /* make sure the reseed doesn't fail because
354 * of the chosen rate limit */
355 #ifdef LTC_FORTUNA_RESEED_RATELIMIT_TIMED
356 prng->u.fortuna.wd = _fortuna_current_time() - 1;
357 #else
358 prng->u.fortuna.wd = LTC_FORTUNA_WD;
359 #endif
360 err = _fortuna_reseed(prng);
361 prng->ready = (err == CRYPT_OK) ? 1 : 0;
362
363 LTC_MUTEX_UNLOCK(&prng->lock);
364 return err;
365 }
366
367 /**
368 Read from the PRNG
369 @param out Destination
370 @param outlen Length of output
371 @param prng The active PRNG to read from
372 @return Number of octets read
373 */
fortuna_read(unsigned char * out,unsigned long outlen,prng_state * prng)374 unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng)
375 {
376 unsigned char tmp[16];
377 unsigned long tlen = 0;
378
379 if (outlen == 0 || prng == NULL || out == NULL) return 0;
380
381 LTC_MUTEX_LOCK(&prng->lock);
382
383 if (!prng->ready) {
384 goto LBL_UNLOCK;
385 }
386
387 /* do we have to reseed? */
388 if (prng->u.fortuna.pool0_len >= 64) {
389 if (_fortuna_reseed(prng) != CRYPT_OK) {
390 goto LBL_UNLOCK;
391 }
392 }
393
394 /* ensure that one reseed happened before allowing to read */
395 if (prng->u.fortuna.reset_cnt == 0) {
396 goto LBL_UNLOCK;
397 }
398
399 /* now generate the blocks required */
400 tlen = outlen;
401
402 /* handle whole blocks without the extra XMEMCPY */
403 while (outlen >= 16) {
404 /* encrypt the IV and store it */
405 rijndael_ecb_encrypt(prng->u.fortuna.IV, out, &prng->u.fortuna.skey);
406 out += 16;
407 outlen -= 16;
408 _fortuna_update_iv(prng);
409 }
410
411 /* left over bytes? */
412 if (outlen > 0) {
413 rijndael_ecb_encrypt(prng->u.fortuna.IV, tmp, &prng->u.fortuna.skey);
414 XMEMCPY(out, tmp, outlen);
415 _fortuna_update_iv(prng);
416 }
417
418 /* generate new key */
419 rijndael_ecb_encrypt(prng->u.fortuna.IV, prng->u.fortuna.K , &prng->u.fortuna.skey);
420 _fortuna_update_iv(prng);
421
422 rijndael_ecb_encrypt(prng->u.fortuna.IV, prng->u.fortuna.K+16, &prng->u.fortuna.skey);
423 _fortuna_update_iv(prng);
424
425 if (rijndael_setup(prng->u.fortuna.K, 32, 0, &prng->u.fortuna.skey) != CRYPT_OK) {
426 tlen = 0;
427 }
428
429 LBL_UNLOCK:
430 #ifdef LTC_CLEAN_STACK
431 zeromem(tmp, sizeof(tmp));
432 #endif
433 LTC_MUTEX_UNLOCK(&prng->lock);
434 return tlen;
435 }
436
437 /**
438 Terminate the PRNG
439 @param prng The PRNG to terminate
440 @return CRYPT_OK if successful
441 */
fortuna_done(prng_state * prng)442 int fortuna_done(prng_state *prng)
443 {
444 int err, x;
445 unsigned char tmp[32];
446
447 LTC_ARGCHK(prng != NULL);
448
449 LTC_MUTEX_LOCK(&prng->lock);
450 prng->ready = 0;
451
452 /* terminate all the hashes */
453 for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
454 if ((err = sha256_done(&(prng->u.fortuna.pool[x]), tmp)) != CRYPT_OK) {
455 goto LBL_UNLOCK;
456 }
457 }
458 /* call cipher done when we invent one ;-) */
459 err = CRYPT_OK; /* success */
460
461 LBL_UNLOCK:
462 #ifdef LTC_CLEAN_STACK
463 zeromem(tmp, sizeof(tmp));
464 #endif
465 LTC_MUTEX_UNLOCK(&prng->lock);
466 LTC_MUTEX_DESTROY(&prng->lock);
467 return err;
468 }
469
470 /**
471 Export the PRNG state
472 @param out [out] Destination
473 @param outlen [in/out] Max size and resulting size of the state
474 @param prng The PRNG to export
475 @return CRYPT_OK if successful
476 */
_LTC_PRNG_EXPORT(fortuna)477 _LTC_PRNG_EXPORT(fortuna)
478
479 /**
480 Import a PRNG state
481 @param in The PRNG state
482 @param inlen Size of the state
483 @param prng The PRNG to import
484 @return CRYPT_OK if successful
485 */
486 int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
487 {
488 int err;
489
490 LTC_ARGCHK(in != NULL);
491 LTC_ARGCHK(prng != NULL);
492
493 if (inlen < (unsigned long)fortuna_desc.export_size) {
494 return CRYPT_INVALID_ARG;
495 }
496
497 if ((err = fortuna_start(prng)) != CRYPT_OK) {
498 return err;
499 }
500
501 if ((err = fortuna_update_seed(in, inlen, prng)) != CRYPT_OK) {
502 return err;
503 }
504
505 return err;
506 }
507
508 /**
509 PRNG self-test
510 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
511 */
fortuna_test(void)512 int fortuna_test(void)
513 {
514 #ifndef LTC_TEST
515 return CRYPT_NOP;
516 #else
517 int err;
518
519 if ((err = sha256_test()) != CRYPT_OK) {
520 return err;
521 }
522 return rijndael_test();
523 #endif
524 }
525
526 #endif
527
528
529 /* ref: $Format:%D$ */
530 /* git commit: $Format:%H$ */
531 /* commit time: $Format:%ai$ */
532