gdsa: Fix the conversion of hashes to integers to conform to the spec.
[u/mdw/catacomb] / mgf-def.h
1 /* -*-c-*-
2 *
3 * $Id: mgf-def.h,v 1.2 2004/04/08 01:36:15 mdw Exp $
4 *
5 * Definitions for the MGF-1 mask generator
6 *
7 * (c) 2000 Straylight/Edgeware
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
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.
18 *
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.
23 *
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
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 \
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 #pre "-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 #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 \
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_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 \
375 static const octet text[] = TEXT; \
376 \
377 /* --- Key and IV to use --- */ \
378 \
379 static const octet key[] = KEY; \
380 \
381 /* --- Buffers for encryption and decryption output --- */ \
382 \
383 static octet ct[sizeof(text)]; \
384 static octet pt[sizeof(text)]; \
385 \
386 static 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 \
396 int 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) \
422 fputc('.', stdout); \
423 if (done % 480 == 0) \
424 fputs("\n\t", stdout); \
425 fflush(stdout); \
426 } else { \
427 printf("\nError (sz = %lu)\n", (unsigned long)sz); \
428 status = 1; \
429 printf("\tplaintext = "); hexdump(text, sz); \
430 printf(", "); hexdump(text + sz, rest); \
431 fputc('\n', stdout); \
432 printf("\tciphertext = "); hexdump(ct, sz); \
433 printf(", "); hexdump(ct + sz, rest); \
434 fputc('\n', stdout); \
435 printf("\trecovered text = "); hexdump(pt, sz); \
436 printf(", "); hexdump(pt + sz, rest); \
437 fputc('\n', stdout); \
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