d83a82be |
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 -------------------------------------------------*/ |