.gitignore: Ignore `ylwrap'.
[u/mdw/catacomb] / mgf-def.h
CommitLineData
fea9a197 1/* -*-c-*-
2 *
b817bfc6 3 * $Id: mgf-def.h,v 1.2 2004/04/08 01:36:15 mdw Exp $
fea9a197 4 *
5 * Definitions for the MGF-1 mask generator
6 *
7 * (c) 2000 Straylight/Edgeware
8 */
9
45c0fd36 10/*----- Licensing notice --------------------------------------------------*
fea9a197 11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
45c0fd36 18 *
fea9a197 19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
45c0fd36 23 *
fea9a197 24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
fea9a197 30#ifndef CATACOMB_MGF_DEF_H
31#define CATACOMB_MGF_DEF_H
32
33#ifdef __cplusplus
34 extern "C" {
35#endif
36
37/*----- Header files ------------------------------------------------------*/
38
39#include <stdarg.h>
40#include <stdlib.h>
41#include <string.h>
42
43#include <mLib/bits.h>
44#include <mLib/sub.h>
45
46#ifndef CATACOMB_ARENA_H
47# include "arena.h"
48#endif
49
50#ifndef CATACOMB_GCIPHER_H
51# include "gcipher.h"
52#endif
53
54#ifndef CATACOMB_GRAND_H
55# include "grand.h"
56#endif
57
58#ifndef CATACOMB_PARANOIA_H
59# include "paranoia.h"
60#endif
61
62/*----- Macros ------------------------------------------------------------*/
63
64#define MGF_DEF(PRE, pre) \
65 \
66/* --- Useful constants --- */ \
67 \
68const 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 \
84void pre##_mgfkeybegin(pre##_mgfctx *k) \
85{ \
86 k->c = 0; \
87 k->bsz = 0; \
88 pre##_init(&k->k); \
89} \
45c0fd36 90 \
fea9a197 91void 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 \
108void 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 \
133void 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) { \
45c0fd36
MW
148 memcpy(dd, p, n); \
149 dd += n; \
fea9a197 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) { \
45c0fd36
MW
175 memcpy(dd, p, n); \
176 dd += n; \
fea9a197 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 \
198void pre##_mgfsetindex(pre##_mgfctx *k, uint32 c) \
199{ \
200 k->c = c; \
201 k->bsz = 0; \
202} \
203 \
204/* --- Generic cipher interface --- */ \
205 \
206static const gcipher_ops gops; \
207 \
208typedef struct gctx { \
209 gcipher c; \
210 pre##_mgfctx k; \
211} gctx; \
212 \
213static 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 \
221static 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 \
227static void gdestroy(gcipher *c) \
228{ \
229 gctx *g = (gctx *)c; \
230 BURN(*g); \
231 S_DESTROY(g); \
232} \
233 \
234static const gcipher_ops gops = { \
235 &pre##_mgf, \
236 gencrypt, gencrypt, gdestroy, 0, 0 \
237}; \
238 \
239const gccipher pre##_mgf = { \
240 #pre "-mgf", pre##_mgfkeysz, 0, \
241 ginit \
242}; \
243 \
244/* --- Generic random number generator interface --- */ \
245 \
246typedef struct grctx { \
247 grand r; \
248 pre##_mgfctx k; \
249} grctx; \
250 \
251static void grdestroy(grand *r) \
252{ \
253 grctx *g = (grctx *)r; \
254 BURN(*g); \
255 S_DESTROY(g); \
256} \
257 \
258static 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 \
306static 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 \
314static 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 \
322static 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 \
328static const grand_ops grops = { \
329 #pre "-mgf", \
330 GRAND_CRYPTO, 0, \
331 grmisc, grdestroy, \
332 grword, grbyte, grword, grand_range, 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 \
346extern 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 \
354MGF_TEST(PRE, pre)
355
356/*----- Test rig ----------------------------------------------------------*/
357
358#ifdef TEST_RIG
359
360#include <stdio.h>
361
362#include "daftstory.h"
363
364/* --- @MGF_TEST@ --- *
365 *
366 * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions
367 *
368 * Use: Standard test rig for MGF functions.
369 */
370
371#define MGF_TEST(PRE, pre) \
372 \
373/* --- Initial plaintext for the test --- */ \
374 \
375static const octet text[] = TEXT; \
376 \
377/* --- Key and IV to use --- */ \
378 \
379static const octet key[] = KEY; \
380 \
381/* --- Buffers for encryption and decryption output --- */ \
382 \
383static octet ct[sizeof(text)]; \
384static octet pt[sizeof(text)]; \
385 \
386static void hexdump(const octet *p, size_t sz) \
387{ \
388 const octet *q = p + sz; \
389 for (sz = 0; p < q; p++, sz++) { \
390 printf("%02x", *p); \
391 if ((sz + 1) % PRE##_HASHSZ == 0) \
392 putchar(':'); \
393 } \
394} \
395 \
396int main(void) \
397{ \
398 size_t sz = 0, rest; \
399 pre##_mgfctx ctx; \
400 int status = 0; \
401 int done = 0; \
402 \
403 size_t keysz = strlen((const char *)key); \
404 \
405 fputs(#pre "-mgf: ", stdout); \
406 \
407 pre##_mgfinit(&ctx, key, keysz); \
408 \
409 while (sz <= sizeof(text)) { \
410 rest = sizeof(text) - sz; \
411 memcpy(ct, text, sizeof(text)); \
412 pre##_mgfsetindex(&ctx, 0); \
413 pre##_mgfencrypt(&ctx, ct, ct, sz); \
414 pre##_mgfencrypt(&ctx, ct + sz, ct + sz, rest); \
415 memcpy(pt, ct, sizeof(text)); \
416 pre##_mgfsetindex(&ctx, 0); \
417 pre##_mgfencrypt(&ctx, pt, pt, rest); \
418 pre##_mgfencrypt(&ctx, pt + rest, pt + rest, sz); \
419 if (memcmp(pt, text, sizeof(text)) == 0) { \
420 done++; \
421 if (sizeof(text) < 40 || done % 8 == 0) \
45c0fd36 422 fputc('.', stdout); \
fea9a197 423 if (done % 480 == 0) \
45c0fd36 424 fputs("\n\t", stdout); \
fea9a197 425 fflush(stdout); \
426 } else { \
427 printf("\nError (sz = %lu)\n", (unsigned long)sz); \
428 status = 1; \
429 printf("\tplaintext = "); hexdump(text, sz); \
45c0fd36
MW
430 printf(", "); hexdump(text + sz, rest); \
431 fputc('\n', stdout); \
fea9a197 432 printf("\tciphertext = "); hexdump(ct, sz); \
45c0fd36
MW
433 printf(", "); hexdump(ct + sz, rest); \
434 fputc('\n', stdout); \
fea9a197 435 printf("\trecovered text = "); hexdump(pt, sz); \
45c0fd36
MW
436 printf(", "); hexdump(pt + sz, rest); \
437 fputc('\n', stdout); \
fea9a197 438 fputc('\n', stdout); \
439 } \
440 if (sz < 63) \
441 sz++; \
442 else \
443 sz += 9; \
444 } \
445 \
446 fputs(status ? " failed\n" : " ok\n", stdout); \
447 return (status); \
448}
449
450#else
451# define MGF_TEST(PRE, pre)
452#endif
453
454/*----- That's all, folks -------------------------------------------------*/
455
456#ifdef __cplusplus
457 }
458#endif
459
460#endif