comparison libtomcrypt/src/prngs/fortuna.c @ 399:a707e6148060

merge of '5fdf69ca60d1683cdd9f4c2595134bed26394834' and '6b61c50f4cf888bea302ac8fcf5dbb573b443251'
author Matt Johnston <matt@ucc.asn.au>
date Sat, 03 Feb 2007 08:20:34 +0000
parents 0cbe8f6dbf9e
children f849a5ca2efc
comparison
equal deleted inserted replaced
394:17d097fc111c 399:a707e6148060
1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
2 *
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
5 *
6 * The library is free for all purposes without any express
7 * guarantee it works.
8 *
9 * Tom St Denis, [email protected], http://libtomcrypt.com
10 */
11 #include "tomcrypt.h"
12
13 /**
14 @file fortuna.c
15 Fortuna PRNG, Tom St Denis
16 */
17
18 /* Implementation of Fortuna by Tom St Denis
19
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 */
23
24 #ifdef FORTUNA
25
26 /* requries SHA256 and AES */
27 #if !(defined(RIJNDAEL) && defined(SHA256))
28 #error FORTUNA requires SHA256 and RIJNDAEL (AES)
29 #endif
30
31 #ifndef FORTUNA_POOLS
32 #warning FORTUNA_POOLS was not previously defined (old headers?)
33 #define FORTUNA_POOLS 32
34 #endif
35
36 #if FORTUNA_POOLS < 4 || FORTUNA_POOLS > 32
37 #error FORTUNA_POOLS must be in [4..32]
38 #endif
39
40 const struct ltc_prng_descriptor fortuna_desc = {
41 "fortuna", 1024,
42 &fortuna_start,
43 &fortuna_add_entropy,
44 &fortuna_ready,
45 &fortuna_read,
46 &fortuna_done,
47 &fortuna_export,
48 &fortuna_import,
49 &fortuna_test
50 };
51
52 /* update the IV */
53 static void fortuna_update_iv(prng_state *prng)
54 {
55 int x;
56 unsigned char *IV;
57 /* update IV */
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;
62 }
63 }
64
65 /* reseed the PRNG */
66 static int fortuna_reseed(prng_state *prng)
67 {
68 unsigned char tmp[MAXBLOCKSIZE];
69 hash_state md;
70 int err, x;
71
72 ++prng->fortuna.reset_cnt;
73
74 /* new K == SHA256(K || s) where s == SHA256(P0) || SHA256(P1) ... */
75 sha256_init(&md);
76 if ((err = sha256_process(&md, prng->fortuna.K, 32)) != CRYPT_OK) {
77 sha256_done(&md, tmp);
78 return err;
79 }
80
81 for (x = 0; x < FORTUNA_POOLS; x++) {
82 if (x == 0 || ((prng->fortuna.reset_cnt >> (x-1)) & 1) == 0) {
83 /* terminate this hash */
84 if ((err = sha256_done(&prng->fortuna.pool[x], tmp)) != CRYPT_OK) {
85 sha256_done(&md, tmp);
86 return err;
87 }
88 /* add it to the string */
89 if ((err = sha256_process(&md, tmp, 32)) != CRYPT_OK) {
90 sha256_done(&md, tmp);
91 return err;
92 }
93 /* reset this pool */
94 if ((err = sha256_init(&prng->fortuna.pool[x])) != CRYPT_OK) {
95 sha256_done(&md, tmp);
96 return err;
97 }
98 } else {
99 break;
100 }
101 }
102
103 /* finish key */
104 if ((err = sha256_done(&md, prng->fortuna.K)) != CRYPT_OK) {
105 return err;
106 }
107 if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
108 return err;
109 }
110 fortuna_update_iv(prng);
111
112 /* reset pool len */
113 prng->fortuna.pool0_len = 0;
114 prng->fortuna.wd = 0;
115
116
117 #ifdef LTC_CLEAN_STACK
118 zeromem(&md, sizeof(md));
119 zeromem(tmp, sizeof(tmp));
120 #endif
121
122 return CRYPT_OK;
123 }
124
125 /**
126 Start the PRNG
127 @param prng [out] The PRNG state to initialize
128 @return CRYPT_OK if successful
129 */
130 int fortuna_start(prng_state *prng)
131 {
132 int err, x, y;
133 unsigned char tmp[MAXBLOCKSIZE];
134
135 LTC_ARGCHK(prng != NULL);
136
137 /* initialize the pools */
138 for (x = 0; x < FORTUNA_POOLS; x++) {
139 if ((err = sha256_init(&prng->fortuna.pool[x])) != CRYPT_OK) {
140 for (y = 0; y < x; y++) {
141 sha256_done(&prng->fortuna.pool[y], tmp);
142 }
143 return err;
144 }
145 }
146 prng->fortuna.pool_idx = prng->fortuna.pool0_len = prng->fortuna.wd = 0;
147 prng->fortuna.reset_cnt = 0;
148
149 /* reset bufs */
150 zeromem(prng->fortuna.K, 32);
151 if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
152 for (x = 0; x < FORTUNA_POOLS; x++) {
153 sha256_done(&prng->fortuna.pool[x], tmp);
154 }
155 return err;
156 }
157 zeromem(prng->fortuna.IV, 16);
158
159 LTC_MUTEX_INIT(&prng->fortuna.prng_lock)
160
161 return CRYPT_OK;
162 }
163
164 /**
165 Add entropy to the PRNG state
166 @param in The data to add
167 @param inlen Length of the data to add
168 @param prng PRNG state to update
169 @return CRYPT_OK if successful
170 */
171 int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
172 {
173 unsigned char tmp[2];
174 int err;
175
176 LTC_ARGCHK(in != NULL);
177 LTC_ARGCHK(prng != NULL);
178
179 LTC_MUTEX_LOCK(&prng->fortuna.prng_lock);
180
181 /* ensure inlen <= 32 */
182 if (inlen > 32) {
183 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
184 return CRYPT_INVALID_ARG;
185 }
186
187 /* add s || length(in) || in to pool[pool_idx] */
188 tmp[0] = 0;
189 tmp[1] = (unsigned char)inlen;
190 if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], tmp, 2)) != CRYPT_OK) {
191 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
192 return err;
193 }
194 if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], in, inlen)) != CRYPT_OK) {
195 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
196 return err;
197 }
198 if (prng->fortuna.pool_idx == 0) {
199 prng->fortuna.pool0_len += inlen;
200 }
201 if (++(prng->fortuna.pool_idx) == FORTUNA_POOLS) {
202 prng->fortuna.pool_idx = 0;
203 }
204
205 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
206 return CRYPT_OK;
207 }
208
209 /**
210 Make the PRNG ready to read from
211 @param prng The PRNG to make active
212 @return CRYPT_OK if successful
213 */
214 int fortuna_ready(prng_state *prng)
215 {
216 return fortuna_reseed(prng);
217 }
218
219 /**
220 Read from the PRNG
221 @param out Destination
222 @param outlen Length of output
223 @param prng The active PRNG to read from
224 @return Number of octets read
225 */
226 unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng)
227 {
228 unsigned char tmp[16];
229 int err;
230 unsigned long tlen;
231
232 LTC_ARGCHK(out != NULL);
233 LTC_ARGCHK(prng != NULL);
234
235 LTC_MUTEX_LOCK(&prng->fortuna.prng_lock);
236
237 /* do we have to reseed? */
238 if (++prng->fortuna.wd == FORTUNA_WD || prng->fortuna.pool0_len >= 64) {
239 if ((err = fortuna_reseed(prng)) != CRYPT_OK) {
240 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
241 return 0;
242 }
243 }
244
245 /* now generate the blocks required */
246 tlen = outlen;
247
248 /* handle whole blocks without the extra XMEMCPY */
249 while (outlen >= 16) {
250 /* encrypt the IV and store it */
251 rijndael_ecb_encrypt(prng->fortuna.IV, out, &prng->fortuna.skey);
252 out += 16;
253 outlen -= 16;
254 fortuna_update_iv(prng);
255 }
256
257 /* left over bytes? */
258 if (outlen > 0) {
259 rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey);
260 XMEMCPY(out, tmp, outlen);
261 fortuna_update_iv(prng);
262 }
263
264 /* generate new key */
265 rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K , &prng->fortuna.skey); fortuna_update_iv(prng);
266 rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K+16, &prng->fortuna.skey); fortuna_update_iv(prng);
267 if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
268 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
269 return 0;
270 }
271
272 #ifdef LTC_CLEAN_STACK
273 zeromem(tmp, sizeof(tmp));
274 #endif
275 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
276 return tlen;
277 }
278
279 /**
280 Terminate the PRNG
281 @param prng The PRNG to terminate
282 @return CRYPT_OK if successful
283 */
284 int fortuna_done(prng_state *prng)
285 {
286 int err, x;
287 unsigned char tmp[32];
288
289 LTC_ARGCHK(prng != NULL);
290 LTC_MUTEX_LOCK(&prng->fortuna.prng_lock);
291
292 /* terminate all the hashes */
293 for (x = 0; x < FORTUNA_POOLS; x++) {
294 if ((err = sha256_done(&(prng->fortuna.pool[x]), tmp)) != CRYPT_OK) {
295 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
296 return err;
297 }
298 }
299 /* call cipher done when we invent one ;-) */
300
301 #ifdef LTC_CLEAN_STACK
302 zeromem(tmp, sizeof(tmp));
303 #endif
304
305 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
306 return CRYPT_OK;
307 }
308
309 /**
310 Export the PRNG state
311 @param out [out] Destination
312 @param outlen [in/out] Max size and resulting size of the state
313 @param prng The PRNG to export
314 @return CRYPT_OK if successful
315 */
316 int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
317 {
318 int x, err;
319 hash_state *md;
320
321 LTC_ARGCHK(out != NULL);
322 LTC_ARGCHK(outlen != NULL);
323 LTC_ARGCHK(prng != NULL);
324
325 LTC_MUTEX_LOCK(&prng->fortuna.prng_lock);
326
327 /* we'll write bytes for s&g's */
328 if (*outlen < 32*FORTUNA_POOLS) {
329 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
330 *outlen = 32*FORTUNA_POOLS;
331 return CRYPT_BUFFER_OVERFLOW;
332 }
333
334 md = XMALLOC(sizeof(hash_state));
335 if (md == NULL) {
336 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
337 return CRYPT_MEM;
338 }
339
340 /* to emit the state we copy each pool, terminate it then hash it again so
341 * an attacker who sees the state can't determine the current state of the PRNG
342 */
343 for (x = 0; x < FORTUNA_POOLS; x++) {
344 /* copy the PRNG */
345 XMEMCPY(md, &(prng->fortuna.pool[x]), sizeof(*md));
346
347 /* terminate it */
348 if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
349 goto LBL_ERR;
350 }
351
352 /* now hash it */
353 if ((err = sha256_init(md)) != CRYPT_OK) {
354 goto LBL_ERR;
355 }
356 if ((err = sha256_process(md, out+x*32, 32)) != CRYPT_OK) {
357 goto LBL_ERR;
358 }
359 if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
360 goto LBL_ERR;
361 }
362 }
363 *outlen = 32*FORTUNA_POOLS;
364 err = CRYPT_OK;
365
366 LBL_ERR:
367 #ifdef LTC_CLEAN_STACK
368 zeromem(md, sizeof(*md));
369 #endif
370 XFREE(md);
371 LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
372 return err;
373 }
374
375 /**
376 Import a PRNG state
377 @param in The PRNG state
378 @param inlen Size of the state
379 @param prng The PRNG to import
380 @return CRYPT_OK if successful
381 */
382 int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
383 {
384 int err, x;
385
386 LTC_ARGCHK(in != NULL);
387 LTC_ARGCHK(prng != NULL);
388
389 if (inlen != 32*FORTUNA_POOLS) {
390 return CRYPT_INVALID_ARG;
391 }
392
393 if ((err = fortuna_start(prng)) != CRYPT_OK) {
394 return err;
395 }
396 for (x = 0; x < FORTUNA_POOLS; x++) {
397 if ((err = fortuna_add_entropy(in+x*32, 32, prng)) != CRYPT_OK) {
398 return err;
399 }
400 }
401 return err;
402 }
403
404 /**
405 PRNG self-test
406 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
407 */
408 int fortuna_test(void)
409 {
410 #ifndef LTC_TEST
411 return CRYPT_NOP;
412 #else
413 int err;
414
415 if ((err = sha256_test()) != CRYPT_OK) {
416 return err;
417 }
418 return rijndael_test();
419 #endif
420 }
421
422 #endif
423
424
425 /* $Source: /cvs/libtom/libtomcrypt/src/prngs/fortuna.c,v $ */
426 /* $Revision: 1.12 $ */
427 /* $Date: 2006/12/04 21:34:03 $ */