Rearrange the file tree.
[u/mdw/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_range, 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