hashsum.1: Write some notes about compatibility with GNU Coreutils.
[u/mdw/catacomb] / tlsprf.c
1 /* -*-c-*-
2 *
3 * $Id: tlsprf.c,v 1.3 2004/04/08 01:36:15 mdw Exp $
4 *
5 * The TLS pseudo-random function
6 *
7 * (c) 2001 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 /*----- Header files ------------------------------------------------------*/
31
32 #include <mLib/alloc.h>
33 #include <mLib/dstr.h>
34 #include <mLib/sub.h>
35
36 #include "arena.h"
37 #include "gmac.h"
38 #include "grand.h"
39 #include "paranoia.h"
40 #include "tlsprf.h"
41
42 /*----- The data expansion function ---------------------------------------*/
43
44 /* --- @tlsdx_init@ --- *
45 *
46 * Arguments: @tlsdx_ctx *c@ = pointer to a context
47 * @gmac *m@ = pointer to a generic MAC instance
48 * @const void *sd@ = pointer to the seed block
49 * @size_t sdsz@ = size of the seed block
50 *
51 * Returns: ---
52 *
53 * Use: Initializes a context for the TLS data expansion function.
54 * This doesn't take ownership of the MAC instance or the seed
55 * memory, nor does it allocate copies.
56 */
57
58 void tlsdx_init(tlsdx_ctx *c, gmac *m, const void *sd, size_t sdsz)
59 {
60 c->k = m;
61 c->hashsz = GM_CLASS(c->k)->hashsz;
62 c->sd = sd; c->sdsz = sdsz;
63
64 c->i = GM_INIT(c->k);
65 GH_HASH(c->i, sd, sdsz);
66 c->ai = GH_DONE(c->i, 0);
67 c->o = GM_INIT(c->k);
68 GH_HASH(c->o, c->ai, c->hashsz);
69 GH_HASH(c->o, sd, sdsz);
70 c->p = GH_DONE(c->o, 0);
71 c->sz = c->hashsz;
72 }
73
74 /* --- @tlsdx_encrypt@ --- *
75 *
76 * Arguments: @tlsdx_ctx *c@ = pointer to a context
77 * @const void *src@ = pointer to source data
78 * @void *dest@ = pointer to destination buffer
79 * @size_t sz@ = size of buffer
80 *
81 * Returns: ---
82 *
83 * Use: Encrypts data using the TLS data expansion function. If the
84 * destination pointer is null, the generator is spun and no
85 * output is produced; if the source pointer is null, raw output
86 * from the generator is written; otherwise, the source data is
87 * XORed with the generator output.
88 */
89
90 void tlsdx_encrypt(tlsdx_ctx *c, const void *src, void *dest, size_t sz)
91 {
92 const octet *s = src;
93 octet *d = dest;
94 ghash *h;
95 size_t i;
96 size_t n;
97
98 while (sz) {
99 if (c->sz)
100 n = c->sz;
101 else {
102 h = GM_INIT(c->k);
103 GH_HASH(h, c->ai, c->hashsz);
104 c->ai = GH_DONE(h, 0);
105 GH_DESTROY(c->i);
106 c->i = h;
107 GH_DESTROY(c->o);
108 h = c->o = GM_INIT(c->k);
109 GH_HASH(h, c->ai, c->hashsz);
110 GH_HASH(h, c->sd, c->sdsz);
111 c->p = GH_DONE(h, 0);
112 c->sz = n = c->hashsz;
113 }
114 if (n > sz)
115 n = sz;
116 if (d) {
117 if (!s)
118 memcpy(d, c->p, n);
119 else {
120 for (i = 0; i < n; i++) d[i] = s[i] ^ c->p[i];
121 s += n;
122 }
123 d += n;
124 }
125 c->p += n;
126 c->sz -= n;
127 sz -= n;
128 }
129 }
130
131 /* --- @tlsdx_free@ --- *
132 *
133 * Arguments: @tlsdx_ctx *c@ = pointer to the context block
134 *
135 * Returns: ---
136 *
137 * Use: Frees a context for the TLS data expansion function
138 */
139
140 void tlsdx_free(tlsdx_ctx *c)
141 {
142 GH_DESTROY(c->i);
143 GH_DESTROY(c->o);
144 }
145
146 /* --- Generic random number generator --- */
147
148 typedef struct dx_grctx {
149 grand r;
150 grand_ops ops;
151 tlsdx_ctx dx;
152 } dx_grctx;
153
154 static void dx_grdestroy(grand *r)
155 {
156 dx_grctx *g = (dx_grctx *)r;
157 xfree((char *)g->ops.name);
158 xfree((octet *)g->dx.sd);
159 g->dx.k->ops->destroy(g->dx.k);
160 tlsdx_free(&g->dx);
161 BURN(*g);
162 S_DESTROY(g);
163 }
164
165 static void dx_seed(dx_grctx *g, const void *p, size_t sz)
166 {
167 octet *q;
168 xfree((octet *)g->dx.sd);
169 g->dx.sd = q = xmalloc(sz);
170 memcpy(q, p, sz);
171 g->dx.sdsz = sz;
172 }
173
174 static int dx_grmisc(grand *r, unsigned op, ...)
175 {
176 dx_grctx *g = (dx_grctx *)r;
177 va_list ap;
178 int rc = 0;
179 uint32 i;
180 octet buf[4];
181 va_start(ap, op);
182
183 switch (op) {
184 case GRAND_CHECK:
185 switch (va_arg(ap, unsigned)) {
186 case GRAND_CHECK:
187 case GRAND_SEEDINT:
188 case GRAND_SEEDUINT32:
189 case GRAND_SEEDBLOCK:
190 case GRAND_SEEDRAND:
191 rc = 1;
192 break;
193 default:
194 rc = 0;
195 break;
196 }
197 break;
198 case GRAND_SEEDINT:
199 i = va_arg(ap, unsigned);
200 STORE32(buf, i);
201 dx_seed(g, buf, sizeof(buf));
202 break;
203 case GRAND_SEEDUINT32:
204 i = va_arg(ap, uint32);
205 STORE32(buf, i);
206 dx_seed(g, buf, sizeof(buf));
207 break;
208 case GRAND_SEEDBLOCK: {
209 const void *p = va_arg(ap, const void *);
210 size_t sz = va_arg(ap, size_t);
211 dx_seed(g, p, sz);
212 } break;
213 case GRAND_SEEDRAND: {
214 grand *rr = va_arg(ap, grand *);
215 octet buf[16];
216 rr->ops->fill(rr, buf, sizeof(buf));
217 dx_seed(g, buf, sizeof(buf));
218 } break;
219 default:
220 GRAND_BADOP;
221 break;
222 }
223
224 va_end(ap);
225 return (rc);
226 }
227
228 static octet dx_grbyte(grand *r)
229 {
230 dx_grctx *g = (dx_grctx *)r;
231 octet o;
232 tlsdx_encrypt(&g->dx, 0, &o, 1);
233 return (o);
234 }
235
236 static uint32 dx_grword(grand *r)
237 {
238 dx_grctx *g = (dx_grctx *)r;
239 octet b[4];
240 tlsdx_encrypt(&g->dx, 0, &b, sizeof(b));
241 return (LOAD32(b));
242 }
243
244 static void dx_grfill(grand *r, void *p, size_t sz)
245 {
246 dx_grctx *g = (dx_grctx *)r;
247 tlsdx_encrypt(&g->dx, 0, p, sz);
248 }
249
250 static const grand_ops dx_grops = {
251 "<tlsdx-dummy>",
252 GRAND_CRYPTO, 0,
253 dx_grmisc, dx_grdestroy,
254 dx_grword, dx_grbyte, dx_grword, grand_range, dx_grfill
255 };
256
257 /* ---@tlsdx_rand@ --- *
258 *
259 * Arguments: @const gcmac *mc@ = MAC function to use
260 * @const void *k@ = pointer to the key material
261 * @size_t ksz@ = size of the key material
262 * @const void *sd@ = pointer to the seed material
263 * @size_t sdsz@ = size of the seed material
264 *
265 * Returns: Pointer to generic random number generator interface.
266 *
267 * Use: Creates a generic generator which does TLS data expansion.
268 */
269
270 grand *tlsdx_rand(const gcmac *mc, const void *k, size_t ksz,
271 const void *sd, size_t sdsz)
272 {
273 dx_grctx *g = S_CREATE(dx_grctx);
274 dstr d = DSTR_INIT;
275 gmac *m = GM_KEY(mc, k, ksz);
276 octet *q = xmalloc(sdsz);
277 memcpy(q, sd, sdsz);
278 dstr_putf(&d, "tlsdx(%s)", mc->name);
279 g->ops = dx_grops;
280 g->ops.name = xstrdup(d.buf);
281 g->r.ops = &g->ops;
282 dstr_destroy(&d);
283 tlsdx_init(&g->dx, m, q, sdsz);
284 return (&g->r);
285 }
286
287 /* --- The actual very paranoid PRF ---------------------------------------*/
288
289 /* --- @tlsprf_init@ --- *
290 *
291 * Arguments: @tlsprf_ctx *c@ = pointer to context block
292 * @const gcmac *mcx, *mcy@ = left and right MAC functions
293 * @const void *k@ = pointer to the key material
294 * @size_t ksz@ = size of the key material
295 * @const void *sd@ = pointer to the seed material
296 * @size_t sdsz@ = size of the seed material
297 *
298 * Returns: ---
299 *
300 * Use: Initializes a TLS PRF context.
301 */
302
303 void tlsprf_init(tlsprf_ctx *c, const gcmac *mcx, const gcmac *mcy,
304 const void *k, size_t ksz, const void *sd, size_t sdsz)
305 {
306 size_t n = (ksz + 1)/2;
307 const octet *kk = k;
308 tlsdx_init(&c->px, mcx->key(kk, n), sd, sdsz);
309 tlsdx_init(&c->py, mcy->key(kk + ksz - n, n), sd, sdsz);
310 }
311
312 /* --- @tlsprf_encrypt@ --- *
313 *
314 * Arguments: @tlsprf_ctx *c@ = pointer to a context
315 * @const void *src@ = pointer to source data
316 * @void *dest@ = pointer to destination buffer
317 * @size_t sz@ = size of buffer
318 *
319 * Returns: ---
320 *
321 * Use: Encrypts data using the TLS pseudo-random function. If the
322 * destination pointer is null, the generator is spun and no
323 * output is produced; if the source pointer is null, raw output
324 * from the generator is written; otherwise, the source data is
325 * XORed with the generator output.
326 */
327
328 void tlsprf_encrypt(tlsprf_ctx *c, const void *src, void *dest, size_t sz)
329 {
330 tlsdx_encrypt(&c->px, src, dest, sz);
331 tlsdx_encrypt(&c->py, dest, dest, sz);
332 }
333
334 /* --- @tlsprf_free@ --- *
335 *
336 * Arguments: @tlsprf_ctx *c@ = pointer to a context
337 *
338 * Returns: ---
339 *
340 * Use: Frees a TLS PRF context.
341 */
342
343 void tlsprf_free(tlsprf_ctx *c)
344 {
345 c->px.k->ops->destroy(c->px.k);
346 c->py.k->ops->destroy(c->py.k);
347 tlsdx_free(&c->px);
348 tlsdx_free(&c->py);
349 }
350
351 /* --- Generic random number generator --- */
352
353 typedef struct prf_grctx {
354 grand r;
355 grand_ops ops;
356 tlsprf_ctx prf;
357 } prf_grctx;
358
359 static void prf_grdestroy(grand *r)
360 {
361 prf_grctx *g = (prf_grctx *)r;
362 xfree((char *)g->ops.name);
363 xfree((octet *)g->prf.px.sd);
364 tlsprf_free(&g->prf);
365 BURN(*g);
366 S_DESTROY(g);
367 }
368
369 static void prf_seed(prf_grctx *g, const void *p, size_t sz)
370 {
371 octet *q;
372
373 xfree((octet *)g->prf.px.sz);
374 g->prf.px.sd = g->prf.py.sd = q = xmalloc(sz);
375 memcpy(q, p, sz);
376 g->prf.px.sdsz = g->prf.py.sdsz = sz;
377 }
378
379 static int prf_grmisc(grand *r, unsigned op, ...)
380 {
381 prf_grctx *g = (prf_grctx *)r;
382 va_list ap;
383 int rc = 0;
384 uint32 i;
385 octet buf[4];
386 va_start(ap, op);
387
388 switch (op) {
389 case GRAND_CHECK:
390 switch (va_arg(ap, unsigned)) {
391 case GRAND_CHECK:
392 case GRAND_SEEDINT:
393 case GRAND_SEEDUINT32:
394 case GRAND_SEEDBLOCK:
395 case GRAND_SEEDRAND:
396 rc = 1;
397 break;
398 default:
399 rc = 0;
400 break;
401 }
402 break;
403 case GRAND_SEEDINT:
404 i = va_arg(ap, unsigned);
405 STORE32(buf, i);
406 prf_seed(g, buf, sizeof(buf));
407 break;
408 case GRAND_SEEDUINT32:
409 i = va_arg(ap, uint32);
410 STORE32(buf, i);
411 prf_seed(g, buf, sizeof(buf));
412 break;
413 case GRAND_SEEDBLOCK: {
414 const void *p = va_arg(ap, const void *);
415 size_t sz = va_arg(ap, size_t);
416 prf_seed(g, p, sz);
417 } break;
418 case GRAND_SEEDRAND: {
419 grand *rr = va_arg(ap, grand *);
420 octet buf[16];
421 rr->ops->fill(rr, buf, sizeof(buf));
422 prf_seed(g, buf, sizeof(buf));
423 } break;
424 default:
425 GRAND_BADOP;
426 break;
427 }
428
429 va_end(ap);
430 return (rc);
431 }
432
433 static octet prf_grbyte(grand *r)
434 {
435 prf_grctx *g = (prf_grctx *)r;
436 octet o;
437 tlsprf_encrypt(&g->prf, 0, &o, 1);
438 return (o);
439 }
440
441 static uint32 prf_grword(grand *r)
442 {
443 prf_grctx *g = (prf_grctx *)r;
444 octet b[4];
445 tlsprf_encrypt(&g->prf, 0, &b, sizeof(b));
446 return (LOAD32(b));
447 }
448
449 static void prf_grfill(grand *r, void *p, size_t sz)
450 {
451 prf_grctx *g = (prf_grctx *)r;
452 tlsprf_encrypt(&g->prf, 0, p, sz);
453 }
454
455 static const grand_ops prf_grops = {
456 "<tlsprf-dummy>",
457 GRAND_CRYPTO, 0,
458 prf_grmisc, prf_grdestroy,
459 prf_grword, prf_grbyte, prf_grword, grand_range, prf_grfill
460 };
461
462 /* ---@tlsprf_rand@ --- *
463 *
464 * Arguments: @const gcmac *mcx, *mcy@ = MAC function to use
465 * @const void *k@ = pointer to the key material
466 * @size_t ksz@ = size of the key material
467 * @const void *sd@ = pointer to the seed material
468 * @size_t sdsz@ = size of the seed material
469 *
470 * Returns: Pointer to generic random number generator interface.
471 *
472 * Use: Creates a generic generator which does TLS data expansion.
473 */
474
475 grand *tlsprf_rand(const gcmac *mcx, const gcmac *mcy,
476 const void *k, size_t ksz, const void *sd, size_t sdsz)
477 {
478 prf_grctx *g = S_CREATE(prf_grctx);
479 dstr d = DSTR_INIT;
480 octet *q = xmalloc(sdsz);
481 memcpy(q, sd, sdsz);
482 dstr_putf(&d, "tlsprf(%s,%s)", mcx->name, mcy->name);
483 g->ops = prf_grops;
484 g->ops.name = xstrdup(d.buf);
485 g->r.ops = &g->ops;
486 dstr_destroy(&d);
487 tlsprf_init(&g->prf, mcx, mcy, k, ksz, q, sdsz);
488 return (&g->r);
489 }
490
491 /*----- Test rig ----------------------------------------------------------*/
492
493 #ifdef TEST_RIG
494
495 #include <stdio.h>
496 #include <string.h>
497
498 #include <mLib/quis.h>
499 #include <mLib/testrig.h>
500
501 #include "sha-hmac.h"
502 #include "md5-hmac.h"
503
504 static int v_generate(dstr *v)
505 {
506 grand *g;
507 dstr d = DSTR_INIT;
508 int ok = 1;
509
510 g = tlsprf_rand(&md5_hmac, &sha_hmac,
511 v[0].buf, v[0].len, v[1].buf, v[1].len);
512 dstr_ensure(&d, v[2].len);
513 d.len = v[2].len;
514 g->ops->fill(g, d.buf, d.len);
515 g->ops->destroy(g);
516 if (memcmp(v[2].buf, d.buf, d.len) != 0) {
517 ok = 0;
518 printf("\nfail tlsprf:"
519 "\n\tkey = ");
520 type_hex.dump(&v[0], stdout);
521 printf("\n\tseed = "); type_hex.dump(&v[1], stdout);
522 printf("\n\texpected = "); type_hex.dump(&v[2], stdout);
523 printf("\n\tcalculated = "); type_hex.dump(&d, stdout);
524 putchar('\n');
525 }
526 return (ok);
527 }
528
529 static test_chunk defs[] = {
530 { "tlsprf", v_generate, { &type_hex, &type_hex, &type_hex, 0 } },
531 { 0, 0, { 0 } }
532 };
533
534 int main(int argc, char *argv[])
535 {
536 test_run(argc, argv, defs, SRCDIR"/tests/tlsprf");
537 return (0);
538 }
539
540 #endif
541
542 /*----- That's all, folks -------------------------------------------------*/