Force subkeys to be sorted in structured keys.
[u/mdw/catacomb] / tlsprf.c
CommitLineData
d83a82be 1/* -*-c-*-
2 *
55fae6a7 3 * $Id: tlsprf.c,v 1.2 2001/04/06 22:05:53 mdw Exp $
d83a82be 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 $
55fae6a7 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 *
d83a82be 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
70void 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;
55fae6a7 75
d83a82be 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
102void 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
152void 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
160typedef struct dx_grctx {
161 grand r;
162 grand_ops ops;
163 tlsdx_ctx dx;
164} dx_grctx;
165
166static 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
177static 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
186static 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
240static 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
248static 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
256static 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
262static const grand_ops dx_grops = {
55fae6a7 263 "<tlsdx-dummy>",
d83a82be 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
282grand *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
315void 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
340void 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
355void 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
365typedef struct prf_grctx {
366 grand r;
367 grand_ops ops;
368 tlsprf_ctx prf;
369} prf_grctx;
370
371static 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
381static 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
391static 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
445static 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
453static 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
461static 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
467static const grand_ops prf_grops = {
55fae6a7 468 "<tlsprf-dummy>",
d83a82be 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
487grand *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
516static 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
541static test_chunk defs[] = {
542 { "tlsprf", v_generate, { &type_hex, &type_hex, &type_hex, 0 } },
543 { 0, 0, { 0 } }
544};
545
546int 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 -------------------------------------------------*/