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 #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 |