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, tomstdenis@gmail.com, 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
BYTE2WORD(unsigned char * b)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
XORWORD(ulong32 w,unsigned char * b)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
cycle(ulong32 * R)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
nltap(struct sober128_prng * c)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 */
sober128_start(prng_state * prng)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 */
s128_savestate(struct sober128_prng * c)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 */
s128_reloadstate(struct sober128_prng * c)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 */
s128_genkonst(struct sober128_prng * c)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;
s128_diffuse(struct sober128_prng * c)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 */
sober128_add_entropy(const unsigned char * in,unsigned long inlen,prng_state * prng)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 */
sober128_ready(prng_state * prng)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 */
sober128_read(unsigned char * out,unsigned long outlen,prng_state * prng)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 */
sober128_done(prng_state * prng)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 */
sober128_export(unsigned char * out,unsigned long * outlen,prng_state * prng)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 */
sober128_import(const unsigned char * in,unsigned long inlen,prng_state * prng)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 */
sober128_test(void)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 $ */
501