Mercurial > dropbear
comparison libtomcrypt/src/prngs/sober128.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 sober128.c | |
15 Implementation of SOBER-128 by Tom St Denis. | |
16 Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM. | |
17 */ | |
18 | |
19 #ifdef SOBER128 | |
20 | |
21 #include "sober128tab.c" | |
22 | |
23 const struct ltc_prng_descriptor sober128_desc = | |
24 { | |
25 "sober128", 64, | |
26 &sober128_start, | |
27 &sober128_add_entropy, | |
28 &sober128_ready, | |
29 &sober128_read, | |
30 &sober128_done, | |
31 &sober128_export, | |
32 &sober128_import, | |
33 &sober128_test | |
34 }; | |
35 | |
36 /* don't change these... */ | |
37 #define N 17 | |
38 #define FOLD N /* how many iterations of folding to do */ | |
39 #define INITKONST 0x6996c53a /* value of KONST to use during key loading */ | |
40 #define KEYP 15 /* where to insert key words */ | |
41 #define FOLDP 4 /* where to insert non-linear feedback */ | |
42 | |
43 #define B(x,i) ((unsigned char)(((x) >> (8*i)) & 0xFF)) | |
44 | |
45 static ulong32 BYTE2WORD(unsigned char *b) | |
46 { | |
47 ulong32 t; | |
48 LOAD32L(t, b); | |
49 return t; | |
50 } | |
51 | |
52 #define WORD2BYTE(w, b) STORE32L(b, w) | |
53 | |
54 static void XORWORD(ulong32 w, unsigned char *b) | |
55 { | |
56 ulong32 t; | |
57 LOAD32L(t, b); | |
58 t ^= w; | |
59 STORE32L(t, b); | |
60 } | |
61 | |
62 /* give correct offset for the current position of the register, | |
63 * where logically R[0] is at position "zero". | |
64 */ | |
65 #define OFF(zero, i) (((zero)+(i)) % N) | |
66 | |
67 /* step the LFSR */ | |
68 /* After stepping, "zero" moves right one place */ | |
69 #define STEP(R,z) \ | |
70 R[OFF(z,0)] = R[OFF(z,15)] ^ R[OFF(z,4)] ^ (R[OFF(z,0)] << 8) ^ Multab[(R[OFF(z,0)] >> 24) & 0xFF]; | |
71 | |
72 static void cycle(ulong32 *R) | |
73 { | |
74 ulong32 t; | |
75 int i; | |
76 | |
77 STEP(R,0); | |
78 t = R[0]; | |
79 for (i = 1; i < N; ++i) { | |
80 R[i-1] = R[i]; | |
81 } | |
82 R[N-1] = t; | |
83 } | |
84 | |
85 /* Return a non-linear function of some parts of the register. | |
86 */ | |
87 #define NLFUNC(c,z) \ | |
88 { \ | |
89 t = c->R[OFF(z,0)] + c->R[OFF(z,16)]; \ | |
90 t ^= Sbox[(t >> 24) & 0xFF]; \ | |
91 t = RORc(t, 8); \ | |
92 t = ((t + c->R[OFF(z,1)]) ^ c->konst) + c->R[OFF(z,6)]; \ | |
93 t ^= Sbox[(t >> 24) & 0xFF]; \ | |
94 t = t + c->R[OFF(z,13)]; \ | |
95 } | |
96 | |
97 static ulong32 nltap(struct sober128_prng *c) | |
98 { | |
99 ulong32 t; | |
100 NLFUNC(c, 0); | |
101 return t; | |
102 } | |
103 | |
104 /** | |
105 Start the PRNG | |
106 @param prng [out] The PRNG state to initialize | |
107 @return CRYPT_OK if successful | |
108 */ | |
109 int sober128_start(prng_state *prng) | |
110 { | |
111 int i; | |
112 struct sober128_prng *c; | |
113 | |
114 LTC_ARGCHK(prng != NULL); | |
115 | |
116 c = &(prng->sober128); | |
117 | |
118 /* Register initialised to Fibonacci numbers */ | |
119 c->R[0] = 1; | |
120 c->R[1] = 1; | |
121 for (i = 2; i < N; ++i) { | |
122 c->R[i] = c->R[i-1] + c->R[i-2]; | |
123 } | |
124 c->konst = INITKONST; | |
125 | |
126 /* next add_entropy will be the key */ | |
127 c->flag = 1; | |
128 c->set = 0; | |
129 | |
130 return CRYPT_OK; | |
131 } | |
132 | |
133 /* Save the current register state | |
134 */ | |
135 static void s128_savestate(struct sober128_prng *c) | |
136 { | |
137 int i; | |
138 for (i = 0; i < N; ++i) { | |
139 c->initR[i] = c->R[i]; | |
140 } | |
141 } | |
142 | |
143 /* initialise to previously saved register state | |
144 */ | |
145 static void s128_reloadstate(struct sober128_prng *c) | |
146 { | |
147 int i; | |
148 | |
149 for (i = 0; i < N; ++i) { | |
150 c->R[i] = c->initR[i]; | |
151 } | |
152 } | |
153 | |
154 /* Initialise "konst" | |
155 */ | |
156 static void s128_genkonst(struct sober128_prng *c) | |
157 { | |
158 ulong32 newkonst; | |
159 | |
160 do { | |
161 cycle(c->R); | |
162 newkonst = nltap(c); | |
163 } while ((newkonst & 0xFF000000) == 0); | |
164 c->konst = newkonst; | |
165 } | |
166 | |
167 /* Load key material into the register | |
168 */ | |
169 #define ADDKEY(k) \ | |
170 c->R[KEYP] += (k); | |
171 | |
172 #define XORNL(nl) \ | |
173 c->R[FOLDP] ^= (nl); | |
174 | |
175 /* nonlinear diffusion of register for key */ | |
176 #define DROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); c->R[OFF((z+1),FOLDP)] ^= t; | |
177 static void s128_diffuse(struct sober128_prng *c) | |
178 { | |
179 ulong32 t; | |
180 /* relies on FOLD == N == 17! */ | |
181 DROUND(0); | |
182 DROUND(1); | |
183 DROUND(2); | |
184 DROUND(3); | |
185 DROUND(4); | |
186 DROUND(5); | |
187 DROUND(6); | |
188 DROUND(7); | |
189 DROUND(8); | |
190 DROUND(9); | |
191 DROUND(10); | |
192 DROUND(11); | |
193 DROUND(12); | |
194 DROUND(13); | |
195 DROUND(14); | |
196 DROUND(15); | |
197 DROUND(16); | |
198 } | |
199 | |
200 /** | |
201 Add entropy to the PRNG state | |
202 @param in The data to add | |
203 @param inlen Length of the data to add | |
204 @param prng PRNG state to update | |
205 @return CRYPT_OK if successful | |
206 */ | |
207 int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) | |
208 { | |
209 struct sober128_prng *c; | |
210 ulong32 i, k; | |
211 | |
212 LTC_ARGCHK(in != NULL); | |
213 LTC_ARGCHK(prng != NULL); | |
214 c = &(prng->sober128); | |
215 | |
216 if (c->flag == 1) { | |
217 /* this is the first call to the add_entropy so this input is the key */ | |
218 /* inlen must be multiple of 4 bytes */ | |
219 if ((inlen & 3) != 0) { | |
220 return CRYPT_INVALID_KEYSIZE; | |
221 } | |
222 | |
223 for (i = 0; i < inlen; i += 4) { | |
224 k = BYTE2WORD((unsigned char *)&in[i]); | |
225 ADDKEY(k); | |
226 cycle(c->R); | |
227 XORNL(nltap(c)); | |
228 } | |
229 | |
230 /* also fold in the length of the key */ | |
231 ADDKEY(inlen); | |
232 | |
233 /* now diffuse */ | |
234 s128_diffuse(c); | |
235 | |
236 s128_genkonst(c); | |
237 s128_savestate(c); | |
238 c->nbuf = 0; | |
239 c->flag = 0; | |
240 c->set = 1; | |
241 } else { | |
242 /* ok we are adding an IV then... */ | |
243 s128_reloadstate(c); | |
244 | |
245 /* inlen must be multiple of 4 bytes */ | |
246 if ((inlen & 3) != 0) { | |
247 return CRYPT_INVALID_KEYSIZE; | |
248 } | |
249 | |
250 for (i = 0; i < inlen; i += 4) { | |
251 k = BYTE2WORD((unsigned char *)&in[i]); | |
252 ADDKEY(k); | |
253 cycle(c->R); | |
254 XORNL(nltap(c)); | |
255 } | |
256 | |
257 /* also fold in the length of the key */ | |
258 ADDKEY(inlen); | |
259 | |
260 /* now diffuse */ | |
261 s128_diffuse(c); | |
262 c->nbuf = 0; | |
263 } | |
264 | |
265 return CRYPT_OK; | |
266 } | |
267 | |
268 /** | |
269 Make the PRNG ready to read from | |
270 @param prng The PRNG to make active | |
271 @return CRYPT_OK if successful | |
272 */ | |
273 int sober128_ready(prng_state *prng) | |
274 { | |
275 return prng->sober128.set == 1 ? CRYPT_OK : CRYPT_ERROR; | |
276 } | |
277 | |
278 /* XOR pseudo-random bytes into buffer | |
279 */ | |
280 #define SROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); XORWORD(t, out+(z*4)); | |
281 | |
282 /** | |
283 Read from the PRNG | |
284 @param out Destination | |
285 @param outlen Length of output | |
286 @param prng The active PRNG to read from | |
287 @return Number of octets read | |
288 */ | |
289 unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng) | |
290 { | |
291 struct sober128_prng *c; | |
292 ulong32 t, tlen; | |
293 | |
294 LTC_ARGCHK(out != NULL); | |
295 LTC_ARGCHK(prng != NULL); | |
296 | |
297 #ifdef LTC_VALGRIND | |
298 zeromem(out, outlen); | |
299 #endif | |
300 | |
301 c = &(prng->sober128); | |
302 t = 0; | |
303 tlen = outlen; | |
304 | |
305 /* handle any previously buffered bytes */ | |
306 while (c->nbuf != 0 && outlen != 0) { | |
307 *out++ ^= c->sbuf & 0xFF; | |
308 c->sbuf >>= 8; | |
309 c->nbuf -= 8; | |
310 --outlen; | |
311 } | |
312 | |
313 #ifndef LTC_SMALL_CODE | |
314 /* do lots at a time, if there's enough to do */ | |
315 while (outlen >= N*4) { | |
316 SROUND(0); | |
317 SROUND(1); | |
318 SROUND(2); | |
319 SROUND(3); | |
320 SROUND(4); | |
321 SROUND(5); | |
322 SROUND(6); | |
323 SROUND(7); | |
324 SROUND(8); | |
325 SROUND(9); | |
326 SROUND(10); | |
327 SROUND(11); | |
328 SROUND(12); | |
329 SROUND(13); | |
330 SROUND(14); | |
331 SROUND(15); | |
332 SROUND(16); | |
333 out += 4*N; | |
334 outlen -= 4*N; | |
335 } | |
336 #endif | |
337 | |
338 /* do small or odd size buffers the slow way */ | |
339 while (4 <= outlen) { | |
340 cycle(c->R); | |
341 t = nltap(c); | |
342 XORWORD(t, out); | |
343 out += 4; | |
344 outlen -= 4; | |
345 } | |
346 | |
347 /* handle any trailing bytes */ | |
348 if (outlen != 0) { | |
349 cycle(c->R); | |
350 c->sbuf = nltap(c); | |
351 c->nbuf = 32; | |
352 while (c->nbuf != 0 && outlen != 0) { | |
353 *out++ ^= c->sbuf & 0xFF; | |
354 c->sbuf >>= 8; | |
355 c->nbuf -= 8; | |
356 --outlen; | |
357 } | |
358 } | |
359 | |
360 return tlen; | |
361 } | |
362 | |
363 /** | |
364 Terminate the PRNG | |
365 @param prng The PRNG to terminate | |
366 @return CRYPT_OK if successful | |
367 */ | |
368 int sober128_done(prng_state *prng) | |
369 { | |
370 LTC_ARGCHK(prng != NULL); | |
371 return CRYPT_OK; | |
372 } | |
373 | |
374 /** | |
375 Export the PRNG state | |
376 @param out [out] Destination | |
377 @param outlen [in/out] Max size and resulting size of the state | |
378 @param prng The PRNG to export | |
379 @return CRYPT_OK if successful | |
380 */ | |
381 int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng) | |
382 { | |
383 LTC_ARGCHK(outlen != NULL); | |
384 LTC_ARGCHK(out != NULL); | |
385 LTC_ARGCHK(prng != NULL); | |
386 | |
387 if (*outlen < 64) { | |
388 *outlen = 64; | |
389 return CRYPT_BUFFER_OVERFLOW; | |
390 } | |
391 | |
392 if (sober128_read(out, 64, prng) != 64) { | |
393 return CRYPT_ERROR_READPRNG; | |
394 } | |
395 *outlen = 64; | |
396 | |
397 return CRYPT_OK; | |
398 } | |
399 | |
400 /** | |
401 Import a PRNG state | |
402 @param in The PRNG state | |
403 @param inlen Size of the state | |
404 @param prng The PRNG to import | |
405 @return CRYPT_OK if successful | |
406 */ | |
407 int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng) | |
408 { | |
409 int err; | |
410 LTC_ARGCHK(in != NULL); | |
411 LTC_ARGCHK(prng != NULL); | |
412 | |
413 if (inlen != 64) { | |
414 return CRYPT_INVALID_ARG; | |
415 } | |
416 | |
417 if ((err = sober128_start(prng)) != CRYPT_OK) { | |
418 return err; | |
419 } | |
420 if ((err = sober128_add_entropy(in, 64, prng)) != CRYPT_OK) { | |
421 return err; | |
422 } | |
423 return sober128_ready(prng); | |
424 } | |
425 | |
426 /** | |
427 PRNG self-test | |
428 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled | |
429 */ | |
430 int sober128_test(void) | |
431 { | |
432 #ifndef LTC_TEST | |
433 return CRYPT_NOP; | |
434 #else | |
435 static const struct { | |
436 int keylen, ivlen, len; | |
437 unsigned char key[16], iv[4], out[20]; | |
438 } tests[] = { | |
439 | |
440 { | |
441 16, 4, 20, | |
442 | |
443 /* key */ | |
444 { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6b, 0x65, 0x79, | |
445 0x20, 0x31, 0x32, 0x38, 0x62, 0x69, 0x74, 0x73 }, | |
446 | |
447 /* IV */ | |
448 { 0x00, 0x00, 0x00, 0x00 }, | |
449 | |
450 /* expected output */ | |
451 { 0x43, 0x50, 0x0c, 0xcf, 0x89, 0x91, 0x9f, 0x1d, | |
452 0xaa, 0x37, 0x74, 0x95, 0xf4, 0xb4, 0x58, 0xc2, | |
453 0x40, 0x37, 0x8b, 0xbb } | |
454 } | |
455 | |
456 }; | |
457 prng_state prng; | |
458 unsigned char dst[20]; | |
459 int err, x; | |
460 | |
461 for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { | |
462 if ((err = sober128_start(&prng)) != CRYPT_OK) { | |
463 return err; | |
464 } | |
465 if ((err = sober128_add_entropy(tests[x].key, tests[x].keylen, &prng)) != CRYPT_OK) { | |
466 return err; | |
467 } | |
468 /* add IV */ | |
469 if ((err = sober128_add_entropy(tests[x].iv, tests[x].ivlen, &prng)) != CRYPT_OK) { | |
470 return err; | |
471 } | |
472 | |
473 /* ready up */ | |
474 if ((err = sober128_ready(&prng)) != CRYPT_OK) { | |
475 return err; | |
476 } | |
477 XMEMSET(dst, 0, tests[x].len); | |
478 if (sober128_read(dst, tests[x].len, &prng) != (unsigned long)tests[x].len) { | |
479 return CRYPT_ERROR_READPRNG; | |
480 } | |
481 sober128_done(&prng); | |
482 if (XMEMCMP(dst, tests[x].out, tests[x].len)) { | |
483 #if 0 | |
484 printf("\n\nSOBER128 failed, I got:\n"); | |
485 for (y = 0; y < tests[x].len; y++) printf("%02x ", dst[y]); | |
486 printf("\n"); | |
487 #endif | |
488 return CRYPT_FAIL_TESTVECTOR; | |
489 } | |
490 } | |
491 return CRYPT_OK; | |
492 #endif | |
493 } | |
494 | |
495 #endif | |
496 | |
497 | |
498 /* $Source: /cvs/libtom/libtomcrypt/src/prngs/sober128.c,v $ */ | |
499 /* $Revision: 1.8 $ */ | |
500 /* $Date: 2006/11/05 00:11:36 $ */ |