1
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
3
* LibTomCrypt is a library that provides various cryptographic
4
* algorithms in a highly modular and flexible manner.
6
* The library is free for all purposes without any express
9
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.org
15
Fortuna PRNG, Tom St Denis
18
/* Implementation of Fortuna by Tom St Denis
20
We deviate slightly here for reasons of simplicity [and to fit in the API]. First all "sources"
21
in the AddEntropy function are fixed to 0. Second since no reliable timer is provided
22
we reseed automatically when len(pool0) >= 64 or every FORTUNA_WD calls to the read function */
26
/* requries SHA256 and AES */
27
#if !(defined(RIJNDAEL) && defined(SHA256))
28
#error FORTUNA requires SHA256 and RIJNDAEL (AES)
32
#warning FORTUNA_POOLS was not previously defined (old headers?)
33
#define FORTUNA_POOLS 32
36
#if FORTUNA_POOLS < 4 || FORTUNA_POOLS > 32
37
#error FORTUNA_POOLS must be in [4..32]
40
const struct ltc_prng_descriptor fortuna_desc = {
53
static void fortuna_update_iv(prng_state *prng)
58
IV = prng->fortuna.IV;
59
for (x = 0; x < 16; x++) {
60
IV[x] = (IV[x] + 1) & 255;
61
if (IV[x] != 0) break;
66
static int fortuna_reseed(prng_state *prng)
68
unsigned char tmp[MAXBLOCKSIZE];
72
++prng->fortuna.reset_cnt;
74
/* new K == SHA256(K || s) where s == SHA256(P0) || SHA256(P1) ... */
76
if ((err = sha256_process(&md, prng->fortuna.K, 32)) != CRYPT_OK) {
80
for (x = 0; x < FORTUNA_POOLS; x++) {
81
if (x == 0 || ((prng->fortuna.reset_cnt >> (x-1)) & 1) == 0) {
82
/* terminate this hash */
83
if ((err = sha256_done(&prng->fortuna.pool[x], tmp)) != CRYPT_OK) {
86
/* add it to the string */
87
if ((err = sha256_process(&md, tmp, 32)) != CRYPT_OK) {
91
sha256_init(&prng->fortuna.pool[x]);
98
if ((err = sha256_done(&md, prng->fortuna.K)) != CRYPT_OK) {
101
if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
104
fortuna_update_iv(prng);
107
prng->fortuna.pool0_len = 0;
108
prng->fortuna.wd = 0;
111
#ifdef LTC_CLEAN_STACK
112
zeromem(&md, sizeof(md));
113
zeromem(tmp, sizeof(tmp));
121
@param prng [out] The PRNG state to initialize
122
@return CRYPT_OK if successful
124
int fortuna_start(prng_state *prng)
128
LTC_ARGCHK(prng != NULL);
130
/* initialize the pools */
131
for (x = 0; x < FORTUNA_POOLS; x++) {
132
sha256_init(&prng->fortuna.pool[x]);
134
prng->fortuna.pool_idx = prng->fortuna.pool0_len = prng->fortuna.reset_cnt =
135
prng->fortuna.wd = 0;
138
zeromem(prng->fortuna.K, 32);
139
if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
142
zeromem(prng->fortuna.IV, 16);
148
Add entropy to the PRNG state
149
@param in The data to add
150
@param inlen Length of the data to add
151
@param prng PRNG state to update
152
@return CRYPT_OK if successful
154
int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
156
unsigned char tmp[2];
159
LTC_ARGCHK(in != NULL);
160
LTC_ARGCHK(prng != NULL);
162
/* ensure inlen <= 32 */
164
return CRYPT_INVALID_ARG;
167
/* add s || length(in) || in to pool[pool_idx] */
170
if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], tmp, 2)) != CRYPT_OK) {
173
if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], in, inlen)) != CRYPT_OK) {
176
if (prng->fortuna.pool_idx == 0) {
177
prng->fortuna.pool0_len += inlen;
179
if (++(prng->fortuna.pool_idx) == FORTUNA_POOLS) {
180
prng->fortuna.pool_idx = 0;
187
Make the PRNG ready to read from
188
@param prng The PRNG to make active
189
@return CRYPT_OK if successful
191
int fortuna_ready(prng_state *prng)
193
return fortuna_reseed(prng);
198
@param out Destination
199
@param outlen Length of output
200
@param prng The active PRNG to read from
201
@return Number of octets read
203
unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng)
205
unsigned char tmp[16];
209
LTC_ARGCHK(out != NULL);
210
LTC_ARGCHK(prng != NULL);
212
/* do we have to reseed? */
213
if (++prng->fortuna.wd == FORTUNA_WD || prng->fortuna.pool0_len >= 64) {
214
if ((err = fortuna_reseed(prng)) != CRYPT_OK) {
219
/* now generate the blocks required */
222
/* handle whole blocks without the extra memcpy */
223
while (outlen >= 16) {
224
/* encrypt the IV and store it */
225
rijndael_ecb_encrypt(prng->fortuna.IV, out, &prng->fortuna.skey);
228
fortuna_update_iv(prng);
231
/* left over bytes? */
233
rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey);
234
XMEMCPY(out, tmp, outlen);
235
fortuna_update_iv(prng);
238
/* generate new key */
239
rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K , &prng->fortuna.skey); fortuna_update_iv(prng);
240
rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K+16, &prng->fortuna.skey); fortuna_update_iv(prng);
241
if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
245
#ifdef LTC_CLEAN_STACK
246
zeromem(tmp, sizeof(tmp));
253
@param prng The PRNG to terminate
254
@return CRYPT_OK if successful
256
int fortuna_done(prng_state *prng)
259
unsigned char tmp[32];
261
LTC_ARGCHK(prng != NULL);
263
/* terminate all the hashes */
264
for (x = 0; x < FORTUNA_POOLS; x++) {
265
if ((err = sha256_done(&(prng->fortuna.pool[x]), tmp)) != CRYPT_OK) {
269
/* call cipher done when we invent one ;-) */
271
#ifdef LTC_CLEAN_STACK
272
zeromem(tmp, sizeof(tmp));
279
Export the PRNG state
280
@param out [out] Destination
281
@param outlen [in/out] Max size and resulting size of the state
282
@param prng The PRNG to export
283
@return CRYPT_OK if successful
285
int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
290
LTC_ARGCHK(out != NULL);
291
LTC_ARGCHK(outlen != NULL);
292
LTC_ARGCHK(prng != NULL);
294
/* we'll write bytes for s&g's */
295
if (*outlen < 32*FORTUNA_POOLS) {
296
return CRYPT_BUFFER_OVERFLOW;
299
md = XMALLOC(sizeof(hash_state));
304
/* to emit the state we copy each pool, terminate it then hash it again so
305
* an attacker who sees the state can't determine the current state of the PRNG
307
for (x = 0; x < FORTUNA_POOLS; x++) {
309
XMEMCPY(md, &(prng->fortuna.pool[x]), sizeof(*md));
312
if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
317
if ((err = sha256_init(md)) != CRYPT_OK) {
320
if ((err = sha256_process(md, out+x*32, 32)) != CRYPT_OK) {
323
if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
327
*outlen = 32*FORTUNA_POOLS;
331
#ifdef LTC_CLEAN_STACK
332
zeromem(md, sizeof(*md));
340
@param in The PRNG state
341
@param inlen Size of the state
342
@param prng The PRNG to import
343
@return CRYPT_OK if successful
345
int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
349
LTC_ARGCHK(in != NULL);
350
LTC_ARGCHK(prng != NULL);
352
if (inlen != 32*FORTUNA_POOLS) {
353
return CRYPT_INVALID_ARG;
356
if ((err = fortuna_start(prng)) != CRYPT_OK) {
359
for (x = 0; x < FORTUNA_POOLS; x++) {
360
if ((err = fortuna_add_entropy(in+x*32, 32, prng)) != CRYPT_OK) {
369
@return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
371
int fortuna_test(void)
378
if ((err = sha256_test()) != CRYPT_OK) {
381
return rijndael_test();
388
/* $Source: /cvs/libtom/libtomcrypt/src/prngs/fortuna.c,v $ */
389
/* $Revision: 1.3 $ */
390
/* $Date: 2005/05/05 14:35:59 $ */