X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/d83a82be67d8e934bafc9a72d48a32c5f31b8d97..51a0f80584415b57d188db22b77a4cd5451b70cd:/sslprf.c diff --git a/sslprf.c b/sslprf.c new file mode 100644 index 0000000..e9682e5 --- /dev/null +++ b/sslprf.c @@ -0,0 +1,366 @@ +/* -*-c-*- + * + * $Id: sslprf.c,v 1.1 2001/04/06 22:05:10 mdw Exp $ + * + * The SSL 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. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: sslprf.c,v $ + * Revision 1.1 2001/04/06 22:05:10 mdw + * Add support for SSL pseudo-random function. + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include + +#include "arena.h" +#include "ghash.h" +#include "grand.h" +#include "paranoia.h" +#include "sslprf.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @step@ --- * + * + * Arguments: @sslprf_ctx *c@ = pointer to context structure + * + * Returns: --- + * + * Use: Steps the generator. + */ + +static void step(sslprf_ctx *c) +{ + octet buf[64]; + size_t n, sz; + octet x; + ghash *h, *hh; + octet *p; + + h = c->ci->init(); + x = 'A' + c->i - 1; + for (sz = c->i++; sz > 0; sz -= n) { + n = sz; + if (n > sizeof(buf)) + n = sizeof(buf); + memset(buf, x, n); + h->ops->hash(h, buf, n); + } + h->ops->hash(h, c->k, c->ksz); + h->ops->hash(h, c->sd, c->sdsz); + p = h->ops->done(h, 0); + + hh = c->co->init(); + hh->ops->hash(hh, c->k, c->ksz); + hh->ops->hash(hh, p, c->ihashsz); + c->p = hh->ops->done(hh, 0); + h->ops->destroy(h); + + c->h = hh; + c->sz = c->ohashsz; +} + +/* --- @sslprf_init@ --- * + * + * Arguments: @sslprf_ctx *c@ = pointer to a context structure + * @const gchash *hco, *hci@ = outer and inner hash functions + * @const void *k@ = pointer to secret buffer + * @size_t ksz@ = size of the secret + * @const void *sd@ = pointer to seed buffer + * @size_t sdsz@ = size of the seed + * + * Returns: --- + * + * Use: Initializes an SSL generator context. + */ + +void sslprf_init(sslprf_ctx *c, const gchash *hco, const gchash *hci, + const void *k, size_t ksz, + const void *sd, size_t sdsz) +{ + c->co = hco; c->ci = hci; + c->ohashsz = hco->hashsz; c->ihashsz = hci->hashsz; + c->k = k; c->ksz = ksz; c->sd = sd; c->sdsz = sdsz; + c->i = 1; + step(c); +} + +/* --- @sslprf_encrypt@ --- * + * + * Arguments: @sslprf_ctx *c@ = pointer to a context structure + * @const void *src@ = pointer to source buffer + * @void *dest@ = pointer to destination buffer + * @size_t sz@ = size of the buffers + * + * Returns: --- + * + * Use: Encrypts data using the SSL 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 sslprf_encrypt(sslprf_ctx *c, const void *src, void *dest, size_t sz) +{ + const octet *s = src; + octet *d = dest; + size_t i, n; + + while (sz) { + if (!c->sz) { + c->h->ops->destroy(c->h); + step(c); + } + n = c->sz; + 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; + } +} + +/* --- @sslprf_free@ --- * + * + * Arguments: @sslprf_ctx@ = pointer to a context + * + * Returns: --- + * + * Use: Frees resources held in an SSL generator context. + */ + +void sslprf_free(sslprf_ctx *c) +{ + c->h->ops->destroy(c->h); +} + +/* --- Generic random number generator --- */ + +typedef struct grctx { + grand r; + grand_ops ops; + sslprf_ctx prf; +} grctx; + +static void grdestroy(grand *r) +{ + grctx *g = (grctx *)r; + xfree((char *)g->ops.name); + xfree((octet *)g->prf.sd); + sslprf_free(&g->prf); + BURN(*g); + S_DESTROY(g); +} + +static void seed(grctx *g, const void *p, size_t sz) +{ + octet *q; + xfree((octet *)g->prf.sd); + g->prf.sd = q = xmalloc(sz); + memcpy(q, p, sz); + g->prf.sdsz = sz; +} + +static int grmisc(grand *r, unsigned op, ...) +{ + grctx *g = (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); + seed(g, buf, sizeof(buf)); + break; + case GRAND_SEEDUINT32: + i = va_arg(ap, uint32); + STORE32(buf, i); + 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); + seed(g, p, sz); + } break; + case GRAND_SEEDRAND: { + grand *rr = va_arg(ap, grand *); + octet buf[16]; + rr->ops->fill(rr, buf, sizeof(buf)); + seed(g, buf, sizeof(buf)); + } break; + default: + GRAND_BADOP; + break; + } + + va_end(ap); + return (rc); +} + +static octet grbyte(grand *r) +{ + grctx *g = (grctx *)r; + octet o; + sslprf_encrypt(&g->prf, 0, &o, 1); + return (o); +} + +static uint32 grword(grand *r) +{ + grctx *g = (grctx *)r; + octet b[4]; + sslprf_encrypt(&g->prf, 0, &b, sizeof(b)); + return (LOAD32(b)); +} + +static void grfill(grand *r, void *p, size_t sz) +{ + grctx *g = (grctx *)r; + sslprf_encrypt(&g->prf, 0, p, sz); +} + +static const grand_ops grops = { + "", + GRAND_CRYPTO, 0, + grmisc, grdestroy, + grword, grbyte, grword, grand_range, grfill +}; + +/* ---@sslprf_rand@ --- * + * + * Arguments: @const gchash *hco, const gchash *hci@ = hash 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: Pointer to generic random number generator interface. + * + * Use: Creates a generic generator which does TLS data expansion. + */ + +grand *sslprf_rand(const gchash *hco, const gchash *hci, + const void *k, size_t ksz, + const void *sd, size_t sdsz) +{ + grctx *g = S_CREATE(grctx); + dstr d = DSTR_INIT; + octet *q = xmalloc(sdsz); + memcpy(q, sd, sdsz); + dstr_putf(&d, "sslprf(%s,%s)", hco->name, hci->name); + g->ops = grops; + g->ops.name = xstrdup(d.buf); + g->r.ops = &g->ops; + dstr_destroy(&d); + sslprf_init(&g->prf, hco, hci, k, ksz, q, sdsz); + return (&g->r); +} + +/*----- Test rig ----------------------------------------------------------*/ + +#ifdef TEST_RIG + +#include +#include + +#include +#include + +#include "sha.h" +#include "md5.h" + +static int v_generate(dstr *v) +{ + grand *g; + dstr d = DSTR_INIT; + int ok = 1; + + g = sslprf_rand(&md5, &sha, 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 sslprf:" + "\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[] = { + { "sslprf", 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/sslprf"); + return (0); +} + +#endif + +/*----- That's all, folks -------------------------------------------------*/