chiark / gitweb /
configure.ac: Replace with a new version.
[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 -------------------------------------------------*/