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