/* -*-c-*-
*
- * $Id: keygen.c,v 1.2 1997/08/04 10:24:23 mdw Exp $
+ * $Id: keygen.c,v 1.5 1998/01/12 16:46:05 mdw Exp $
*
* Key generation
*
- * (c) 1997 EBI
+ * (c) 1998 EBI
*/
/*----- Licensing notice --------------------------------------------------*
/*----- Revision history --------------------------------------------------*
*
* $Log: keygen.c,v $
+ * Revision 1.5 1998/01/12 16:46:05 mdw
+ * Fix copyright date.
+ *
+ * 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.
+ *
* Revision 1.2 1997/08/04 10:24:23 mdw
* Sources placed under CVS control.
*
/* --- Local headers --- */
#include "config.h"
-#include "tx.h"
#include "mdwopt.h"
+#include "noise.h"
+#include "rand.h"
+#include "tx.h"
#include "utils.h"
/*----- Static variables --------------------------------------------------*/
{
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 {
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"
-"\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"
+"Usage: %s [-h] [-|+ek] [-b BITS] [-o FILE] [-f FORMAT]\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;
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();
- /* --- Open the terminal --- *
- *
- * I'd like to be able to @fprintf@ to the terminal, so use @fopen@.
- */
+ /* --- Fetch randomness from key timings --- */
- if ((kg__ttyfp = fopen("/dev/tty", "r+")) == 0)
- die("couldn't open terminal: %s", strerror(errno));
- kg__tty = fileno(kg__ttyfp);
+ 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);
+
+ /* --- 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, 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 --- */
* 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)
} 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();
-
- /* --- Now write the number and exit --- */
-
- D( fputs("*** ", fp); tx_putBits(uip, sz, stdout); )
fmt(uip, sz, fp);
if (file)
fclose(fp);
memset(uip, 0, sz / 8); /* Burn temporary buffer */
+ rand_clear();
return (0);
}