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 -------------------------------------------------*/