• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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