143
|
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.org |
|
10 */ |
|
11 |
|
12 /* Implementation of Fortuna by Tom St Denis |
|
13 |
|
14 We deviate slightly here for reasons of simplicity [and to fit in the API]. First all "sources" |
|
15 in the AddEntropy function are fixed to 0. Second since no reliable timer is provided |
|
16 we reseed automatically when len(pool0) >= 64 or every FORTUNA_WD calls to the read function */ |
|
17 |
|
18 #include "mycrypt.h" |
|
19 |
|
20 #ifdef FORTUNA |
|
21 |
|
22 /* requries SHA256 and AES */ |
|
23 #if !(defined(RIJNDAEL) && defined(SHA256)) |
|
24 #error FORTUNA requires SHA256 and RIJNDAEL (AES) |
|
25 #endif |
|
26 |
|
27 #ifndef FORTUNA_POOLS |
|
28 #warning FORTUNA_POOLS was not previously defined (old headers?) |
|
29 #define FORTUNA_POOLS 32 |
|
30 #endif |
|
31 |
|
32 #if FORTUNA_POOLS < 4 || FORTUNA_POOLS > 32 |
|
33 #error FORTUNA_POOLS must be in [4..32] |
|
34 #endif |
|
35 |
|
36 const struct _prng_descriptor fortuna_desc = { |
|
37 "fortuna", 1024, |
|
38 &fortuna_start, |
|
39 &fortuna_add_entropy, |
|
40 &fortuna_ready, |
|
41 &fortuna_read, |
|
42 &fortuna_done, |
|
43 &fortuna_export, |
|
44 &fortuna_import, |
|
45 &fortuna_test |
|
46 }; |
|
47 |
|
48 /* update the IV */ |
|
49 static void fortuna_update_iv(prng_state *prng) |
|
50 { |
|
51 int x; |
|
52 unsigned char *IV; |
|
53 /* update IV */ |
|
54 IV = prng->fortuna.IV; |
|
55 for (x = 0; x < 16; x++) { |
|
56 IV[x] = (IV[x] + 1) & 255; |
|
57 if (IV[x] != 0) break; |
|
58 } |
|
59 } |
|
60 |
|
61 /* reseed the PRNG */ |
|
62 static int fortuna_reseed(prng_state *prng) |
|
63 { |
|
64 unsigned char tmp[MAXBLOCKSIZE]; |
|
65 hash_state md; |
|
66 int err, x; |
|
67 |
|
68 ++prng->fortuna.reset_cnt; |
|
69 |
|
70 /* new K == SHA256(K || s) where s == SHA256(P0) || SHA256(P1) ... */ |
|
71 sha256_init(&md); |
|
72 if ((err = sha256_process(&md, prng->fortuna.K, 32)) != CRYPT_OK) { |
|
73 return err; |
|
74 } |
|
75 |
|
76 for (x = 0; x < FORTUNA_POOLS; x++) { |
|
77 if (x == 0 || ((prng->fortuna.reset_cnt >> (x-1)) & 1) == 0) { |
|
78 /* terminate this hash */ |
|
79 if ((err = sha256_done(&prng->fortuna.pool[x], tmp)) != CRYPT_OK) { |
|
80 return err; |
|
81 } |
|
82 /* add it to the string */ |
|
83 if ((err = sha256_process(&md, tmp, 32)) != CRYPT_OK) { |
|
84 return err; |
|
85 } |
|
86 /* reset this pool */ |
|
87 sha256_init(&prng->fortuna.pool[x]); |
|
88 } else { |
|
89 break; |
|
90 } |
|
91 } |
|
92 |
|
93 /* finish key */ |
|
94 if ((err = sha256_done(&md, prng->fortuna.K)) != CRYPT_OK) { |
|
95 return err; |
|
96 } |
|
97 if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) { |
|
98 return err; |
|
99 } |
|
100 fortuna_update_iv(prng); |
|
101 |
|
102 /* reset pool len */ |
|
103 prng->fortuna.pool0_len = 0; |
|
104 prng->fortuna.wd = 0; |
|
105 |
|
106 |
|
107 #ifdef CLEAN_STACK |
|
108 zeromem(&md, sizeof(md)); |
|
109 zeromem(tmp, sizeof(tmp)); |
|
110 #endif |
|
111 |
|
112 return CRYPT_OK; |
|
113 } |
|
114 |
|
115 int fortuna_start(prng_state *prng) |
|
116 { |
|
117 int err, x; |
|
118 |
|
119 _ARGCHK(prng != NULL); |
|
120 |
|
121 /* initialize the pools */ |
|
122 for (x = 0; x < FORTUNA_POOLS; x++) { |
|
123 sha256_init(&prng->fortuna.pool[x]); |
|
124 } |
|
125 prng->fortuna.pool_idx = prng->fortuna.pool0_len = prng->fortuna.reset_cnt = |
|
126 prng->fortuna.wd = 0; |
|
127 |
|
128 /* reset bufs */ |
|
129 zeromem(prng->fortuna.K, 32); |
|
130 if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) { |
|
131 return err; |
|
132 } |
|
133 zeromem(prng->fortuna.IV, 16); |
|
134 |
|
135 return CRYPT_OK; |
|
136 } |
|
137 |
|
138 int fortuna_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng) |
|
139 { |
|
140 unsigned char tmp[2]; |
|
141 int err; |
|
142 |
|
143 _ARGCHK(buf != NULL); |
|
144 _ARGCHK(prng != NULL); |
|
145 |
|
146 /* ensure len <= 32 */ |
|
147 if (len > 32) { |
|
148 return CRYPT_INVALID_ARG; |
|
149 } |
|
150 |
|
151 /* add s || length(buf) || buf to pool[pool_idx] */ |
|
152 tmp[0] = 0; |
|
153 tmp[1] = len; |
|
154 if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], tmp, 2)) != CRYPT_OK) { |
|
155 return err; |
|
156 } |
|
157 if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], buf, len)) != CRYPT_OK) { |
|
158 return err; |
|
159 } |
|
160 if (prng->fortuna.pool_idx == 0) { |
|
161 prng->fortuna.pool0_len += len; |
|
162 } |
|
163 if (++(prng->fortuna.pool_idx) == FORTUNA_POOLS) { |
|
164 prng->fortuna.pool_idx = 0; |
|
165 } |
|
166 |
|
167 return CRYPT_OK; |
|
168 } |
|
169 |
|
170 int fortuna_ready(prng_state *prng) |
|
171 { |
|
172 return fortuna_reseed(prng); |
|
173 } |
|
174 |
|
175 unsigned long fortuna_read(unsigned char *dst, unsigned long len, prng_state *prng) |
|
176 { |
|
177 unsigned char tmp[16]; |
|
178 int err; |
|
179 unsigned long tlen; |
|
180 |
|
181 _ARGCHK(dst != NULL); |
|
182 _ARGCHK(prng != NULL); |
|
183 |
|
184 /* do we have to reseed? */ |
|
185 if (++prng->fortuna.wd == FORTUNA_WD || prng->fortuna.pool0_len >= 64) { |
|
186 if ((err = fortuna_reseed(prng)) != CRYPT_OK) { |
|
187 return 0; |
|
188 } |
|
189 } |
|
190 |
|
191 /* now generate the blocks required */ |
|
192 tlen = len; |
|
193 |
|
194 /* handle whole blocks without the extra memcpy */ |
|
195 while (len >= 16) { |
|
196 /* encrypt the IV and store it */ |
|
197 rijndael_ecb_encrypt(prng->fortuna.IV, dst, &prng->fortuna.skey); |
|
198 dst += 16; |
|
199 len -= 16; |
|
200 fortuna_update_iv(prng); |
|
201 } |
|
202 |
|
203 /* left over bytes? */ |
|
204 if (len > 0) { |
|
205 rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey); |
|
206 XMEMCPY(dst, tmp, len); |
|
207 fortuna_update_iv(prng); |
|
208 } |
|
209 |
|
210 /* generate new key */ |
|
211 rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K , &prng->fortuna.skey); fortuna_update_iv(prng); |
|
212 rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K+16, &prng->fortuna.skey); fortuna_update_iv(prng); |
|
213 if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) { |
|
214 return 0; |
|
215 } |
|
216 |
|
217 #ifdef CLEAN_STACK |
|
218 zeromem(tmp, sizeof(tmp)); |
|
219 #endif |
|
220 return tlen; |
|
221 } |
|
222 |
|
223 int fortuna_done(prng_state *prng) |
|
224 { |
|
225 int err, x; |
|
226 unsigned char tmp[32]; |
|
227 |
|
228 _ARGCHK(prng != NULL); |
|
229 |
|
230 /* terminate all the hashes */ |
|
231 for (x = 0; x < FORTUNA_POOLS; x++) { |
|
232 if ((err = sha256_done(&(prng->fortuna.pool[x]), tmp)) != CRYPT_OK) { |
|
233 return err; |
|
234 } |
|
235 } |
|
236 /* call cipher done when we invent one ;-) */ |
|
237 |
|
238 #ifdef CLEAN_STACK |
|
239 zeromem(tmp, sizeof(tmp)); |
|
240 #endif |
|
241 |
|
242 return CRYPT_OK; |
|
243 } |
|
244 |
|
245 int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng) |
|
246 { |
|
247 int x, err; |
|
248 hash_state *md; |
|
249 |
|
250 _ARGCHK(out != NULL); |
|
251 _ARGCHK(outlen != NULL); |
|
252 _ARGCHK(prng != NULL); |
|
253 |
|
254 /* we'll write bytes for s&g's */ |
|
255 if (*outlen < 32*FORTUNA_POOLS) { |
|
256 return CRYPT_BUFFER_OVERFLOW; |
|
257 } |
|
258 |
|
259 md = XMALLOC(sizeof(hash_state)); |
|
260 if (md == NULL) { |
|
261 return CRYPT_MEM; |
|
262 } |
|
263 |
|
264 /* to emit the state we copy each pool, terminate it then hash it again so |
|
265 * an attacker who sees the state can't determine the current state of the PRNG |
|
266 */ |
|
267 for (x = 0; x < FORTUNA_POOLS; x++) { |
|
268 /* copy the PRNG */ |
|
269 XMEMCPY(md, &(prng->fortuna.pool[x]), sizeof(*md)); |
|
270 |
|
271 /* terminate it */ |
|
272 if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) { |
|
273 goto __ERR; |
|
274 } |
|
275 |
|
276 /* now hash it */ |
|
277 if ((err = sha256_init(md)) != CRYPT_OK) { |
|
278 goto __ERR; |
|
279 } |
|
280 if ((err = sha256_process(md, out+x*32, 32)) != CRYPT_OK) { |
|
281 goto __ERR; |
|
282 } |
|
283 if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) { |
|
284 goto __ERR; |
|
285 } |
|
286 } |
|
287 *outlen = 32*FORTUNA_POOLS; |
|
288 err = CRYPT_OK; |
|
289 |
|
290 __ERR: |
|
291 #ifdef CLEAN_STACK |
|
292 zeromem(md, sizeof(*md)); |
|
293 #endif |
|
294 XFREE(md); |
|
295 return err; |
|
296 } |
|
297 |
|
298 int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng) |
|
299 { |
|
300 int err, x; |
|
301 |
|
302 _ARGCHK(in != NULL); |
|
303 _ARGCHK(prng != NULL); |
|
304 |
|
305 if (inlen != 32*FORTUNA_POOLS) { |
|
306 return CRYPT_INVALID_ARG; |
|
307 } |
|
308 |
|
309 if ((err = fortuna_start(prng)) != CRYPT_OK) { |
|
310 return err; |
|
311 } |
|
312 for (x = 0; x < FORTUNA_POOLS; x++) { |
|
313 if ((err = fortuna_add_entropy(in+x*32, 32, prng)) != CRYPT_OK) { |
|
314 return err; |
|
315 } |
|
316 } |
|
317 return err; |
|
318 } |
|
319 |
|
320 int fortuna_test(void) |
|
321 { |
|
322 #ifndef LTC_TEST |
|
323 return CRYPT_NOP; |
|
324 #else |
|
325 int err; |
|
326 |
|
327 if ((err = sha256_test()) != CRYPT_OK) { |
|
328 return err; |
|
329 } |
|
330 return rijndael_test(); |
|
331 #endif |
|
332 } |
|
333 |
|
334 #endif |
|
335 |