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