New function and example program computes Fibonacci numbers fairly fast.
[u/mdw/catacomb] / seal.c
1 /* -*-c-*-
2 *
3 * $Id: seal.c,v 1.2 2004/04/08 01:36:15 mdw Exp $
4 *
5 * The SEAL pseudo-random function family
6 *
7 * (c) 2000 Straylight/Edgeware
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30 /*----- Header files ------------------------------------------------------*/
31
32 #include <assert.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35
36 #include <mLib/bits.h>
37
38 #include "arena.h"
39 #include "gcipher.h"
40 #include "grand.h"
41 #include "paranoia.h"
42 #include "seal.h"
43 #include "sha.h"
44
45 /*----- Global variables --------------------------------------------------*/
46
47 const octet seal_keysz[] = { KSZ_ANY, SHA_HASHSZ };
48
49 /*----- Main code ---------------------------------------------------------*/
50
51 /* --- @gamma@ --- *
52 *
53 * Arguments: @uint32 *p@ = output table
54 * @size_t sz@ = size of the output table
55 * @const void *k@ = pointer to key material
56 * @unsigned i@ = integer offset
57 *
58 * Returns: ---
59 *
60 * Use: Initializes a SEAL key table.
61 */
62
63 static void gamma(uint32 *p, size_t sz, const void *k, unsigned i)
64 {
65 uint32 buf[80] = { 0 };
66 const octet *kk = k;
67 uint32 aa = LOAD32(kk);
68 uint32 bb = LOAD32(kk + 4);
69 uint32 cc = LOAD32(kk + 8);
70 uint32 dd = LOAD32(kk + 12);
71 uint32 ee = LOAD32(kk + 16);
72
73 unsigned skip = i % 5;
74 i /= 5;
75
76 /* --- While there's hashing to do, do hashing --- */
77
78 while (sz) {
79 uint32 a = aa, b = bb, c = cc, d = dd, e = ee;
80 int j;
81
82 /* --- Initialize and expand the buffer --- */
83
84 buf[0] = i++;
85
86 for (j = 16; j < 80; j++) {
87 uint32 x = buf[j - 3] ^ buf[j - 8] ^ buf[j - 14] ^ buf[j - 16];
88 buf[j] = ROL32(x, 1);
89 }
90
91 /* --- Definitions for round functions --- */
92
93 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
94 #define G(x, y, z) ((x) ^ (y) ^ (z))
95 #define H(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
96
97 #define T(v, w, x, y, z, i, f, k) do { \
98 uint32 _x; \
99 z = ROL32(v, 5) + f(w, x, y) + z + buf[i] + k; \
100 w = ROR32(w, 2); \
101 _x = v; v = z; z = y; y = x; x = w; w = _x; \
102 } while (0)
103
104 #define FF(v, w, x, y, z, i) T(v, w, x, y, z, i, F, 0x5a827999)
105 #define GG(v, w, x, y, z, i) T(v, w, x, y, z, i, G, 0x6ed9eba1)
106 #define HH(v, w, x, y, z, i) T(v, w, x, y, z, i, H, 0x8f1bbcdc)
107 #define II(v, w, x, y, z, i) T(v, w, x, y, z, i, G, 0xca62c1d6)
108
109 /* --- The main compression function --- *
110 *
111 * Since this isn't doing bulk hashing, do it the easy way.
112 */
113
114 for (j = 0; j < 20; j++)
115 FF(a, b, c, d, e, j);
116 for (j = 20; j < 40; j++)
117 GG(a, b, c, d, e, j);
118 for (j = 40; j < 60; j++)
119 HH(a, b, c, d, e, j);
120 for (j = 60; j < 80; j++)
121 II(a, b, c, d, e, j);
122
123 /* --- Do the chaining at the end --- */
124
125 a += aa; b += bb; c += cc; d += dd; e += ee;
126
127 /* --- Write to the output buffer --- */
128
129 switch (skip) {
130 case 0:
131 if (sz) { *p++ = a; sz--; }
132 case 1:
133 if (sz) { *p++ = b; sz--; }
134 case 2:
135 if (sz) { *p++ = c; sz--; }
136 case 3:
137 if (sz) { *p++ = d; sz--; }
138 case 4:
139 if (sz) { *p++ = e; sz--; }
140 skip = 0;
141 }
142 }
143 }
144
145 /* --- @seal_initkey@ --- *
146 *
147 * Arguments: @seal_key *k@ = pointer to key block
148 * @const void *buf@ = pointer to key material
149 * @size_t sz@ = size of the key material
150 *
151 * Returns: ---
152 *
153 * Use: Initializes a SEAL key block. The key material may be any
154 * size, but if it's not 20 bytes long it's passed to SHA for
155 * hashing first.
156 */
157
158 void seal_initkey(seal_key *k, const void *buf, size_t sz)
159 {
160 /* --- Hash the key if it's the wrong size --- */
161
162 if (sz == SHA_HASHSZ)
163 memcpy(k->k, buf, sizeof(k->k));
164 else {
165 sha_ctx c;
166 sha_init(&c);
167 sha_hash(&c, buf, sz);
168 sha_done(&c, k->k);
169 }
170
171 /* --- Expand the key to fit the various tables --- */
172
173 gamma(k->t, 512, k->k, 0);
174 gamma(k->s, 256, k->k, 0x1000);
175 gamma(k->r, SEAL_R, k->k, 0x2000);
176 }
177
178 /* --- @seal_reset@ --- *
179 *
180 * Arguments: @seal_ctx *c@ = pointer to a SEAL context
181 *
182 * Returns: ---
183 *
184 * Use: Resets the context so that more data can be extracted from
185 * it.
186 */
187
188 static void seal_reset(seal_ctx *c)
189 {
190 seal_key *k = c->k;
191 uint32 n = c->n;
192 uint32 A, B, C, D;
193 unsigned p;
194
195 /* --- Initialize the new chaining variables --- */
196
197 if (c->l >= SEAL_R) {
198 gamma(c->rbuf, SEAL_R, k->k, c->ri);
199 c->ri += SEAL_R;
200 c->l = 0;
201 c->r = c->rbuf;
202 }
203
204 A = n ^ c->r[0];
205 B = ROR32(n, 8) ^ c->r[1];
206 C = ROR32(n, 16) ^ c->r[2];
207 D = ROR32(n, 24) ^ c->r[3];
208 c->l += 4;
209 c->r += 4;
210
211 /* --- Ensure that everything is sufficiently diffused --- */
212
213 p = A & 0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
214 p = B & 0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
215 p = C & 0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
216 p = D & 0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
217 p = A & 0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
218 p = B & 0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
219 p = C & 0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
220 p = D & 0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
221
222 /* --- Write out some context --- */
223
224 c->n1 = D; c->n2 = B; c->n3 = A; c->n4 = C;
225
226 /* --- Diffuse some more --- */
227
228 p = A & 0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
229 p = B & 0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
230 p = C & 0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
231 p = D & 0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
232
233 /* --- Write out the magic numbers --- */
234
235 c->a = A; c->b = B; c->c = C; c->d = D;
236 c->i = 0;
237 }
238
239 /* --- @seal_initctx@ --- *
240 *
241 * Arguments: @seal_ctx *c@ = pointer to a SEAL context
242 * @seal_key *k@ = pointer to a SEAL key
243 * @uint32 n@ = integer sequence number
244 *
245 * Returns: ---
246 *
247 * Use: Initializes a SEAL context which can be used for random
248 * number generation or whatever.
249 */
250
251 void seal_initctx(seal_ctx *c, seal_key *k, uint32 n)
252 {
253 c->k = k;
254 c->n = n;
255 c->l = 0;
256 c->r = k->r;
257 c->ri = 0x2000 + SEAL_R;
258 c->qsz = 0;
259 seal_reset(c);
260 }
261
262 /* --- @seal_encrypt@ --- *
263 *
264 * Arguments: @seal_ctx *c@ = pointer to a SEAL context
265 * @const void *src@ = pointer to source data
266 * @void *dest@ = pointer to destination data
267 * @size_t sz@ = size of the data
268 *
269 * Returns: ---
270 *
271 * Use: Encrypts a block of data using SEAL. If @src@ is zero,
272 * @dest@ is filled with SEAL output. If @dest@ is zero, the
273 * SEAL generator is just spun around for a bit. This shouldn't
274 * be necessary, because SEAL isn't RC4.
275 */
276
277 void seal_encrypt(seal_ctx *c, const void *src, void *dest, size_t sz)
278 {
279 const octet *s = src;
280 octet *d = dest;
281
282 /* --- Expect a big dollop of bytes --- */
283
284 if (sz > c->qsz) {
285 seal_key *k = c->k;
286 uint32 A = c->a, B = c->b, C = c->c, D = c->d;
287 uint32 n1 = c->n1, n2 = c->n2, n3 = c->n3, n4 = c->n4;
288 uint32 aa, bb, cc, dd;
289 unsigned j = c->i;
290
291 /* --- Empty the queue first --- */
292
293 if (c->qsz) {
294 if (d) {
295 unsigned i;
296 octet *p = c->q + sizeof(c->q) - c->qsz;
297 for (i = 0; i < c->qsz; i++)
298 *d++ = (s ? *s++ ^ *p++ : *p++);
299 }
300 sz -= c->qsz;
301 }
302
303 /* --- Main sequence --- */
304
305 for (;;) {
306 unsigned P, Q;
307
308 /* --- Reset if we've run out of steam on this iteration --- */
309
310 if (j == 256) {
311 seal_reset(c);
312 A = c->a, B = c->b, C = c->c, D = c->d;
313 n1 = c->n1, n2 = c->n2, n3 = c->n3, n4 = c->n4;
314 j = 0;
315 }
316
317 /* --- Make some new numbers --- */
318
319 P = A & 0x7fc; B += k->t[P >> 2]; A = ROR32(A, 9); B ^= A;
320 Q = B & 0x7fc; C ^= k->t[Q >> 2]; B = ROR32(B, 9); C += B;
321 P = (P + C) & 0x7fc; D += k->t[P >> 2]; C = ROR32(C, 9); D ^= C;
322 Q = (Q + D) & 0x7fc; A ^= k->t[Q >> 2]; D = ROR32(D, 9); A += D;
323 P = (P + A) & 0x7fc; B ^= k->t[P >> 2]; A = ROR32(A, 9);
324 Q = (Q + B) & 0x7fc; C += k->t[Q >> 2]; B = ROR32(B, 9);
325 P = (P + C) & 0x7fc; D ^= k->t[P >> 2]; C = ROR32(C, 9);
326 Q = (Q + D) & 0x7fc; A += k->t[Q >> 2]; D = ROR32(D, 9);
327
328 /* --- Remember the output and set up the next round --- */
329
330 aa = B + k->s[j + 0];
331 bb = C ^ k->s[j + 1];
332 cc = D + k->s[j + 2];
333 dd = A ^ k->s[j + 3];
334 j += 4;
335
336 if (j & 4)
337 A += n1, B += n2, C ^= n1, D ^= n2;
338 else
339 A += n3, B += n4, C ^= n3, D ^= n4;
340
341 /* --- Bail out here if we need to do buffering --- */
342
343 if (sz < 16)
344 break;
345
346 /* --- Write the next 16 bytes --- */
347
348 if (d) {
349 if (s) {
350 aa ^= LOAD32_L(s + 0);
351 bb ^= LOAD32_L(s + 4);
352 cc ^= LOAD32_L(s + 8);
353 dd ^= LOAD32_L(s + 12);
354 s += 16;
355 }
356 STORE32_L(d + 0, aa);
357 STORE32_L(d + 4, bb);
358 STORE32_L(d + 8, cc);
359 STORE32_L(d + 12, dd);
360 d += 16;
361 }
362 sz -= 16;
363 }
364
365 /* --- Write the new queue --- */
366
367 STORE32_L(c->q + 0, aa);
368 STORE32_L(c->q + 4, bb);
369 STORE32_L(c->q + 8, cc);
370 STORE32_L(c->q + 12, dd);
371 c->qsz = 16;
372
373 c->a = A; c->b = B; c->c = C; c->d = D;
374 c->i = j;
375 }
376
377 /* --- Deal with the rest from the queue --- */
378
379 if (sz) {
380 unsigned i;
381 octet *p = c->q + sizeof(c->q) - c->qsz;
382 if (d) {
383 for (i = 0; i < sz; i++)
384 *d++ = (s ? *s++ ^ *p++ : *p++);
385 }
386 c->qsz -= sz;
387 }
388 }
389
390 /*----- Generic cipher interface ------------------------------------------*/
391
392 typedef struct gctx {
393 gcipher c;
394 seal_key k;
395 seal_ctx cc;
396 } gctx;
397
398 static const gcipher_ops gops;
399
400 static gcipher *ginit(const void *k, size_t sz)
401 {
402 gctx *g = S_CREATE(gctx);
403 g->c.ops = &gops;
404 seal_initkey(&g->k, k, sz);
405 seal_initctx(&g->cc, &g->k, 0);
406 return (&g->c);
407 }
408
409 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)
410 {
411 gctx *g = (gctx *)c;
412 seal_encrypt(&g->cc, s, t, sz);
413 }
414
415 static void gsetiv(gcipher *c, const void *iv)
416 {
417 gctx *g = (gctx *)c;
418 uint32 n = *(const uint32 *)iv;
419 seal_initctx(&g->cc, &g->k, n);
420 }
421
422 static void gdestroy(gcipher *c)
423 {
424 gctx *g = (gctx *)c;
425 BURN(*g);
426 S_DESTROY(g);
427 }
428
429 static const gcipher_ops gops = {
430 &seal,
431 gencrypt, gencrypt, gdestroy, gsetiv, 0
432 };
433
434 const gccipher seal = {
435 "seal", seal_keysz, 0,
436 ginit
437 };
438
439 /*----- Generic random number generator interface -------------------------*/
440
441 typedef struct grctx {
442 grand r;
443 seal_key k;
444 seal_ctx cc;
445 } grctx;
446
447 static void grdestroy(grand *r)
448 {
449 grctx *g = (grctx *)r;
450 BURN(*g);
451 S_DESTROY(g);
452 }
453
454 static int grmisc(grand *r, unsigned op, ...)
455 {
456 grctx *g = (grctx *)r;
457 va_list ap;
458 int rc = 0;
459 va_start(ap, op);
460
461 switch (op) {
462 case GRAND_CHECK:
463 switch (va_arg(ap, unsigned)) {
464 case GRAND_CHECK:
465 case GRAND_SEEDINT:
466 case GRAND_SEEDUINT32:
467 case GRAND_SEEDBLOCK:
468 case GRAND_SEEDRAND:
469 rc = 1;
470 break;
471 default:
472 rc = 0;
473 break;
474 }
475 break;
476 case GRAND_SEEDINT:
477 seal_initctx(&g->cc, &g->k, va_arg(ap, int));
478 break;
479 case GRAND_SEEDUINT32:
480 seal_initctx(&g->cc, &g->k, va_arg(ap, uint32));
481 break;
482 case GRAND_SEEDBLOCK: {
483 const void *p = va_arg(ap, const void *);
484 size_t sz = va_arg(ap, size_t);
485 uint32 n;
486 if (sz >= 4)
487 n = LOAD32_L(p);
488 else {
489 octet buf[4] = { 0 };
490 memcpy(buf, p, sz);
491 n = LOAD32_L(p);
492 }
493 seal_initctx(&g->cc, &g->k, n);
494 } break;
495 case GRAND_SEEDRAND: {
496 grand *rr = va_arg(ap, grand *);
497 seal_initctx(&g->cc, &g->k, rr->ops->word(rr));
498 } break;
499 default:
500 GRAND_BADOP;
501 break;
502 }
503
504 va_end(ap);
505 return (rc);
506 }
507
508 static octet grbyte(grand *r)
509 {
510 grctx *g = (grctx *)r;
511 octet o;
512 seal_encrypt(&g->cc, 0, &o, 1);
513 return (o);
514 }
515
516 static uint32 grword(grand *r)
517 {
518 grctx *g = (grctx *)r;
519 octet b[4];
520 seal_encrypt(&g->cc, 0, b, 4);
521 return (LOAD32(b));
522 }
523
524 static void grfill(grand *r, void *p, size_t sz)
525 {
526 grctx *g = (grctx *)r;
527 seal_encrypt(&g->cc, 0, p, sz);
528 }
529
530 static const grand_ops grops = {
531 "seal",
532 GRAND_CRYPTO, 0,
533 grmisc, grdestroy,
534 grword, grbyte, grword, grand_range, grfill
535 };
536
537 /* --- @seal_rand@ --- *
538 *
539 * Arguments: @const void *k@ = pointer to key material
540 * @size_t sz@ = size of key material
541 * @uint32 n@ = sequence number
542 *
543 * Returns: Pointer to generic random number generator interface.
544 *
545 * Use: Creates a random number interface wrapper around a SEAL
546 * pseudorandom function.
547 */
548
549 grand *seal_rand(const void *k, size_t sz, uint32 n)
550 {
551 grctx *g = S_CREATE(grctx);
552 g->r.ops = &grops;
553 seal_initkey(&g->k, k, sz);
554 seal_initctx(&g->cc, &g->k, n);
555 return (&g->r);
556 }
557
558 /*----- Test rig ----------------------------------------------------------*/
559
560 #ifdef TEST_RIG
561
562 #include <string.h>
563
564 #include <mLib/testrig.h>
565
566 static int verify(dstr *v)
567 {
568 seal_key k;
569 seal_ctx c;
570 uint32 n = *(uint32 *)v[1].buf;
571 dstr d = DSTR_INIT;
572 dstr z = DSTR_INIT;
573 int i;
574 int ok = 1;
575
576 DENSURE(&d, v[2].len);
577 DENSURE(&z, v[2].len);
578 memset(z.buf, 0, v[2].len);
579 z.len = d.len = v[2].len;
580 seal_initkey(&k, v[0].buf, v[0].len);
581
582 for (i = 0; i < v[2].len; i++) {
583 seal_initctx(&c, &k, n);
584 seal_encrypt(&c, 0, d.buf, i);
585 seal_encrypt(&c, z.buf, d.buf + i, d.len - i);
586 if (memcmp(d.buf, v[2].buf, d.len) != 0) {
587 ok = 0;
588 printf("*** seal failure\n");
589 printf("*** k = "); type_hex.dump(&v[0], stdout); putchar('\n');
590 printf("*** n = %08lx\n", (unsigned long)n);
591 printf("*** i = %i\n", i);
592 printf("*** expected = "); type_hex.dump(&v[2], stdout); putchar('\n');
593 printf("*** computed = "); type_hex.dump(&d, stdout); putchar('\n');
594 }
595 }
596
597 dstr_destroy(&d);
598 dstr_destroy(&z);
599
600 return (ok);
601 }
602
603 static test_chunk defs[] = {
604 { "seal", verify, { &type_hex, &type_uint32, &type_hex, 0 } },
605 { 0, 0, { 0 } }
606 };
607
608 int main(int argc, char *argv[])
609 {
610 test_run(argc, argv, defs, SRCDIR"/tests/seal");
611 return (0);
612 }
613
614 #endif
615
616 /*----- That's all, folks -------------------------------------------------*/