+++ /dev/null
-/* -*-c-*-
- *
- * $Id: tlsprf.c,v 1.3 2004/04/08 01:36:15 mdw Exp $
- *
- * The TLS pseudo-random function
- *
- * (c) 2001 Straylight/Edgeware
- */
-
-/*----- Licensing notice --------------------------------------------------*
- *
- * This file is part of Catacomb.
- *
- * Catacomb is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * Catacomb is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with Catacomb; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-/*----- Header files ------------------------------------------------------*/
-
-#include <mLib/alloc.h>
-#include <mLib/dstr.h>
-#include <mLib/sub.h>
-
-#include "arena.h"
-#include "gmac.h"
-#include "grand.h"
-#include "paranoia.h"
-#include "tlsprf.h"
-
-/*----- The data expansion function ---------------------------------------*/
-
-/* --- @tlsdx_init@ --- *
- *
- * Arguments: @tlsdx_ctx *c@ = pointer to a context
- * @gmac *m@ = pointer to a generic MAC instance
- * @const void *sd@ = pointer to the seed block
- * @size_t sdsz@ = size of the seed block
- *
- * Returns: ---
- *
- * Use: Initializes a context for the TLS data expansion function.
- * This doesn't take ownership of the MAC instance or the seed
- * memory, nor does it allocate copies.
- */
-
-void tlsdx_init(tlsdx_ctx *c, gmac *m, const void *sd, size_t sdsz)
-{
- c->k = m;
- c->hashsz = GM_CLASS(c->k)->hashsz;
- c->sd = sd; c->sdsz = sdsz;
-
- c->i = GM_INIT(c->k);
- GH_HASH(c->i, sd, sdsz);
- c->ai = GH_DONE(c->i, 0);
- c->o = GM_INIT(c->k);
- GH_HASH(c->o, c->ai, c->hashsz);
- GH_HASH(c->o, sd, sdsz);
- c->p = GH_DONE(c->o, 0);
- c->sz = c->hashsz;
-}
-
-/* --- @tlsdx_encrypt@ --- *
- *
- * Arguments: @tlsdx_ctx *c@ = pointer to a context
- * @const void *src@ = pointer to source data
- * @void *dest@ = pointer to destination buffer
- * @size_t sz@ = size of buffer
- *
- * Returns: ---
- *
- * Use: Encrypts data using the TLS data expansion function. If the
- * destination pointer is null, the generator is spun and no
- * output is produced; if the source pointer is null, raw output
- * from the generator is written; otherwise, the source data is
- * XORed with the generator output.
- */
-
-void tlsdx_encrypt(tlsdx_ctx *c, const void *src, void *dest, size_t sz)
-{
- const octet *s = src;
- octet *d = dest;
- ghash *h;
- size_t i;
- size_t n;
-
- while (sz) {
- if (c->sz)
- n = c->sz;
- else {
- h = GM_INIT(c->k);
- GH_HASH(h, c->ai, c->hashsz);
- c->ai = GH_DONE(h, 0);
- GH_DESTROY(c->i);
- c->i = h;
- GH_DESTROY(c->o);
- h = c->o = GM_INIT(c->k);
- GH_HASH(h, c->ai, c->hashsz);
- GH_HASH(h, c->sd, c->sdsz);
- c->p = GH_DONE(h, 0);
- c->sz = n = c->hashsz;
- }
- if (n > sz)
- n = sz;
- if (d) {
- if (!s)
- memcpy(d, c->p, n);
- else {
- for (i = 0; i < n; i++) d[i] = s[i] ^ c->p[i];
- s += n;
- }
- d += n;
- }
- c->p += n;
- c->sz -= n;
- sz -= n;
- }
-}
-
-/* --- @tlsdx_free@ --- *
- *
- * Arguments: @tlsdx_ctx *c@ = pointer to the context block
- *
- * Returns: ---
- *
- * Use: Frees a context for the TLS data expansion function
- */
-
-void tlsdx_free(tlsdx_ctx *c)
-{
- GH_DESTROY(c->i);
- GH_DESTROY(c->o);
-}
-
-/* --- Generic random number generator --- */
-
-typedef struct dx_grctx {
- grand r;
- grand_ops ops;
- tlsdx_ctx dx;
-} dx_grctx;
-
-static void dx_grdestroy(grand *r)
-{
- dx_grctx *g = (dx_grctx *)r;
- xfree((char *)g->ops.name);
- xfree((octet *)g->dx.sd);
- g->dx.k->ops->destroy(g->dx.k);
- tlsdx_free(&g->dx);
- BURN(*g);
- S_DESTROY(g);
-}
-
-static void dx_seed(dx_grctx *g, const void *p, size_t sz)
-{
- octet *q;
- xfree((octet *)g->dx.sd);
- g->dx.sd = q = xmalloc(sz);
- memcpy(q, p, sz);
- g->dx.sdsz = sz;
-}
-
-static int dx_grmisc(grand *r, unsigned op, ...)
-{
- dx_grctx *g = (dx_grctx *)r;
- va_list ap;
- int rc = 0;
- uint32 i;
- octet buf[4];
- va_start(ap, op);
-
- switch (op) {
- case GRAND_CHECK:
- switch (va_arg(ap, unsigned)) {
- case GRAND_CHECK:
- case GRAND_SEEDINT:
- case GRAND_SEEDUINT32:
- case GRAND_SEEDBLOCK:
- case GRAND_SEEDRAND:
- rc = 1;
- break;
- default:
- rc = 0;
- break;
- }
- break;
- case GRAND_SEEDINT:
- i = va_arg(ap, unsigned);
- STORE32(buf, i);
- dx_seed(g, buf, sizeof(buf));
- break;
- case GRAND_SEEDUINT32:
- i = va_arg(ap, uint32);
- STORE32(buf, i);
- dx_seed(g, buf, sizeof(buf));
- break;
- case GRAND_SEEDBLOCK: {
- const void *p = va_arg(ap, const void *);
- size_t sz = va_arg(ap, size_t);
- dx_seed(g, p, sz);
- } break;
- case GRAND_SEEDRAND: {
- grand *rr = va_arg(ap, grand *);
- octet buf[16];
- rr->ops->fill(rr, buf, sizeof(buf));
- dx_seed(g, buf, sizeof(buf));
- } break;
- default:
- GRAND_BADOP;
- break;
- }
-
- va_end(ap);
- return (rc);
-}
-
-static octet dx_grbyte(grand *r)
-{
- dx_grctx *g = (dx_grctx *)r;
- octet o;
- tlsdx_encrypt(&g->dx, 0, &o, 1);
- return (o);
-}
-
-static uint32 dx_grword(grand *r)
-{
- dx_grctx *g = (dx_grctx *)r;
- octet b[4];
- tlsdx_encrypt(&g->dx, 0, &b, sizeof(b));
- return (LOAD32(b));
-}
-
-static void dx_grfill(grand *r, void *p, size_t sz)
-{
- dx_grctx *g = (dx_grctx *)r;
- tlsdx_encrypt(&g->dx, 0, p, sz);
-}
-
-static const grand_ops dx_grops = {
- "<tlsdx-dummy>",
- GRAND_CRYPTO, 0,
- dx_grmisc, dx_grdestroy,
- dx_grword, dx_grbyte, dx_grword, grand_range, dx_grfill
-};
-
-/* ---@tlsdx_rand@ --- *
- *
- * Arguments: @const gcmac *mc@ = MAC function to use
- * @const void *k@ = pointer to the key material
- * @size_t ksz@ = size of the key material
- * @const void *sd@ = pointer to the seed material
- * @size_t sdsz@ = size of the seed material
- *
- * Returns: Pointer to generic random number generator interface.
- *
- * Use: Creates a generic generator which does TLS data expansion.
- */
-
-grand *tlsdx_rand(const gcmac *mc, const void *k, size_t ksz,
- const void *sd, size_t sdsz)
-{
- dx_grctx *g = S_CREATE(dx_grctx);
- dstr d = DSTR_INIT;
- gmac *m = GM_KEY(mc, k, ksz);
- octet *q = xmalloc(sdsz);
- memcpy(q, sd, sdsz);
- dstr_putf(&d, "tlsdx(%s)", mc->name);
- g->ops = dx_grops;
- g->ops.name = xstrdup(d.buf);
- g->r.ops = &g->ops;
- dstr_destroy(&d);
- tlsdx_init(&g->dx, m, q, sdsz);
- return (&g->r);
-}
-
-/* --- The actual very paranoid PRF ---------------------------------------*/
-
-/* --- @tlsprf_init@ --- *
- *
- * Arguments: @tlsprf_ctx *c@ = pointer to context block
- * @const gcmac *mcx, *mcy@ = left and right MAC functions
- * @const void *k@ = pointer to the key material
- * @size_t ksz@ = size of the key material
- * @const void *sd@ = pointer to the seed material
- * @size_t sdsz@ = size of the seed material
- *
- * Returns: ---
- *
- * Use: Initializes a TLS PRF context.
- */
-
-void tlsprf_init(tlsprf_ctx *c, const gcmac *mcx, const gcmac *mcy,
- const void *k, size_t ksz, const void *sd, size_t sdsz)
-{
- size_t n = (ksz + 1)/2;
- const octet *kk = k;
- tlsdx_init(&c->px, mcx->key(kk, n), sd, sdsz);
- tlsdx_init(&c->py, mcy->key(kk + ksz - n, n), sd, sdsz);
-}
-
-/* --- @tlsprf_encrypt@ --- *
- *
- * Arguments: @tlsprf_ctx *c@ = pointer to a context
- * @const void *src@ = pointer to source data
- * @void *dest@ = pointer to destination buffer
- * @size_t sz@ = size of buffer
- *
- * Returns: ---
- *
- * Use: Encrypts data using the TLS pseudo-random function. If the
- * destination pointer is null, the generator is spun and no
- * output is produced; if the source pointer is null, raw output
- * from the generator is written; otherwise, the source data is
- * XORed with the generator output.
- */
-
-void tlsprf_encrypt(tlsprf_ctx *c, const void *src, void *dest, size_t sz)
-{
- tlsdx_encrypt(&c->px, src, dest, sz);
- tlsdx_encrypt(&c->py, dest, dest, sz);
-}
-
-/* --- @tlsprf_free@ --- *
- *
- * Arguments: @tlsprf_ctx *c@ = pointer to a context
- *
- * Returns: ---
- *
- * Use: Frees a TLS PRF context.
- */
-
-void tlsprf_free(tlsprf_ctx *c)
-{
- c->px.k->ops->destroy(c->px.k);
- c->py.k->ops->destroy(c->py.k);
- tlsdx_free(&c->px);
- tlsdx_free(&c->py);
-}
-
-/* --- Generic random number generator --- */
-
-typedef struct prf_grctx {
- grand r;
- grand_ops ops;
- tlsprf_ctx prf;
-} prf_grctx;
-
-static void prf_grdestroy(grand *r)
-{
- prf_grctx *g = (prf_grctx *)r;
- xfree((char *)g->ops.name);
- xfree((octet *)g->prf.px.sd);
- tlsprf_free(&g->prf);
- BURN(*g);
- S_DESTROY(g);
-}
-
-static void prf_seed(prf_grctx *g, const void *p, size_t sz)
-{
- octet *q;
-
- xfree((octet *)g->prf.px.sz);
- g->prf.px.sd = g->prf.py.sd = q = xmalloc(sz);
- memcpy(q, p, sz);
- g->prf.px.sdsz = g->prf.py.sdsz = sz;
-}
-
-static int prf_grmisc(grand *r, unsigned op, ...)
-{
- prf_grctx *g = (prf_grctx *)r;
- va_list ap;
- int rc = 0;
- uint32 i;
- octet buf[4];
- va_start(ap, op);
-
- switch (op) {
- case GRAND_CHECK:
- switch (va_arg(ap, unsigned)) {
- case GRAND_CHECK:
- case GRAND_SEEDINT:
- case GRAND_SEEDUINT32:
- case GRAND_SEEDBLOCK:
- case GRAND_SEEDRAND:
- rc = 1;
- break;
- default:
- rc = 0;
- break;
- }
- break;
- case GRAND_SEEDINT:
- i = va_arg(ap, unsigned);
- STORE32(buf, i);
- prf_seed(g, buf, sizeof(buf));
- break;
- case GRAND_SEEDUINT32:
- i = va_arg(ap, uint32);
- STORE32(buf, i);
- prf_seed(g, buf, sizeof(buf));
- break;
- case GRAND_SEEDBLOCK: {
- const void *p = va_arg(ap, const void *);
- size_t sz = va_arg(ap, size_t);
- prf_seed(g, p, sz);
- } break;
- case GRAND_SEEDRAND: {
- grand *rr = va_arg(ap, grand *);
- octet buf[16];
- rr->ops->fill(rr, buf, sizeof(buf));
- prf_seed(g, buf, sizeof(buf));
- } break;
- default:
- GRAND_BADOP;
- break;
- }
-
- va_end(ap);
- return (rc);
-}
-
-static octet prf_grbyte(grand *r)
-{
- prf_grctx *g = (prf_grctx *)r;
- octet o;
- tlsprf_encrypt(&g->prf, 0, &o, 1);
- return (o);
-}
-
-static uint32 prf_grword(grand *r)
-{
- prf_grctx *g = (prf_grctx *)r;
- octet b[4];
- tlsprf_encrypt(&g->prf, 0, &b, sizeof(b));
- return (LOAD32(b));
-}
-
-static void prf_grfill(grand *r, void *p, size_t sz)
-{
- prf_grctx *g = (prf_grctx *)r;
- tlsprf_encrypt(&g->prf, 0, p, sz);
-}
-
-static const grand_ops prf_grops = {
- "<tlsprf-dummy>",
- GRAND_CRYPTO, 0,
- prf_grmisc, prf_grdestroy,
- prf_grword, prf_grbyte, prf_grword, grand_range, prf_grfill
-};
-
-/* ---@tlsprf_rand@ --- *
- *
- * Arguments: @const gcmac *mcx, *mcy@ = MAC function to use
- * @const void *k@ = pointer to the key material
- * @size_t ksz@ = size of the key material
- * @const void *sd@ = pointer to the seed material
- * @size_t sdsz@ = size of the seed material
- *
- * Returns: Pointer to generic random number generator interface.
- *
- * Use: Creates a generic generator which does TLS data expansion.
- */
-
-grand *tlsprf_rand(const gcmac *mcx, const gcmac *mcy,
- const void *k, size_t ksz, const void *sd, size_t sdsz)
-{
- prf_grctx *g = S_CREATE(prf_grctx);
- dstr d = DSTR_INIT;
- octet *q = xmalloc(sdsz);
- memcpy(q, sd, sdsz);
- dstr_putf(&d, "tlsprf(%s,%s)", mcx->name, mcy->name);
- g->ops = prf_grops;
- g->ops.name = xstrdup(d.buf);
- g->r.ops = &g->ops;
- dstr_destroy(&d);
- tlsprf_init(&g->prf, mcx, mcy, k, ksz, q, sdsz);
- return (&g->r);
-}
-
-/*----- Test rig ----------------------------------------------------------*/
-
-#ifdef TEST_RIG
-
-#include <stdio.h>
-#include <string.h>
-
-#include <mLib/quis.h>
-#include <mLib/testrig.h>
-
-#include "sha-hmac.h"
-#include "md5-hmac.h"
-
-static int v_generate(dstr *v)
-{
- grand *g;
- dstr d = DSTR_INIT;
- int ok = 1;
-
- g = tlsprf_rand(&md5_hmac, &sha_hmac,
- v[0].buf, v[0].len, v[1].buf, v[1].len);
- dstr_ensure(&d, v[2].len);
- d.len = v[2].len;
- g->ops->fill(g, d.buf, d.len);
- g->ops->destroy(g);
- if (memcmp(v[2].buf, d.buf, d.len) != 0) {
- ok = 0;
- printf("\nfail tlsprf:"
- "\n\tkey = ");
- type_hex.dump(&v[0], stdout);
- printf("\n\tseed = "); type_hex.dump(&v[1], stdout);
- printf("\n\texpected = "); type_hex.dump(&v[2], stdout);
- printf("\n\tcalculated = "); type_hex.dump(&d, stdout);
- putchar('\n');
- }
- return (ok);
-}
-
-static test_chunk defs[] = {
- { "tlsprf", v_generate, { &type_hex, &type_hex, &type_hex, 0 } },
- { 0, 0, { 0 } }
-};
-
-int main(int argc, char *argv[])
-{
- test_run(argc, argv, defs, SRCDIR"/tests/tlsprf");
- return (0);
-}
-
-#endif
-
-/*----- That's all, folks -------------------------------------------------*/