3 * The SEAL pseudo-random function family
5 * (c) 2000 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 /*----- Header files ------------------------------------------------------*/
34 #include <mLib/bits.h>
43 /*----- Global variables --------------------------------------------------*/
45 const octet seal_keysz[] = { KSZ_ANY, SHA_HASHSZ };
47 /*----- Main code ---------------------------------------------------------*/
51 * Arguments: @uint32 *p@ = output table
52 * @size_t sz@ = size of the output table
53 * @const void *k@ = pointer to key material
54 * @unsigned i@ = integer offset
58 * Use: Initializes a SEAL key table.
61 static void sealgamma(uint32 *p, size_t sz, const void *k, unsigned i)
63 uint32 buf[80] = { 0 };
65 uint32 a, aa = LOAD32(kk);
66 uint32 b, bb = LOAD32(kk + 4);
67 uint32 c, cc = LOAD32(kk + 8);
68 uint32 d, dd = LOAD32(kk + 12);
69 uint32 e, ee = LOAD32(kk + 16);
77 /* --- While there's hashing to do, do hashing --- */
80 a = aa, b = bb, c = cc, d = dd, e = ee;
82 /* --- Initialize and expand the buffer --- */
86 for (j = 16; j < 80; j++) {
87 x = buf[j - 3] ^ buf[j - 8] ^ buf[j - 14] ^ buf[j - 16];
91 /* --- Definitions for round functions --- */
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)))
97 #define T(v, w, x, y, z, i, f, k) do { \
99 z = ROL32(v, 5) + f(w, x, y) + z + buf[i] + k; \
101 _x = v; v = z; z = y; y = x; x = w; w = _x; \
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)
109 /* --- The main compression function --- *
111 * Since this isn't doing bulk hashing, do it the easy way.
114 for (j = 0; j < 20; j++) FF(a, b, c, d, e, j);
115 for (j = 20; j < 40; j++) GG(a, b, c, d, e, j);
116 for (j = 40; j < 60; j++) HH(a, b, c, d, e, j);
117 for (j = 60; j < 80; j++) II(a, b, c, d, e, j);
119 /* --- Do the chaining at the end --- */
121 a += aa; b += bb; c += cc; d += dd; e += ee;
123 /* --- Write to the output buffer --- */
126 case 0: if (sz) { *p++ = a; sz--; }
127 case 1: if (sz) { *p++ = b; sz--; }
128 case 2: if (sz) { *p++ = c; sz--; }
129 case 3: if (sz) { *p++ = d; sz--; }
130 case 4: if (sz) { *p++ = e; sz--; }
136 /* --- @seal_initkey@ --- *
138 * Arguments: @seal_key *k@ = pointer to key block
139 * @const void *buf@ = pointer to key material
140 * @size_t sz@ = size of the key material
144 * Use: Initializes a SEAL key block. The key material may be any
145 * size, but if it's not 20 bytes long it's passed to SHA for
149 void seal_initkey(seal_key *k, const void *buf, size_t sz)
153 /* --- Hash the key if it's the wrong size --- */
155 if (sz == SHA_HASHSZ) memcpy(k->k, buf, sizeof(k->k));
156 else { sha_init(&h); sha_hash(&h, buf, sz); sha_done(&h, k->k); }
158 /* --- Expand the key to fit the various tables --- */
160 sealgamma(k->t, 512, k->k, 0);
161 sealgamma(k->s, 256, k->k, 0x1000);
162 sealgamma(k->r, SEAL_R, k->k, 0x2000);
165 /* --- @seal_reset@ --- *
167 * Arguments: @seal_ctx *c@ = pointer to a SEAL context
171 * Use: Resets the context so that more data can be extracted from
175 static void seal_reset(seal_ctx *c)
182 /* --- Initialize the new chaining variables --- */
184 if (c->l >= SEAL_R) {
185 sealgamma(c->rbuf, SEAL_R, k->k, c->ri);
192 B = ROR32(n, 8) ^ c->r[1];
193 C = ROR32(n, 16) ^ c->r[2];
194 D = ROR32(n, 24) ^ c->r[3];
198 /* --- Ensure that everything is sufficiently diffused --- */
200 p = A&0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
201 p = B&0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
202 p = C&0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
203 p = D&0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
204 p = A&0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
205 p = B&0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
206 p = C&0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
207 p = D&0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
209 /* --- Write out some context --- */
211 c->n1 = D; c->n2 = B; c->n3 = A; c->n4 = C;
213 /* --- Diffuse some more --- */
215 p = A&0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
216 p = B&0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
217 p = C&0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
218 p = D&0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
220 /* --- Write out the magic numbers --- */
222 c->a = A; c->b = B; c->c = C; c->d = D;
226 /* --- @seal_initctx@ --- *
228 * Arguments: @seal_ctx *c@ = pointer to a SEAL context
229 * @seal_key *k@ = pointer to a SEAL key
230 * @uint32 n@ = integer sequence number
234 * Use: Initializes a SEAL context which can be used for random
235 * number generation or whatever.
238 void seal_initctx(seal_ctx *c, seal_key *k, uint32 n)
244 c->ri = 0x2000 + SEAL_R;
249 /* --- @seal_encrypt@ --- *
251 * Arguments: @seal_ctx *c@ = pointer to a SEAL context
252 * @const void *src@ = pointer to source data
253 * @void *dest@ = pointer to destination data
254 * @size_t sz@ = size of the data
258 * Use: Encrypts a block of data using SEAL. If @src@ is zero,
259 * @dest@ is filled with SEAL output. If @dest@ is zero, the
260 * SEAL generator is just spun around for a bit. This shouldn't
261 * be necessary, because SEAL isn't RC4.
264 void seal_encrypt(seal_ctx *c, const void *src, void *dest, size_t sz)
267 const octet *s = src;
269 uint32 A = c->a, B = c->b, C = c->c, D = c->d;
270 uint32 n1 = c->n1, n2 = c->n2, n3 = c->n3, n4 = c->n4;
271 uint32 aa, bb, cc, dd;
275 /* --- Expect a big dollop of bytes --- */
277 if (sz > 16 - c->off) {
280 /* --- Drain the buffer first --- */
283 p = c->buf + c->off; sz -= 16 - c->off;
284 if (!d) /* nothing to do* */;
285 else if (!s) memcpy(d, p, 16 - c->off);
286 else for (i = c->off; i < 16; i++) *d++ = *s++ ^ *p++;
289 /* --- Main sequence --- */
293 /* --- Reset if we've run out of steam on this iteration --- */
297 A = c->a, B = c->b, C = c->c, D = c->d;
298 n1 = c->n1, n2 = c->n2, n3 = c->n3, n4 = c->n4;
302 /* --- Make some new numbers --- */
304 P = A&0x7fc; B += k->t[P >> 2]; A = ROR32(A, 9); B ^= A;
305 Q = B&0x7fc; C ^= k->t[Q >> 2]; B = ROR32(B, 9); C += B;
306 P = (P + C)&0x7fc; D += k->t[P >> 2]; C = ROR32(C, 9); D ^= C;
307 Q = (Q + D)&0x7fc; A ^= k->t[Q >> 2]; D = ROR32(D, 9); A += D;
308 P = (P + A)&0x7fc; B ^= k->t[P >> 2]; A = ROR32(A, 9);
309 Q = (Q + B)&0x7fc; C += k->t[Q >> 2]; B = ROR32(B, 9);
310 P = (P + C)&0x7fc; D ^= k->t[P >> 2]; C = ROR32(C, 9);
311 Q = (Q + D)&0x7fc; A += k->t[Q >> 2]; D = ROR32(D, 9);
313 /* --- Remember the output and set up the next round --- */
315 aa = B + k->s[j + 0]; bb = C ^ k->s[j + 1];
316 cc = D + k->s[j + 2]; dd = A ^ k->s[j + 3];
319 if (j&4) { A += n1; B += n2; C ^= n1; D ^= n2; }
320 else { A += n3; B += n4; C ^= n3; D ^= n4; }
322 /* --- Bail out here if we need to do buffering --- */
326 /* --- Write the next 16 bytes --- */
328 if (!d) /* nothing to do */;
331 aa ^= LOAD32_L(s + 0); bb ^= LOAD32_L(s + 4);
332 cc ^= LOAD32_L(s + 8); dd ^= LOAD32_L(s + 12);
335 STORE32_L(d + 0, aa); STORE32_L(d + 4, bb);
336 STORE32_L(d + 8, cc); STORE32_L(d + 12, dd);
342 /* --- Write the new buffer --- */
344 STORE32_L(c->buf + 0, aa);
345 STORE32_L(c->buf + 4, bb);
346 STORE32_L(c->buf + 8, cc);
347 STORE32_L(c->buf + 12, dd);
350 c->a = A; c->b = B; c->c = C; c->d = D;
354 /* --- Deal with the rest from the buffer --- */
357 p = c->buf + c->off; c->off += sz;
358 if (!d) /* nothing to do* */;
359 else if (!s) memcpy(d, p, sz);
360 else for (i = 0; i < sz; i++) *d++ = *s++ ^ *p++;
364 /*----- Generic cipher interface ------------------------------------------*/
366 typedef struct gctx {
372 static const gcipher_ops gops;
374 static gcipher *ginit(const void *k, size_t sz)
376 gctx *g = S_CREATE(gctx);
378 seal_initkey(&g->k, k, sz);
379 seal_initctx(&g->cc, &g->k, 0);
383 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)
384 { gctx *g = (gctx *)c; seal_encrypt(&g->cc, s, t, sz); }
386 static void gsetiv(gcipher *c, const void *iv)
389 const octet *ivp = iv;
390 seal_initctx(&g->cc, &g->k, LOAD32(ivp));
393 static void gdestroy(gcipher *c)
394 { gctx *g = (gctx *)c; BURN(*g); S_DESTROY(g); }
396 static const gcipher_ops gops = {
398 gencrypt, gencrypt, gdestroy, gsetiv, 0
401 const gccipher seal = {
402 "seal", seal_keysz, 4,
406 /*----- Generic random number generator interface -------------------------*/
408 typedef struct grctx {
414 static void grdestroy(grand *r)
415 { grctx *g = (grctx *)r; BURN(*g); S_DESTROY(g); }
417 static int grmisc(grand *r, unsigned op, ...)
419 grctx *g = (grctx *)r;
426 switch (va_arg(ap, unsigned)) {
429 case GRAND_SEEDUINT32:
430 case GRAND_SEEDBLOCK:
440 seal_initctx(&g->cc, &g->k, va_arg(ap, int));
442 case GRAND_SEEDUINT32:
443 seal_initctx(&g->cc, &g->k, va_arg(ap, uint32));
445 case GRAND_SEEDBLOCK: {
446 const void *p = va_arg(ap, const void *);
447 size_t sz = va_arg(ap, size_t);
452 octet buf[4] = { 0 };
456 seal_initctx(&g->cc, &g->k, n);
458 case GRAND_SEEDRAND: {
459 grand *rr = va_arg(ap, grand *);
460 seal_initctx(&g->cc, &g->k, rr->ops->word(rr));
471 static octet grbyte(grand *r)
473 grctx *g = (grctx *)r;
475 seal_encrypt(&g->cc, 0, &o, 1);
479 static uint32 grword(grand *r)
481 grctx *g = (grctx *)r;
483 seal_encrypt(&g->cc, 0, b, 4);
487 static void grfill(grand *r, void *p, size_t sz)
488 { grctx *g = (grctx *)r; seal_encrypt(&g->cc, 0, p, sz); }
490 static const grand_ops grops = {
494 grword, grbyte, grword, grand_defaultrange, grfill
497 /* --- @seal_rand@ --- *
499 * Arguments: @const void *k@ = pointer to key material
500 * @size_t sz@ = size of key material
501 * @uint32 n@ = sequence number
503 * Returns: Pointer to generic random number generator interface.
505 * Use: Creates a random number interface wrapper around a SEAL
506 * pseudorandom function.
509 grand *seal_rand(const void *k, size_t sz, uint32 n)
511 grctx *g = S_CREATE(grctx);
513 seal_initkey(&g->k, k, sz);
514 seal_initctx(&g->cc, &g->k, n);
518 /*----- Test rig ----------------------------------------------------------*/
524 #include <mLib/testrig.h>
526 static int verify(dstr *v)
530 uint32 n = *(uint32 *)v[1].buf;
536 DENSURE(&d, v[2].len);
537 DENSURE(&z, v[2].len);
538 memset(z.buf, 0, v[2].len);
539 z.len = d.len = v[2].len;
540 seal_initkey(&k, v[0].buf, v[0].len);
542 for (i = 0; i < v[2].len; i++) {
543 seal_initctx(&c, &k, n);
544 seal_encrypt(&c, 0, d.buf, i);
545 seal_encrypt(&c, z.buf, d.buf + i, d.len - i);
546 if (memcmp(d.buf, v[2].buf, d.len) != 0) {
548 printf("*** seal failure\n");
549 printf("*** k = "); type_hex.dump(&v[0], stdout); putchar('\n');
550 printf("*** n = %08lx\n", (unsigned long)n);
551 printf("*** i = %i\n", i);
552 printf("*** expected = "); type_hex.dump(&v[2], stdout); putchar('\n');
553 printf("*** computed = "); type_hex.dump(&d, stdout); putchar('\n');
563 static test_chunk defs[] = {
564 { "seal", verify, { &type_hex, &type_uint32, &type_hex, 0 } },
568 int main(int argc, char *argv[])
570 test_run(argc, argv, defs, SRCDIR"/t/seal");
576 /*----- That's all, folks -------------------------------------------------*/