comparison sober128.c @ 143:5d99163f7e32 libtomcrypt-orig

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