tests/Makefile.m4: Distribute the converted AES test-vector files.
[u/mdw/catacomb] / tlsprf.c
CommitLineData
d83a82be 1/* -*-c-*-
2 *
b817bfc6 3 * $Id: tlsprf.c,v 1.3 2004/04/08 01:36:15 mdw Exp $
d83a82be 4 *
5 * The TLS pseudo-random function
6 *
7 * (c) 2001 Straylight/Edgeware
8 */
9
45c0fd36 10/*----- Licensing notice --------------------------------------------------*
d83a82be 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.
45c0fd36 18 *
d83a82be 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.
45c0fd36 23 *
d83a82be 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
d83a82be 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
58void tlsdx_init(tlsdx_ctx *c, gmac *m, const void *sd, size_t sdsz)
59{
60 c->k = m;
b817bfc6 61 c->hashsz = GM_CLASS(c->k)->hashsz;
d83a82be 62 c->sd = sd; c->sdsz = sdsz;
55fae6a7 63
b817bfc6 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);
d83a82be 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
90void 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 {
b817bfc6 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);
d83a82be 106 c->i = h;
b817bfc6 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);
d83a82be 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
140void tlsdx_free(tlsdx_ctx *c)
141{
b817bfc6 142 GH_DESTROY(c->i);
143 GH_DESTROY(c->o);
d83a82be 144}
145
146/* --- Generic random number generator --- */
147
148typedef struct dx_grctx {
149 grand r;
150 grand_ops ops;
151 tlsdx_ctx dx;
152} dx_grctx;
153
154static 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
165static 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
174static 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;
45c0fd36 221 break;
d83a82be 222 }
223
224 va_end(ap);
225 return (rc);
226}
227
228static 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
236static 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
244static 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
250static const grand_ops dx_grops = {
55fae6a7 251 "<tlsdx-dummy>",
d83a82be 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
270grand *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;
b817bfc6 275 gmac *m = GM_KEY(mc, k, ksz);
d83a82be 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
303void 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
328void 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
343void 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
353typedef struct prf_grctx {
354 grand r;
355 grand_ops ops;
356 tlsprf_ctx prf;
357} prf_grctx;
358
359static 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
369static 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
379static 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;
45c0fd36 426 break;
d83a82be 427 }
428
429 va_end(ap);
430 return (rc);
431}
432
433static 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
441static 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
449static 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
455static const grand_ops prf_grops = {
55fae6a7 456 "<tlsprf-dummy>",
d83a82be 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
475grand *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
504static 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:"
45c0fd36 519 "\n\tkey = ");
d83a82be 520 type_hex.dump(&v[0], stdout);
45c0fd36 521 printf("\n\tseed = "); type_hex.dump(&v[1], stdout);
d83a82be 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
529static test_chunk defs[] = {
530 { "tlsprf", v_generate, { &type_hex, &type_hex, &type_hex, 0 } },
531 { 0, 0, { 0 } }
532};
533
534int 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 -------------------------------------------------*/