chiark / gitweb /
Shore up the `grand' protocol.
[catacomb] / symm / mgf-def.h
1 /* -*-c-*-
2  *
3  * Definitions for the MGF-1 mask generator
4  *
5  * (c) 2000 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Catacomb.
11  *
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.
16  *
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.
21  *
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,
25  * MA 02111-1307, USA.
26  */
27
28 #ifndef CATACOMB_MGF_DEF_H
29 #define CATACOMB_MGF_DEF_H
30
31 #ifdef __cplusplus
32   extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include <mLib/bits.h>
42 #include <mLib/sub.h>
43
44 #ifndef CATACOMB_ARENA_H
45 #  include "arena.h"
46 #endif
47
48 #ifndef CATACOMB_GCIPHER_H
49 #  include "gcipher.h"
50 #endif
51
52 #ifndef CATACOMB_GRAND_H
53 #  include "grand.h"
54 #endif
55
56 #ifndef CATACOMB_PARANOIA_H
57 #  include "paranoia.h"
58 #endif
59
60 /*----- Macros ------------------------------------------------------------*/
61
62 #define MGF_DEF(PRE, pre)                                               \
63                                                                         \
64 /* --- Useful constants --- */                                          \
65                                                                         \
66 const octet pre##_mgfkeysz[] = { KSZ_ANY, PRE##_HASHSZ };               \
67                                                                         \
68 /* --- @pre_mgfkeybegin@, @pre_mgfkeyadd@ --- *                         \
69  *                                                                      \
70  * Arguments:   @pre_mgfctx *k@ = pointer to context to initialize      \
71  *              @const void *p@ = pointer to data to contribute         \
72  *                                                                      \
73  * Returns:     ---                                                     \
74  *                                                                      \
75  * Use:         A multi-step keying procedure for initializing an MGF   \
76  *              context.  The data is contributed to a hashing context  \
77  *              which is then used for mask generation.  If you only    \
78  *              have a fixed buffer, you can save a lot of effort by    \
79  *              simply calling @pre_mgfinit@.                           \
80  */                                                                     \
81                                                                         \
82 void pre##_mgfkeybegin(pre##_mgfctx *k)                                 \
83 {                                                                       \
84   k->c = 0;                                                             \
85   k->bsz = 0;                                                           \
86   pre##_init(&k->k);                                                    \
87 }                                                                       \
88                                                                         \
89 void pre##_mgfkeyadd(pre##_mgfctx *k, const void *p, size_t sz)         \
90 {                                                                       \
91   pre##_hash(&k->k, p, sz);                                             \
92 }                                                                       \
93                                                                         \
94 /* ---- @pre_mgfinit@ --- *                                             \
95  *                                                                      \
96  * Arguments:   @pre_mgfctx *k@ = pointer to context to initialize      \
97  *              @const void *p@ = pointer to data to contribute         \
98  *              @size_t sz@ = size of data to contribute                \
99  *                                                                      \
100  * Returns:     ---                                                     \
101  *                                                                      \
102  * Use:         A simpler interface to initialization if all of your    \
103  *              keying material is in one place.                        \
104  */                                                                     \
105                                                                         \
106 void pre##_mgfinit(pre##_mgfctx *k, const void *p, size_t sz)           \
107 {                                                                       \
108   k->c = 0;                                                             \
109   k->bsz = 0;                                                           \
110   pre##_init(&k->k);                                                    \
111   pre##_hash(&k->k, p, sz);                                             \
112 }                                                                       \
113                                                                         \
114 /* --- @pre_mgfencrypt@ --- *                                           \
115  *                                                                      \
116  * Arguments:   @pre_mgfctx *k@ = pointer to masking context            \
117  *              @const void *s@ = pointer to source buffer              \
118  *              @void *d@ = pointer to destination buffer               \
119  *              @size_t sz@ = size of buffers                           \
120  *                                                                      \
121  * Returns:     ---                                                     \
122  *                                                                      \
123  * Use:         Outputs pseudorandom data, or masks an input buffer.    \
124  *                                                                      \
125  *              If @s@ is nonzero, the source material is exclusive-    \
126  *              orred with the generated mask.  If @d@ is zero, the     \
127  *              generator is simply spun around for a while, which      \
128  *              isn't very useful.                                      \
129  */                                                                     \
130                                                                         \
131 void pre##_mgfencrypt(pre##_mgfctx *k, const void *s,                   \
132                       void *d, size_t sz)                               \
133 {                                                                       \
134   const octet *ss = s;                                                  \
135   octet *dd = d;                                                        \
136                                                                         \
137   /* --- Empty the buffer if there's anything there --- */              \
138                                                                         \
139   if (k->bsz) {                                                         \
140     const octet *p = k->buf + PRE##_HASHSZ - k->bsz;                    \
141     size_t n = sz > k->bsz ? k->bsz : sz;                               \
142     sz -= n;                                                            \
143     k->bsz -= n;                                                        \
144     if (dd) {                                                           \
145       if (!ss) {                                                        \
146         memcpy(dd, p, n);                                               \
147         dd += n;                                                        \
148       } else {                                                          \
149         while (n) {                                                     \
150           *dd++ = *ss++ ^ *p++;                                         \
151           n--;                                                          \
152         }                                                               \
153       }                                                                 \
154     }                                                                   \
155   }                                                                     \
156                                                                         \
157   /* --- While necessary, generate some more mask --- */                \
158                                                                         \
159   while (sz) {                                                          \
160     pre##_ctx c = k->k;         /* Not quick! */                        \
161     size_t n;                                                           \
162                                                                         \
163     STORE32(k->buf, k->c);                                              \
164     k->c++;                                                             \
165     pre##_hash(&c, k->buf, 4);                                          \
166     pre##_done(&c, k->buf);                                             \
167     n = sz > PRE##_HASHSZ ? PRE##_HASHSZ : sz;                          \
168     k->bsz = PRE##_HASHSZ - n;                                          \
169     sz -= n;                                                            \
170     if (dd) {                                                           \
171       const octet *p = k->buf;                                          \
172       if (!ss) {                                                        \
173         memcpy(dd, p, n);                                               \
174         dd += n;                                                        \
175       } else {                                                          \
176         while (n) {                                                     \
177           *dd++ = *ss++ ^ *p++;                                         \
178           n--;                                                          \
179         }                                                               \
180       }                                                                 \
181     }                                                                   \
182   }                                                                     \
183 }                                                                       \
184                                                                         \
185 /* --- @pre_mgfsetindex@ --- *                                          \
186  *                                                                      \
187  * Arguments:   @pre_mgfctx *k@ = pointer to masking context            \
188  *              @uint32 *c@ = new index to set                          \
189  *                                                                      \
190  * Returns:     ---                                                     \
191  *                                                                      \
192  * Use:         Sets a new index.  This may be used to step around the  \
193  *              output stream in a rather crude way.                    \
194  */                                                                     \
195                                                                         \
196 void pre##_mgfsetindex(pre##_mgfctx *k, uint32 c)                       \
197 {                                                                       \
198   k->c = c;                                                             \
199   k->bsz = 0;                                                           \
200 }                                                                       \
201                                                                         \
202 /* --- Generic cipher interface --- */                                  \
203                                                                         \
204 static const gcipher_ops gops;                                          \
205                                                                         \
206 typedef struct gctx {                                                   \
207   gcipher c;                                                            \
208   pre##_mgfctx k;                                                       \
209 } gctx;                                                                 \
210                                                                         \
211 static gcipher *ginit(const void *k, size_t sz)                         \
212 {                                                                       \
213   gctx *g = S_CREATE(gctx);                                             \
214   g->c.ops = &gops;                                                     \
215   pre##_mgfinit(&g->k, k, sz);                                          \
216   return (&g->c);                                                       \
217 }                                                                       \
218                                                                         \
219 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)     \
220 {                                                                       \
221   gctx *g = (gctx *)c;                                                  \
222   pre##_mgfencrypt(&g->k, s, t, sz);                                    \
223 }                                                                       \
224                                                                         \
225 static void gdestroy(gcipher *c)                                        \
226 {                                                                       \
227   gctx *g = (gctx *)c;                                                  \
228   BURN(*g);                                                             \
229   S_DESTROY(g);                                                         \
230 }                                                                       \
231                                                                         \
232 static const gcipher_ops gops = {                                       \
233   &pre##_mgf,                                                           \
234   gencrypt, gencrypt, gdestroy, 0, 0                                    \
235 };                                                                      \
236                                                                         \
237 const gccipher pre##_mgf = {                                            \
238   #pre "-mgf", pre##_mgfkeysz, 0,                                       \
239   ginit                                                                 \
240 };                                                                      \
241                                                                         \
242 /* --- Generic random number generator interface --- */                 \
243                                                                         \
244 typedef struct grctx {                                                  \
245   grand r;                                                              \
246   pre##_mgfctx k;                                                       \
247 } grctx;                                                                \
248                                                                         \
249 static void grdestroy(grand *r)                                         \
250 {                                                                       \
251   grctx *g = (grctx *)r;                                                \
252   BURN(*g);                                                             \
253   S_DESTROY(g);                                                         \
254 }                                                                       \
255                                                                         \
256 static int grmisc(grand *r, unsigned op, ...)                           \
257 {                                                                       \
258   grctx *g = (grctx *)r;                                                \
259   va_list ap;                                                           \
260   int rc = 0;                                                           \
261   va_start(ap, op);                                                     \
262                                                                         \
263   switch (op) {                                                         \
264     case GRAND_CHECK:                                                   \
265       switch (va_arg(ap, unsigned)) {                                   \
266         case GRAND_CHECK:                                               \
267         case GRAND_SEEDINT:                                             \
268         case GRAND_SEEDUINT32:                                          \
269         case GRAND_SEEDBLOCK:                                           \
270         case GRAND_SEEDRAND:                                            \
271           rc = 1;                                                       \
272           break;                                                        \
273         default:                                                        \
274           rc = 0;                                                       \
275           break;                                                        \
276       }                                                                 \
277       break;                                                            \
278     case GRAND_SEEDINT:                                                 \
279       pre##_mgfsetindex(&g->k, va_arg(ap, unsigned));                   \
280       break;                                                            \
281     case GRAND_SEEDUINT32:                                              \
282       pre##_mgfsetindex(&g->k, va_arg(ap, uint32));                     \
283       break;                                                            \
284     case GRAND_SEEDBLOCK: {                                             \
285       const void *p = va_arg(ap, const void *);                         \
286       size_t sz = va_arg(ap, size_t);                                   \
287       pre##_hash(&g->k.k, p, sz);                                       \
288     } break;                                                            \
289     case GRAND_SEEDRAND: {                                              \
290       octet buf[PRE##_BUFSZ];                                           \
291       grand *rr = va_arg(ap, grand *);                                  \
292       rr->ops->fill(rr, buf, sizeof(buf));                              \
293       pre##_hash(&g->k.k, buf, sizeof(buf));                            \
294     } break;                                                            \
295     default:                                                            \
296       GRAND_BADOP;                                                      \
297       break;                                                            \
298   }                                                                     \
299                                                                         \
300   va_end(ap);                                                           \
301   return (rc);                                                          \
302 }                                                                       \
303                                                                         \
304 static octet grbyte(grand *r)                                           \
305 {                                                                       \
306   grctx *g = (grctx *)r;                                                \
307   octet o;                                                              \
308   pre##_mgfencrypt(&g->k, 0, &o, 1);                                    \
309   return (o);                                                           \
310 }                                                                       \
311                                                                         \
312 static uint32 grword(grand *r)                                          \
313 {                                                                       \
314   grctx *g = (grctx *)r;                                                \
315   octet b[4];                                                           \
316   pre##_mgfencrypt(&g->k, 0, b, sizeof(b));                             \
317   return (LOAD32(b));                                                   \
318 }                                                                       \
319                                                                         \
320 static void grfill(grand *r, void *p, size_t sz)                        \
321 {                                                                       \
322   grctx *g = (grctx *)r;                                                \
323   pre##_mgfencrypt(&g->k, 0, p, sz);                                    \
324 }                                                                       \
325                                                                         \
326 static const grand_ops grops = {                                        \
327   #pre "-mgf",                                                          \
328   GRAND_CRYPTO, 0,                                                      \
329   grmisc, grdestroy,                                                    \
330   grword, grbyte, grword, grand_defaultrange, grfill                    \
331 };                                                                      \
332                                                                         \
333 /* --- @pre_mgfrand@ --- *                                              \
334  *                                                                      \
335  * Arguments:   @const void *k@ = pointer to key material               \
336  *              @size_t sz@ = size of key material                      \
337  *                                                                      \
338  * Returns:     Pointer to a generic random number generator instance.  \
339  *                                                                      \
340  * Use:         Creates a random number interface wrapper around an     \
341  *              MGF-1-mode hash function.                               \
342  */                                                                     \
343                                                                         \
344 extern grand *pre##_mgfrand(const void *k, size_t sz)                   \
345 {                                                                       \
346   grctx *g = S_CREATE(grctx);                                           \
347   g->r.ops = &grops;                                                    \
348   pre##_mgfinit(&g->k, k, sz);                                          \
349   return (&g->r);                                                       \
350 }                                                                       \
351                                                                         \
352 MGF_TEST(PRE, pre)
353
354 /*----- Test rig ----------------------------------------------------------*/
355
356 #ifdef TEST_RIG
357
358 #include <stdio.h>
359
360 #include "daftstory.h"
361
362 /* --- @MGF_TEST@ --- *
363  *
364  * Arguments:   @PRE@, @pre@ = prefixes for block cipher definitions
365  *
366  * Use:         Standard test rig for MGF functions.
367  */
368
369 #define MGF_TEST(PRE, pre)                                              \
370                                                                         \
371 /* --- Initial plaintext for the test --- */                            \
372                                                                         \
373 static const octet text[] = TEXT;                                       \
374                                                                         \
375 /* --- Key and IV to use --- */                                         \
376                                                                         \
377 static const octet key[] = KEY;                                         \
378                                                                         \
379 /* --- Buffers for encryption and decryption output --- */              \
380                                                                         \
381 static octet ct[sizeof(text)];                                          \
382 static octet pt[sizeof(text)];                                          \
383                                                                         \
384 static void hexdump(const octet *p, size_t sz)                          \
385 {                                                                       \
386   const octet *q = p + sz;                                              \
387   for (sz = 0; p < q; p++, sz++) {                                      \
388     printf("%02x", *p);                                                 \
389     if ((sz + 1) % PRE##_HASHSZ == 0)                                   \
390       putchar(':');                                                     \
391   }                                                                     \
392 }                                                                       \
393                                                                         \
394 int main(void)                                                          \
395 {                                                                       \
396   size_t sz = 0, rest;                                                  \
397   pre##_mgfctx ctx;                                                     \
398   int status = 0;                                                       \
399   int done = 0;                                                         \
400                                                                         \
401   size_t keysz = strlen((const char *)key);                             \
402                                                                         \
403   fputs(#pre "-mgf: ", stdout);                                         \
404                                                                         \
405   pre##_mgfinit(&ctx, key, keysz);                                      \
406                                                                         \
407   while (sz <= sizeof(text)) {                                          \
408     rest = sizeof(text) - sz;                                           \
409     memcpy(ct, text, sizeof(text));                                     \
410     pre##_mgfsetindex(&ctx, 0);                                         \
411     pre##_mgfencrypt(&ctx, ct, ct, sz);                                 \
412     pre##_mgfencrypt(&ctx, ct + sz, ct + sz, rest);                     \
413     memcpy(pt, ct, sizeof(text));                                       \
414     pre##_mgfsetindex(&ctx, 0);                                         \
415     pre##_mgfencrypt(&ctx, pt, pt, rest);                               \
416     pre##_mgfencrypt(&ctx, pt + rest, pt + rest, sz);                   \
417     if (memcmp(pt, text, sizeof(text)) == 0) {                          \
418       done++;                                                           \
419       if (sizeof(text) < 40 || done % 8 == 0)                           \
420         fputc('.', stdout);                                             \
421       if (done % 480 == 0)                                              \
422         fputs("\n\t", stdout);                                          \
423       fflush(stdout);                                                   \
424     } else {                                                            \
425       printf("\nError (sz = %lu)\n", (unsigned long)sz);                \
426       status = 1;                                                       \
427       printf("\tplaintext      = "); hexdump(text, sz);                 \
428         printf(", "); hexdump(text + sz, rest);                         \
429         fputc('\n', stdout);                                            \
430       printf("\tciphertext     = "); hexdump(ct, sz);                   \
431         printf(", "); hexdump(ct + sz, rest);                           \
432         fputc('\n', stdout);                                            \
433       printf("\trecovered text = "); hexdump(pt, sz);                   \
434         printf(", "); hexdump(pt + sz, rest);                           \
435         fputc('\n', stdout);                                            \
436       fputc('\n', stdout);                                              \
437     }                                                                   \
438     if (sz < 63)                                                        \
439       sz++;                                                             \
440     else                                                                \
441       sz += 9;                                                          \
442   }                                                                     \
443                                                                         \
444   fputs(status ? " failed\n" : " ok\n", stdout);                        \
445   return (status);                                                      \
446 }
447
448 #else
449 #  define MGF_TEST(PRE, pre)
450 #endif
451
452 /*----- That's all, folks -------------------------------------------------*/
453
454 #ifdef __cplusplus
455   }
456 #endif
457
458 #endif