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