Major update: make random number sources configurable. Generate
authormdw <mdw>
Mon, 8 Dec 1997 15:29:27 +0000 (15:29 +0000)
committermdw <mdw>
Mon, 8 Dec 1997 15:29:27 +0000 (15:29 +0000)
warnings if there isn't enough randomness available.

src/keygen.c

index eba38d9..4e016fa 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: keygen.c,v 1.3 1997/09/17 15:29:28 mdw Exp $
+ * $Id: keygen.c,v 1.4 1997/12/08 15:29:27 mdw Exp $
  *
  * Key generation
  *
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: keygen.c,v $
- * Revision 1.3  1997/09/17 15:29:28  mdw
+ * Revision 1.4  1997/12/08 15:29:27  mdw
+ * Major update: make random number sources configurable.  Generate
+ * warnings if there isn't enough randomness available.
+ *
+ * Revision 1.3  1997/09/17  15:29:28  mdw
  * Mix the noise from the key timings with some other environmental noise
  * (obtained from `noise_acquire') for a little bit more randomness.
  *
@@ -434,9 +438,16 @@ int main(int argc, char *argv[])
 {
   unsigned char *uip;
   size_t sz = 128;
+  size_t keybits = 0;
+  unsigned f = 0;
   const char *file = 0;
   FILE *fp;
 
+  enum {
+    f_envNoise = 1,
+    f_keyTimer = 2
+  };
+
   /* --- Formats table --- */
 
   static struct {
@@ -456,33 +467,45 @@ int main(int argc, char *argv[])
 
   ego(argv[0]);
 
+  f |= f_envNoise | f_keyTimer;
+
   /* --- Read arguments --- */
 
   for (;;) {
     static struct option opts[] = {
-      { "help",                0,              0,      'h' },
-      { "bits",                gFlag_argReq,   0,      'b' },
-      { "output",      gFlag_argReq,   0,      'o' },
-      { "format",      gFlag_argReq,   0,      'f' },
-      { 0,             0,              0,      0 }
+      { "help",                0,                              0,      'h' },
+      { "bits",                gFlag_argReq,                   0,      'b' },
+      { "output",      gFlag_argReq,                   0,      'o' },
+      { "format",      gFlag_argReq,                   0,      'f' },
+      { "key-times",   gFlag_negate|gFlag_argOpt,      0,      'k' },
+      { "env-noise",   gFlag_negate,                   0,      'e' },
+      { 0,             0,                              0,      0 }
     };
 
-    int i = mdwopt(argc, argv, "hb:o:f:", opts, 0, 0, 0);
+    int i = mdwopt(argc, argv, "hb:o:f:k+::e+", opts, 0, 0, gFlag_negation);
 
     if (i < 0)
       break;
     switch (i) {
       case 'h':
        printf(""
-"Usage: %s [--bits=BITS] [--output=FILE] [--format=FORMAT]\n"
+"Usage: %s [-h] [-|+ek] [-b BITS] [-o FILE] [-f FORMAT]\n"
 "\n"
-"Generates BITS (by default, 128) random bits by timing keypresses.  The\n"
-"resulting number is written to FILE, or standard output in the given\n"
-"format.  Formats currently supported are:\n"
-"\n"
-"tx, hex               Hexadecimal, with punctuating dashes.\n"
-"binary                Raw binary.\n"
-"base64                Base64-encoded binary; the result is printable ASCII.\n",
+"Generates BITS (by default, 128) random bits.  The resulting number is\n"
+"written to FILE, or standard output.\n\n"
+"Randomness is taken from key-timings and environmental noise, although\n"
+"you can disable either (or both) of these sources.\n\n"
+"Options provided are:\n\n"
+"-h, --help                    Display this help text\n"
+"-b, --bits=BITS\t             Generate BITS random bits instead of 128\n"
+"-o, --output=FILE             Write bits to FILE, not standard output\n"
+"-f, --format=FORMAT           Write bits in FORMAT:\n"
+"                                tx, hex  Hexadecimal\n"
+"                                binary   Raw binary\n"
+"                                base64   Base64-encoded binary\n"
+"-e, --[no-]env-noise          Do [not] read environmental noise\n"
+"-k, --[no-]key-times[=BITS]   Do [not] read key timing information\n"
+"                                (only read BITS bits from key timings)\n",
               quis());
        exit(0);
        break;
@@ -516,29 +539,107 @@ int main(int argc, char *argv[])
        if (!fmt)
          die("unknown format name: `%s'", optarg);
        break;
+      case 'e':
+       f |= f_envNoise;
+       break;
+      case 'e' | gFlag_negated:
+       f &= ~f_envNoise;
+       break;
+      case 'k':
+       f |= f_keyTimer;
+       if (optarg) {
+         keybits = atoi(optarg);
+         if (keybits == 0)
+           die("bad number of bits (illegible or zero)");
+         if (keybits % 8)
+           die("bad number of bits (must be multiple of 8)");
+       }
+       else
+         keybits = 0;
+       break;
+      case 'k' | gFlag_negated:
+       f &= ~f_keyTimer;
+       break;
       case '?':
        exit(1);
        break;
     }
   }
 
