Deprecate `rand_getgood'. Provide a new interface to ensure that a pool
authormdw <mdw>
Sat, 17 Jun 2000 11:53:55 +0000 (11:53 +0000)
committermdw <mdw>
Sat, 17 Jun 2000 11:53:55 +0000 (11:53 +0000)
is well seeded.  Use secure arena for memory allocation.

rand.c

diff --git a/rand.c b/rand.c
index a93bf9b..c3b777d 100644 (file)
--- a/rand.c
+++ b/rand.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: rand.c,v 1.4 1999/12/13 15:34:28 mdw Exp $
+ * $Id: rand.c,v 1.5 2000/06/17 11:53:55 mdw Exp $
  *
  * Secure random number generator
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: rand.c,v $
+ * Revision 1.5  2000/06/17 11:53:55  mdw
+ * Deprecate `rand_getgood'.  Provide a new interface to ensure that a pool
+ * is well seeded.  Use secure arena for memory allocation.
+ *
  * Revision 1.4  1999/12/13 15:34:28  mdw
  * Increase the entropy threshhold in rand_getgood.
  *
@@ -53,6 +57,7 @@
 #include <mLib/bits.h>
 #include <mLib/sub.h>
 
+#include "arena.h"
 #include "blowfish-cbc.h"
 #include "paranoia.h"
 #include "rand.h"
@@ -68,13 +73,16 @@ typedef struct gctx {
   rand_pool p;
 } gctx;
 
-static gctx pool = { { &gops } };      /* Default random pool */
+static gctx *pool = 0;                 /* Default random pool */
 
 /*----- Macros ------------------------------------------------------------*/
 
 #define RAND_RESOLVE(r) do {                                           \
-  if ((r) == RAND_GLOBAL)                                              \
-    (r) = &pool.p;                                                     \
+  if ((r) == RAND_GLOBAL) {                                            \
+    if (!pool)                                                         \
+      pool = (gctx *)rand_create();                                    \
+    (r) = &pool->p;                                                    \
+  }                                                                    \
 } while (0)
 
 #define TIMER(r) do {                                                  \
@@ -91,7 +99,9 @@ static gctx pool = { { &gops } };     /* Default random pool */
  * Returns:    ---
  *
  * Use:                Initializes a randomness pool.  The pool doesn't start out
- *             very random: that's your job to sort 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)
@@ -131,6 +141,31 @@ void rand_noisesrc(rand_pool *r, const rand_source *s)
   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
@@ -364,13 +399,11 @@ void rand_get(rand_pool *r, void *p, size_t sz)
  *
  * 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.
- *             If a noise source is attached to the pool in question, it is
- *             called to replenish the supply of good bits in the pool;
- *             otherwise this call is equivalent to @rand_get@.
+ * 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)
@@ -411,20 +444,34 @@ void rand_getgood(rand_pool *r, void *p, size_t sz)
 
 /*----- 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 = (r == &rand_global ? &pool : (gctx *)r);
-  if (g != &pool)
-    DESTROY(g);
+  gctx *g;
+  GRESOLVE(g, r);
+  if (g != pool) {
+    BURN(*g);
+    S_DESTROY(g);
+  }
 }
 
 static int gmisc(grand *r, unsigned op, ...)
 {
-  gctx *g = (r == &rand_global ? &pool : (gctx *)r);
+  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)) {
@@ -437,6 +484,7 @@ static int gmisc(grand *r, unsigned op, ...)
        case RAND_STRETCH:
        case RAND_KEY:
        case RAND_NOISESRC:
+       case RAND_SEED:
          rc = 1;
          break;
        default:
@@ -477,6 +525,9 @@ static int gmisc(grand *r, unsigned op, ...)
     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;
     default:
       GRAND_BADOP;
       break;
@@ -488,29 +539,32 @@ static int gmisc(grand *r, unsigned op, ...)
 
 static octet gbyte(grand *r)
 {
-  gctx *g = (r == &rand_global ? &pool : (gctx *)r);
+  gctx *g;
   octet o;
+  GRESOLVE(g, r);
   rand_getgood(&g->p, &o, 1);
   return (o);
 }
 
 static uint32 gword(grand *r)
 {
-  gctx *g = (r == &rand_global ? &pool : (gctx *)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 = (r == &rand_global ? &pool : (gctx *)r);
-  rand_getgood(&g->p, p, sz);
+  gctx *g;
+  GRESOLVE(g, r);
+  rand_get(&g->p, p, sz);
 }
 
 static const grand_ops gops = {
   "rand",
-  0,
+  GRAND_CRYPTO, 0,
   gmisc, gdestroy,
   gword, gbyte, gword, grand_range, gfill
 };
@@ -529,7 +583,7 @@ grand rand_global = { &gops };
 
 grand *rand_create(void)
 {
-  gctx *g = CREATE(gctx);
+  gctx *g = S_CREATE(gctx);
   g->r.ops = &gops;
   rand_init(&g->p);
   return (&g->r);