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