X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/ba6e6b64033b1f9de49feccb5c9cd438354481f7..0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a:/rand.c diff --git a/rand.c b/rand.c deleted file mode 100644 index b004b3f..0000000 --- a/rand.c +++ /dev/null @@ -1,586 +0,0 @@ -/* -*-c-*- - * - * $Id$ - * - * Secure random number generator - * - * (c) 1998 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 -#include -#include - -#include -#include - -#include "arena.h" -#include "blowfish-cbc.h" -#include "paranoia.h" -#include "rand.h" -#include "rmd160.h" -#include "rmd160-hmac.h" - -/*----- Static variables --------------------------------------------------*/ - -static const grand_ops gops; - -typedef struct gctx { - grand r; - rand_pool p; -} gctx; - -static gctx *pool = 0; /* Default random pool */ - -/*----- Macros ------------------------------------------------------------*/ - -#define RAND_RESOLVE(r) do { \ - if ((r) == RAND_GLOBAL) { \ - if (!pool) \ - pool = (gctx *)rand_create(); \ - (r) = &pool->p; \ - } \ -} while (0) - -#define TIMER(r) do { \ - if ((r)->s && (r)->s->timer) \ - (r)->s->timer(r); \ -} while (0) - -/*----- Main code ---------------------------------------------------------*/ - -/* --- @rand_init@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * - * Returns: --- - * - * Use: Initializes a randomness pool. The pool doesn't start out - * very random: that's your job to sort out. A good suggestion - * would be to attach an appropriate noise source and call - * @rand_seed@. - */ - -void rand_init(rand_pool *r) -{ - RAND_RESOLVE(r); - memset(r->pool, 0, sizeof(r->pool)); - memset(r->buf, 0, sizeof(r->buf)); - r->i = 0; - r->irot = 0; - r->ibits = r->obits = 0; - r->o = RAND_SECSZ; - r->s = 0; - rmd160_hmacinit(&r->k, 0, 0); - rand_gate(r); -} - -/* --- @rand_noisesrc@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * @const rand_source *s@ = pointer to source definition - * - * Returns: --- - * - * Use: Sets a noise source for a randomness pool. When the pool's - * estimate of good random bits falls to zero, the @getnoise@ - * function is called, passing the pool handle as an argument. - * It is expected to increase the number of good bits by at - * least one, because it'll be called over and over again until - * there are enough bits to satisfy the caller. The @timer@ - * function is called frequently throughout the generator's - * operation. - */ - -void rand_noisesrc(rand_pool *r, const rand_source *s) -{ - RAND_RESOLVE(r); - r->s = s; -} - -/* --- @rand_seed@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * @unsigned bits@ = number of bits to ensure - * - * Returns: --- - * - * Use: Ensures that there are at least @bits@ good bits of entropy - * in the pool. It is recommended that you call this after - * initializing a new pool. Requesting @bits > RAND_IBITS@ is - * doomed to failure (and is an error). - */ - -void rand_seed(rand_pool *r, unsigned bits) -{ - RAND_RESOLVE(r); - - assert(((void)"bits pointlessly large in rand_seed", bits <= RAND_IBITS)); - assert(((void)"no noise source in rand_seed", r->s)); - - while (r->ibits < bits) - r->s->getnoise(r); - rand_gate(r); -} - -/* --- @rand_key@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * @const void *k@ = pointer to key data - * @size_t sz@ = size of key data - * - * Returns: --- - * - * Use: Sets the secret key for a randomness pool. The key is used - * when mixing in new random bits. - */ - -void rand_key(rand_pool *r, const void *k, size_t sz) -{ - RAND_RESOLVE(r); - rmd160_hmacinit(&r->k, k, sz); -} - -/* --- @rand_add@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * @const void *p@ = pointer a buffer of data to add - * @size_t sz@ = size of the data buffer - * @unsigned goodbits@ = number of good bits estimated in buffer - * - * Returns: --- - * - * Use: Mixes the data in the buffer with the contents of the - * pool. The estimate of the number of good bits is added to - * the pool's own count. The mixing operation is not - * cryptographically strong. However, data in the input pool - * isn't output directly, only through the one-way gating - * operation, so that shouldn't matter. - */ - -void rand_add(rand_pool *r, const void *p, size_t sz, unsigned goodbits) -{ - const octet *c = p; - int i, rot; - -#if RAND_POOLSZ != 128 -# error Polynomial in rand_add is out of date. Fix it. -#endif - - RAND_RESOLVE(r); - - i = r->i; rot = r->irot; - - while (sz) { - octet o = *c++; - r->pool[i] ^= (ROL8(o, rot) ^ - r->pool[(i + 1) % RAND_POOLSZ] ^ - r->pool[(i + 2) % RAND_POOLSZ] ^ - r->pool[(i + 7) % RAND_POOLSZ]); - rot = (rot + 5) & 7; - i++; if (i >= RAND_POOLSZ) i -= RAND_POOLSZ; - sz--; - } - - r->i = i; - r->irot = rot; - r->ibits += goodbits; - if (r->ibits > RAND_IBITS) - r->ibits = RAND_IBITS; -} - -/* --- @rand_goodbits@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * - * Returns: Estimate of the number of good bits remaining in the pool. - */ - -unsigned rand_goodbits(rand_pool *r) -{ - RAND_RESOLVE(r); - return (r->ibits + r->obits); -} - -/* --- @rand_gate@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * - * Returns: --- - * - * Use: Mixes up the entire state of the generator in a nonreversible - * way. - */ - -void rand_gate(rand_pool *r) -{ - octet mac[RMD160_HASHSZ]; - - RAND_RESOLVE(r); - TIMER(r); - - /* --- Hash up all the data in the pool --- */ - - { - rmd160_macctx mc; - - rmd160_macinit(&mc, &r->k); - rmd160_machash(&mc, r->pool, sizeof(r->pool)); - rmd160_machash(&mc, r->buf, sizeof(r->buf)); - rmd160_macdone(&mc, mac); - BURN(mc); - } - - /* --- Now mangle all of the data based on the hash --- */ - - { - blowfish_cbcctx bc; - - blowfish_cbcinit(&bc, mac, sizeof(mac), 0); - blowfish_cbcencrypt(&bc, r->pool, r->pool, sizeof(r->pool)); - blowfish_cbcencrypt(&bc, r->buf, r->buf, sizeof(r->buf)); - BURN(bc); - } - - /* --- Reset the various state variables --- */ - - r->o = RAND_SECSZ; - r->obits += r->ibits; - if (r->obits > RAND_OBITS) { - r->ibits = r->obits - r->ibits; - r->obits = RAND_OBITS; - } else - r->ibits = 0; - TIMER(r); -} - -/* --- @rand_stretch@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * - * Returns: --- - * - * Use: Stretches the contents of the output buffer by transforming - * it in a nonreversible way. This doesn't add any entropy - * worth speaking about, but it works well enough when the - * caller doesn't care about that sort of thing. - */ - -void rand_stretch(rand_pool *r) -{ - octet mac[RMD160_HASHSZ]; - - RAND_RESOLVE(r); - TIMER(r); - - /* --- Hash up all the data in the buffer --- */ - - { - rmd160_macctx mc; - - rmd160_macinit(&mc, &r->k); - rmd160_machash(&mc, r->pool, sizeof(r->pool)); - rmd160_machash(&mc, r->buf, sizeof(r->buf)); - rmd160_macdone(&mc, mac); - BURN(mc); - } - - /* --- Now mangle the buffer based on that hash --- */ - - { - blowfish_cbcctx bc; - - blowfish_cbcinit(&bc, mac, sizeof(mac), 0); - blowfish_cbcencrypt(&bc, r->buf, r->buf, sizeof(r->buf)); - BURN(bc); - } - - /* --- Reset the various state variables --- */ - - r->o = RAND_SECSZ; - TIMER(r); -} - -/* --- @rand_get@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * @void *p@ = pointer to output buffer - * @size_t sz@ = size of output buffer - * - * Returns: --- - * - * Use: Gets random data from the pool. The pool's contents can't be - * determined from the output of this function; nor can the - * output data be determined from a knowledge of the data input - * to the pool wihtout also having knowledge of the secret key. - * The good bits counter is decremented, although no special - * action is taken if it reaches zero. - */ - -void rand_get(rand_pool *r, void *p, size_t sz) -{ - octet *o = p; - - RAND_RESOLVE(r); - TIMER(r); - - if (!sz) - return; - for (;;) { - if (r->o + sz <= RAND_BUFSZ) { - memcpy(o, r->buf + r->o, sz); - r->o += sz; - break; - } else { - size_t chunk = RAND_BUFSZ - r->o; - if (chunk) { - memcpy(o, r->buf + r->o, chunk); - sz -= chunk; - o += chunk; - } - rand_stretch(r); - } - } - - if (r->obits > sz * 8) - r->obits -= sz * 8; - else - r->obits = 0; -} - -/* --- @rand_getgood@ --- * - * - * Arguments: @rand_pool *r@ = pointer to a randomness pool - * @void *p@ = pointer to output buffer - * @size_t sz@ = size of output buffer - * - * Returns: --- - * - * Use: Gets random data from the pool, ensuring that there are - * enough good bits. This interface isn't recommended: it makes - * the generator slow, and doesn't provide much more security - * than @rand_get@, assuming you've previously done a - * @rand_seed@. - */ - -void rand_getgood(rand_pool *r, void *p, size_t sz) -{ - octet *o = p; - - RAND_RESOLVE(r); - - if (!sz) - return; - if (!r->s || !r->s->getnoise) { - rand_get(r, p, sz); - return; - } - TIMER(r); - - while (sz) { - size_t chunk = sz; - - if (chunk * 8 > r->obits) { - if (chunk * 8 > r->ibits + r->obits) - do r->s->getnoise(r); while (r->ibits + r->obits < 256); - rand_gate(r); - if (chunk * 8 > r->obits) - chunk = r->obits / 8; - } - - if (chunk + r->o > RAND_BUFSZ) - chunk = RAND_BUFSZ - r->o; - - memcpy(o, r->buf + r->o, chunk); - r->o += chunk; - r->obits -= chunk * 8; - o += chunk; - sz -= chunk; - } -} - -/*----- Generic random number generator interface -------------------------*/ - -#define GRESOLVE(g, r) do { \ - if (r != &rand_global) \ - g = (gctx *)r; \ - else { \ - if (!pool) \ - pool = (gctx *)rand_create(); \ - g = pool; \ - } \ -} while (0) - -static void gdestroy(grand *r) -{ - gctx *g; - GRESOLVE(g, r); - if (g != pool) { - BURN(*g); - S_DESTROY(g); - } -} - -static int gmisc(grand *r, unsigned op, ...) -{ - gctx *g; - va_list ap; - int rc = 0; - va_start(ap, op); - - GRESOLVE(g, r); - 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: - case RAND_GATE: - case RAND_STRETCH: - case RAND_KEY: - case RAND_NOISESRC: - case RAND_SEED: - case RAND_TIMER: - case RAND_GOODBITS: - case RAND_ADD: - rc = 1; - break; - default: - rc = 0; - break; - } - break; - case GRAND_SEEDINT: { - unsigned u = va_arg(ap, unsigned); - rand_add(&g->p, &u, sizeof(u), sizeof(u)); - } break; - case GRAND_SEEDUINT32: { - uint32 i = va_arg(ap, uint32); - rand_add(&g->p, &i, sizeof(i), 4); - } break; - case GRAND_SEEDBLOCK: { - const void *p = va_arg(ap, const void *); - size_t sz = va_arg(ap, size_t); - rand_add(&g->p, p, sz, sz); - } break; - case GRAND_SEEDRAND: { - grand *rr = va_arg(ap, grand *); - octet buf[16]; - rr->ops->fill(rr, buf, sizeof(buf)); - rand_add(&g->p, buf, sizeof(buf), 8); - } break; - case RAND_GATE: - rand_gate(&g->p); - break; - case RAND_STRETCH: - rand_stretch(&g->p); - break; - case RAND_KEY: { - const void *k = va_arg(ap, const void *); - size_t sz = va_arg(ap, size_t); - rand_key(&g->p, k, sz); - } break; - case RAND_NOISESRC: - rand_noisesrc(&g->p, va_arg(ap, const rand_source *)); - break; - case RAND_SEED: - rand_seed(&g->p, va_arg(ap, unsigned)); - break; - case RAND_TIMER: - TIMER(&g->p); - break; - case RAND_GOODBITS: - rc = rand_goodbits(&g->p); - break; - case RAND_ADD: { - const void *p = va_arg(ap, const void *); - size_t sz = va_arg(ap, size_t); - unsigned goodbits = va_arg(ap, unsigned); - rand_add(&g->p, p, sz, goodbits); - } break; - default: - GRAND_BADOP; - break; - } - - va_end(ap); - return (rc); -} - -static octet gbyte(grand *r) -{ - gctx *g; - octet o; - GRESOLVE(g, r); - rand_getgood(&g->p, &o, 1); - return (o); -} - -static uint32 gword(grand *r) -{ - gctx *g; - octet b[4]; - GRESOLVE(g, r); - rand_getgood(&g->p, &b, sizeof(b)); - return (LOAD32(b)); -} - -static void gfill(grand *r, void *p, size_t sz) -{ - gctx *g; - GRESOLVE(g, r); - rand_get(&g->p, p, sz); -} - -static const grand_ops gops = { - "rand", - GRAND_CRYPTO, 0, - gmisc, gdestroy, - gword, gbyte, gword, grand_range, gfill -}; - -grand rand_global = { &gops }; - -/* --- @rand_create@ --- * - * - * Arguments: --- - * - * Returns: Pointer to a generic generator. - * - * Use: Constructs a generic generator interface over a Catacomb - * entropy pool generator. - */ - -grand *rand_create(void) -{ - gctx *g = S_CREATE(gctx); - g->r.ops = &gops; - rand_init(&g->p); - return (&g->r); -} - -/*----- That's all, folks -------------------------------------------------*/