+  /* --- Check the sanity of this request --- */
+
+  {
+    size_t bits = 0;
+
+    if (f & f_keyTimer) {
+      if (!keybits)
+       keybits = sz;
+      bits += keybits;
+    }
+    if (f & f_envNoise)
+      bits += 384; /* Estimate */
+
+    if (bits == 0)
+      die("no randomness sources given");
+    if (bits < sz)
+      moan("warning: randomness may not be sufficiently high");
+  } 
+
   if (optind < argc) {
-    fprintf(stderr, "Usage: %s [--bits=BITS] [--output=FILE]\n", quis());
+    fprintf(stderr, "Usage: %s [-opts]\n", quis());
     exit(1);
   }
 
   /* --- Allocate memory --- */
 
-  uip = xmalloc(sz / 8);
+  {
+    size_t buff = sz / 8;
+    if (f & f_keyTimer && keybits > sz)
+      buff = keybits / 8;
+    uip = xmalloc(buff);
+  }
+
+  rand_clear();
+
+  /* --- Fetch randomness from key timings --- */
+
+  if (f & f_keyTimer) {
+
+    /* --- Open the terminal --- *
+     *
+     * I'd like to be able to @fprintf@ to the terminal, so use @fopen@.
+     */
+
+    if ((kg__ttyfp = fopen("/dev/tty", "r+")) == 0)
+      die("couldn't open terminal: %s", strerror(errno));
+    kg__tty = fileno(kg__ttyfp);
 
-  /* --- Open the terminal --- *
-   *
-   * I'd like to be able to @fprintf@ to the terminal, so use @fopen@.
-   */
+    /* --- Tidy up nicely if I die --- */
 
-  if ((kg__ttyfp = fopen("/dev/tty", "r+")) == 0)
-    die("couldn't open terminal: %s", strerror(errno));
-  kg__tty = fileno(kg__ttyfp);
+    signal(SIGINT, kg__signal);
+    signal(SIGTERM, kg__signal);
+    atexit(kg__crepair);
+
+    /* --- Put the terminal into cbreak, read the key, and restore --- */
+
+    kg__cbreak();
+    kg__gen(uip, keybits);
+    kg__crepair();
+    rand_add(uip, keybits / 8);
+    rand_churn();
+  }
+
+  /* --- Find some noise from the environment too --- */
+
+  if (f & f_envNoise) {
+    noise_acquire();
+    rand_churn();
+  }
+
+  /* --- Now write the number and exit --- */
+
+  rand_extract(uip, sz / 8);
+  D( fputs("*** ", fp); tx_putBits(uip, sz, stdout); )
 
   /* --- Open the output file, if one is specified --- */
 
@@ -550,8 +651,8 @@ int main(int argc, char *argv[])
      * There's a good reason for this.  I want to be able to @fprintf@ (for
      * the benefit of @tx_putWords@ mainly) but I also want to ensure that
      * only the user has read permissions for the file.  So I'll use @open@
-     * with an appropriate mode and then @fdopen@ the file descriptor to get
-     * a stream.  Yuk.
+     * with an appropriate mode and then @fdopen@ the file descriptor to
+     * get a stream.  Yuk.
      */
 
     if ((fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
@@ -561,29 +662,6 @@ int main(int argc, char *argv[])
   } else
     fp = stdout;
 
-  /* --- Tidy up nicely if I die --- */
-
-  signal(SIGINT, kg__signal);
-  signal(SIGTERM, kg__signal);
-  atexit(kg__crepair);
-
-  /* --- Put the terminal into cbreak, read the key, and restore --- */
-
-  kg__cbreak();
-  kg__gen(uip, sz);
-  kg__crepair();
-
-  /* --- Find some noise from the environment too --- */
-
-  rand_clear();
-  noise_acquire();
-  rand_add(uip, sz / 8);
-  rand_churn();
-  rand_extract(uip, sz / 8);
-
-  /* --- Now write the number and exit --- */
-
-  D( fputs("*** ", fp); tx_putBits(uip, sz, stdout); )
   fmt(uip, sz, fp);
   if (file)
     fclose(fp);