Mercurial > dropbear
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 $ */ |