3 * $Id: seal.c,v 1.1 2000/06/17 12:08:34 mdw Exp $
5 * The SEAL pseudo-random function family
7 * (c) 2000 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
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.
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.
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,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.1 2000/06/17 12:08:34 mdw
38 /*----- Header files ------------------------------------------------------*/
44 #include <mLib/bits.h>
53 /*----- Global variables --------------------------------------------------*/
55 const octet seal_keysz[] = { KSZ_ANY, SHA_HASHSZ };
57 /*----- Main code ---------------------------------------------------------*/
61 * Arguments: @uint32 *p@ = output table
62 * @size_t sz@ = size of the output table
63 * @const void *k@ = pointer to key material
64 * @unsigned i@ = integer offset
68 * Use: Initializes a SEAL key table.
71 static void gamma(uint32 *p, size_t sz, const void *k, unsigned i)
73 uint32 buf[80] = { 0 };
75 uint32 aa = LOAD32(kk);
76 uint32 bb = LOAD32(kk + 4);
77 uint32 cc = LOAD32(kk + 8);
78 uint32 dd = LOAD32(kk + 12);
79 uint32 ee = LOAD32(kk + 16);
81 unsigned skip = i % 5;
84 /* --- While there's hashing to do, do hashing --- */
87 uint32 a = aa, b = bb, c = cc, d = dd, e = ee;
90 /* --- Initialize and expand the buffer --- */
94 for (j = 16; j < 80; j++) {
95 uint32 x = buf[j - 3] ^ buf[j - 8] ^ buf[j - 14] ^ buf[j - 16];
99 /* --- Definitions for round functions --- */
101 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
102 #define G(x, y, z) ((x) ^ (y) ^ (z))
103 #define H(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
105 #define T(v, w, x, y, z, i, f, k) do { \
107 z = ROL32(v, 5) + f(w, x, y) + z + buf[i] + k; \
109 _x = v; v = z; z = y; y = x; x = w; w = _x; \
112 #define FF(v, w, x, y, z, i) T(v, w, x, y, z, i, F, 0x5a827999)
113 #define GG(v, w, x, y, z, i) T(v, w, x, y, z, i, G, 0x6ed9eba1)
114 #define HH(v, w, x, y, z, i) T(v, w, x, y, z, i, H, 0x8f1bbcdc)
115 #define II(v, w, x, y, z, i) T(v, w, x, y, z, i, G, 0xca62c1d6)
117 /* --- The main compression function --- *
119 * Since this isn't doing bulk hashing, do it the easy way.
122 for (j = 0; j < 20; j++)
123 FF(a, b, c, d, e, j);
124 for (j = 20; j < 40; j++)
125 GG(a, b, c, d, e, j);
126 for (j = 40; j < 60; j++)
127 HH(a, b, c, d, e, j);
128 for (j = 60; j < 80; j++)
129 II(a, b, c, d, e, j);
131 /* --- Do the chaining at the end --- */
133 a += aa; b += bb; c += cc; d += dd; e += ee;
135 /* --- Write to the output buffer --- */
139 if (sz) { *p++ = a; sz--; }
141 if (sz) { *p++ = b; sz--; }
143 if (sz) { *p++ = c; sz--; }
145 if (sz) { *p++ = d; sz--; }
147 if (sz) { *p++ = e; sz--; }
153 /* --- @seal_initkey@ --- *
155 * Arguments: @seal_key *k@ = pointer to key block
156 * @const void *buf@ = pointer to key material
157 * @size_t sz@ = size of the key material
161 * Use: Initializes a SEAL key block. The key material may be any
162 * size, but if it's not 20 bytes long it's passed to SHA for
166 void seal_initkey(seal_key *k, const void *buf, size_t sz)
168 /* --- Hash the key if it's the wrong size --- */
170 if (sz == SHA_HASHSZ)
171 memcpy(k->k, buf, sizeof(k->k));
175 sha_hash(&c, buf, sz);
179 /* --- Expand the key to fit the various tables --- */
181 gamma(k->t, 512, k->k, 0);
182 gamma(k->s, 256, k->k, 0x1000);
183 gamma(k->r, SEAL_R, k->k, 0x2000);
186 /* --- @seal_reset@ --- *
188 * Arguments: @seal_ctx *c@ = pointer to a SEAL context
192 * Use: Resets the context so that more data can be extracted from
196 static void seal_reset(seal_ctx *c)
203 /* --- Initialize the new chaining variables --- */
205 if (c->l >= SEAL_R) {
206 gamma(c->rbuf, SEAL_R, k->k, c->ri);
213 B = ROR32(n, 8) ^ c->r[1];
214 C = ROR32(n, 16) ^ c->r[2];
215 D = ROR32(n, 24) ^ c->r[3];
219 /* --- Ensure that everything is sufficiently diffused --- */
221 p = A & 0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
222 p = B & 0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
223 p = C & 0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
224 p = D & 0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
225 p = A & 0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
226 p = B & 0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
227 p = C & 0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
228 p = D & 0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
230 /* --- Write out some context --- */
232 c->n1 = D; c->n2 = B; c->n3 = A; c->n4 = C;
234 /* --- Diffuse some more --- */
236 p = A & 0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
237 p = B & 0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
238 p = C & 0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
239 p = D & 0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
241 /* --- Write out the magic numbers --- */
243 c->a = A; c->b = B; c->c = C; c->d = D;
247 /* --- @seal_initctx@ --- *
249 * Arguments: @seal_ctx *c@ = pointer to a SEAL context
250 * @seal_key *k@ = pointer to a SEAL key
251 * @uint32 n@ = integer sequence number
255 * Use: Initializes a SEAL context which can be used for random
256 * number generation or whatever.
259 void seal_initctx(seal_ctx *c, seal_key *k, uint32 n)
265 c->ri = 0x2000 + SEAL_R;
270 /* --- @seal_encrypt@ --- *
272 * Arguments: @seal_ctx *c@ = pointer to a SEAL context
273 * @const void *src@ = pointer to source data
274 * @void *dest@ = pointer to destination data
275 * @size_t sz@ = size of the data
279 * Use: Encrypts a block of data using SEAL. If @src@ is zero,
280 * @dest@ is filled with SEAL output. If @dest@ is zero, the
281 * SEAL generator is just spun around for a bit. This shouldn't
282 * be necessary, because SEAL isn't RC4.
285 void seal_encrypt(seal_ctx *c, const void *src, void *dest, size_t sz)
287 const octet *s = src;
290 /* --- Expect a big dollop of bytes --- */
294 uint32 A = c->a, B = c->b, C = c->c, D = c->d;
295 uint32 n1 = c->n1, n2 = c->n2, n3 = c->n3, n4 = c->n4;
296 uint32 aa, bb, cc, dd;
299 /* --- Empty the queue first --- */
304 octet *p = c->q + sizeof(c->q) - c->qsz;
305 for (i = 0; i < c->qsz; i++)
306 *d++ = (s ? *s++ ^ *p++ : *p++);
311 /* --- Main sequence --- */
316 /* --- Reset if we've run out of steam on this iteration --- */
320 A = c->a, B = c->b, C = c->c, D = c->d;
321 n1 = c->n1, n2 = c->n2, n3 = c->n3, n4 = c->n4;
325 /* --- Make some new numbers --- */
327 P = A & 0x7fc; B += k->t[P >> 2]; A = ROR32(A, 9); B ^= A;
328 Q = B & 0x7fc; C ^= k->t[Q >> 2]; B = ROR32(B, 9); C += B;
329 P = (P + C) & 0x7fc; D += k->t[P >> 2]; C = ROR32(C, 9); D ^= C;
330 Q = (Q + D) & 0x7fc; A ^= k->t[Q >> 2]; D = ROR32(D, 9); A += D;
331 P = (P + A) & 0x7fc; B ^= k->t[P >> 2]; A = ROR32(A, 9);
332 Q = (Q + B) & 0x7fc; C += k->t[Q >> 2]; B = ROR32(B, 9);
333 P = (P + C) & 0x7fc; D ^= k->t[P >> 2]; C = ROR32(C, 9);
334 Q = (Q + D) & 0x7fc; A += k->t[Q >> 2]; D = ROR32(D, 9);
336 /* --- Remember the output and set up the next round --- */
338 aa = B + k->s[j + 0];
339 bb = C ^ k->s[j + 1];
340 cc = D + k->s[j + 2];
341 dd = A ^ k->s[j + 3];
345 A += n1, B += n2, C ^= n1, D ^= n2;
347 A += n3, B += n4, C ^= n3, D ^= n4;
349 /* --- Bail out here if we need to do buffering --- */
354 /* --- Write the next 16 bytes --- */
358 aa ^= LOAD32_L(s + 0);
359 bb ^= LOAD32_L(s + 4);
360 cc ^= LOAD32_L(s + 8);
361 dd ^= LOAD32_L(s + 12);
364 STORE32_L(d + 0, aa);
365 STORE32_L(d + 4, bb);
366 STORE32_L(d + 8, cc);
367 STORE32_L(d + 12, dd);
373 /* --- Write the new queue --- */
375 STORE32_L(c->q + 0, aa);
376 STORE32_L(c->q + 4, bb);
377 STORE32_L(c->q + 8, cc);
378 STORE32_L(c->q + 12, dd);
381 c->a = A; c->b = B; c->c = C; c->d = D;
385 /* --- Deal with the rest from the queue --- */
389 octet *p = c->q + sizeof(c->q) - c->qsz;
391 for (i = 0; i < sz; i++)
392 *d++ = (s ? *s++ ^ *p++ : *p++);
398 /*----- Generic cipher interface ------------------------------------------*/
400 typedef struct gctx {
406 static const gcipher_ops gops;
408 static gcipher *ginit(const void *k, size_t sz)
410 gctx *g = S_CREATE(gctx);
412 seal_initkey(&g->k, k, sz);
413 seal_initctx(&g->cc, &g->k, 0);
417 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)
420 seal_encrypt(&g->cc, s, t, sz);
423 static void gsetiv(gcipher *c, const void *iv)
426 uint32 n = *(const uint32 *)iv;
427 seal_initctx(&g->cc, &g->k, n);
430 static void gdestroy(gcipher *c)
437 static const gcipher_ops gops = {
439 gencrypt, gencrypt, gdestroy, gsetiv, 0
442 const gccipher seal = {
443 "seal", seal_keysz, 0,
447 /*----- Generic random number generator interface -------------------------*/
449 typedef struct grctx {
455 static void grdestroy(grand *r)
457 grctx *g = (grctx *)r;
462 static int grmisc(grand *r, unsigned op, ...)
464 grctx *g = (grctx *)r;
471 switch (va_arg(ap, unsigned)) {
474 case GRAND_SEEDUINT32:
475 case GRAND_SEEDBLOCK:
485 seal_initctx(&g->cc, &g->k, va_arg(ap, int));
487 case GRAND_SEEDUINT32:
488 seal_initctx(&g->cc, &g->k, va_arg(ap, uint32));
490 case GRAND_SEEDBLOCK: {
491 const void *p = va_arg(ap, const void *);
492 size_t sz = va_arg(ap, size_t);
497 octet buf[4] = { 0 };
501 seal_initctx(&g->cc, &g->k, n);
503 case GRAND_SEEDRAND: {
504 grand *rr = va_arg(ap, grand *);
505 seal_initctx(&g->cc, &g->k, rr->ops->word(rr));
516 static octet grbyte(grand *r)
518 grctx *g = (grctx *)r;
520 seal_encrypt(&g->cc, 0, &o, 1);
524 static uint32 grword(grand *r)
526 grctx *g = (grctx *)r;
528 seal_encrypt(&g->cc, 0, b, 4);
532 static void grfill(grand *r, void *p, size_t sz)
534 grctx *g = (grctx *)r;
535 seal_encrypt(&g->cc, 0, p, sz);
538 static const grand_ops grops = {
542 grword, grbyte, grword, grand_range, grfill
545 /* --- @seal_rand@ --- *
547 * Arguments: @const void *k@ = pointer to key material
548 * @size_t sz@ = size of key material
549 * @uint32 n@ = sequence number
551 * Returns: Pointer to generic random number generator interface.
553 * Use: Creates a random number interface wrapper around a SEAL
554 * pseudorandom function.
557 grand *seal_rand(const void *k, size_t sz, uint32 n)
559 grctx *g = S_CREATE(grctx);
561 seal_initkey(&g->k, k, sz);
562 seal_initctx(&g->cc, &g->k, n);
566 /*----- Test rig ----------------------------------------------------------*/
572 #include <mLib/testrig.h>
574 static int verify(dstr *v)
578 uint32 n = *(uint32 *)v[1].buf;
584 DENSURE(&d, v[2].len);
585 DENSURE(&z, v[2].len);
586 memset(z.buf, 0, v[2].len);
587 z.len = d.len = v[2].len;
588 seal_initkey(&k, v[0].buf, v[0].len);
590 for (i = 0; i < v[2].len; i++) {
591 seal_initctx(&c, &k, n);
592 seal_encrypt(&c, 0, d.buf, i);
593 seal_encrypt(&c, z.buf, d.buf + i, d.len - i);
594 if (memcmp(d.buf, v[2].buf, d.len) != 0) {
596 printf("*** seal failure\n");
597 printf("*** k = "); type_hex.dump(&v[0], stdout); putchar('\n');
598 printf("*** n = %08lx\n", (unsigned long)n);
599 printf("*** i = %i\n", i);
600 printf("*** expected = "); type_hex.dump(&v[2], stdout); putchar('\n');
601 printf("*** computed = "); type_hex.dump(&d, stdout); putchar('\n');
611 static test_chunk defs[] = {
612 { "seal", verify, { &type_hex, &type_uint32, &type_hex, 0 } },
616 int main(int argc, char *argv[])
618 test_run(argc, argv, defs, SRCDIR"/tests/seal");
624 /*----- That's all, folks -------------------------------------------------*/