Overhaul of key management (again).
[u/mdw/catacomb] / keyutil.c
index b6b1bf9..673f4ea 100644 (file)
--- a/keyutil.c
+++ b/keyutil.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: keyutil.c,v 1.4 1999/12/22 15:48:10 mdw Exp $
+ * $Id: keyutil.c,v 1.5 2000/02/12 18:21:03 mdw Exp $
  *
  * Simple key manager program
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: keyutil.c,v $
+ * Revision 1.5  2000/02/12 18:21:03  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.4  1999/12/22 15:48:10  mdw
  * Track new key-management changes.  Support new key generation
  * algorithms.
@@ -66,6 +69,7 @@
 #include <rand.h>
 
 #include "bbs.h"
+#include "dh.h"
 #include "dsa.h"
 #include "fibrand.h"
 #include "getdate.h"
@@ -97,7 +101,7 @@ static const char *keyfile = "keyring";
 static void doopen(key_file *f, unsigned how)
 {
   if (key_open(f, keyfile, how, key_moan, 0))
-    die(1, "couldn't open file `%s': %s", keyfile, strerror(errno));
+    die(1, "couldn't open keyring `%s': %s", keyfile, strerror(errno));
 }
 
 /* --- @doclose@ --- *
@@ -268,6 +272,58 @@ static mp *getmp(key_data *k, const char *tag)
   return (k->u.m);
 }
 
+/* --- @keyrand@ --- *
+ *
+ * Arguments:  @key_file *kf@ = pointer to key file
+ *             @const char *id@ = pointer to key id (or null)
+ *
+ * Returns:    ---
+ *
+ * Use:                Keys the random number generator.
+ */
+
+static void keyrand(key_file *kf, const char *id)
+{
+  key *k;
+
+  /* --- Find the key --- */
+
+  if (id) {
+    if ((k = key_bytag(kf, id)) == 0)
+      die(EXIT_FAILURE, "key `%s' not found", id);
+  } else
+    k = key_bytype(kf, "catacomb-rand");
+
+  if (k) {
+    key_data *kd = &k->k, kkd;
+
+  again:
+    switch (kd->e & KF_ENCMASK) {
+      case KENC_BINARY:
+       break;
+      case KENC_ENCRYPT: {
+       dstr d = DSTR_INIT;
+       key_fulltag(k, &d);
+       if (key_punlock(d.buf, kd, &kkd))
+         die(EXIT_FAILURE, "error unlocking key `%s'", d.buf);
+       dstr_destroy(&d);
+       kd = &kkd;
+      } goto again;
+      default: {
+       dstr d = DSTR_INIT;
+       key_fulltag(k, &d);
+       die(EXIT_FAILURE, "bad encoding type for key `%s'", d.buf);
+      } break;
+    }
+
+    /* --- Key the generator --- */
+
+    rand_key(RAND_GLOBAL, kd->u.k.k, kd->u.k.sz);
+    if (kd == &kkd)
+      key_destroy(&kkd);
+  }
+}
+
 /* --- Key generation algorithms --- */
 
 static void alg_binary(keyopts *k)
@@ -310,10 +366,10 @@ static void alg_des(keyopts *k)
   p = sub_alloc(sz);
   rand_getgood(RAND_GLOBAL, p, sz);    /* Too much work done here! */
   for (i = 0; i < sz; i++) {
-    octet x = p[i] & 0xfe;
+    octet x = p[i] | 0x01;
     x = x ^ (x >> 4);
     x = x ^ (x >> 2);
-    x = x ^ (x >> 1) ^ 1;
+    x = x ^ (x >> 1);
     p[i] = (p[i] & 0xfe) | (x & 0x01);
   }
   key_binary(&k->k->k, p, sz);
@@ -471,14 +527,15 @@ static void alg_dsa(keyopts *k)
   key_structure(kd);
   mpkey(kd, "x", x, KCAT_PRIV | KF_BURN);
   dolock(k, kd, "private");
+
+  mp_drop(x); mp_drop(y);
 }
 
 static void alg_dhparam(keyopts *k)
 {
-  static const char *pl[] = { "p", "g", 0 };
+  static const char *pl[] = { "p", "q", "g", 0 };
   if (!copyparam(k, pl)) {
-    pgen_safetestctx c;
-    mp *p, *q;
+    dh_param dp;
     key_data *kd = &k->k->k;
 
     if (!k->bits)
@@ -486,35 +543,24 @@ static void alg_dhparam(keyopts *k)
 
     /* --- Choose a large safe prime number --- */
 
-    q = MP_NEW;
-    q = mprand(q, k->bits, &rand_global, 3);
-    p = pgen("p", MP_NEW, q, (k->f & f_quiet) ? 0 : pgen_ev, 0,
-            0, pgen_safestep, &c.c,
-            rabin_iters(k->bits), pgen_safetest, &c);
-    if (!p)
+    if (dh_gen(&dp, k->qbits, k->bits, 0, &rand_global,
+              (k->f & f_quiet) ? 0 : pgen_ev, 0))
       die(EXIT_FAILURE, "Diffie-Hellman parameter generation failed");
 
     key_structure(kd);
-    mpkey(kd, "p", p, KCAT_SHARE);
-    mp_drop(q);
-    mp_drop(p);
-
-    /* --- The generator 4 is good --- *
-     *
-     * Since 4 is clearly a quadratic residue, and %$p = 2q + 1$% for prime
-     * %$q$%, the number 4 has order %$q$%.  This is better than choosing a
-     * real primitive element, because it could conceivably be trapped in an
-     * order-2 subgroup.  (Not very likely, I'll admit, but possible.)
-     */
-
-    mpkey(kd, "g", MP_FOUR, KCAT_SHARE);
+    mpkey(kd, "p", dp.p, KCAT_SHARE);
+    mpkey(kd, "q", dp.q, KCAT_SHARE);
+    mpkey(kd, "g", dp.g, KCAT_SHARE);
+    mp_drop(dp.q);
+    mp_drop(dp.p);
+    mp_drop(dp.g);
   }    
 }
 
 static void alg_dh(keyopts *k)
 {
   mp *x, *y;
-  mp *p, *g;
+  mp *p, *q, *g;
   mpmont mm;
   key_data *kd = &k->k->k;
 
@@ -522,6 +568,7 @@ static void alg_dh(keyopts *k)
 
   alg_dhparam(k);
   p = getmp(kd, "p");
+  q = getmp(kd, "q");
   g = getmp(kd, "g");
 
   /* --- Choose a suitable private key --- *
@@ -529,14 +576,13 @@ static void alg_dh(keyopts *k)
    * Since %$g$% has order %$q$%, choose %$x < q$%.
    */
 
-  y = mp_lsr(MP_NEW, p, 1);
-  x = mprand_range(MP_NEW, y, &rand_global, 0);
+  x = mprand_range(MP_NEW, q, &rand_global, 0);
   mp_burn(x);
 
   /* --- Compute the public key %$y = g^x \bmod p$% --- */
 
   mpmont_create(&mm, p);
-  y = mpmont_exp(&mm, y, g, x);
+  y = mpmont_exp(&mm, MP_NEW, g, x);
   mpmont_destroy(&mm);
 
   /* --- Store everything away --- */
@@ -547,13 +593,14 @@ static void alg_dh(keyopts *k)
   key_structure(kd);
   mpkey(kd, "x", x, KCAT_PRIV | KF_BURN);
   dolock(k, kd, "private");
+
+  mp_drop(x); mp_drop(y);
 }
 
 static void alg_bbs(keyopts *k)
 {
   bbs_param bp;
   key_data *kd;
-  mp *p, *q;
 
   /* --- Sanity checking --- */
 
@@ -564,12 +611,9 @@ static void alg_bbs(keyopts *k)
 
   /* --- Generate the BBS parameters --- */
 
-  p = mprand(MP_NEW, k->bits / 2, &rand_global, 3);
-  q = mprand(MP_NEW, k->bits - k->bits / 2, &rand_global, 3);
-  mp_burn(p); mp_burn(q);
-  if (bbs_gen(&bp, p, q, 0, (k->f & f_quiet) ? 0 : pgen_ev, 0))
+  if (bbs_gen(&bp, k->bits, &rand_global, 0,
+             (k->f & f_quiet) ? 0 : pgen_ev, 0))
     die(EXIT_FAILURE, "Blum-Blum-Shub key generation failed");
-  mp_drop(p); mp_drop(q);
 
   /* --- Allrighty then --- */
 
@@ -615,6 +659,7 @@ static int cmd_add(int argc, char *argv[])
   const char *tag = 0, *ptag = 0;
   const char *c = 0;
   keyalg *alg = algtab;
+  const char *rtag = 0;
   keyopts k = { 0, 0, DSTR_INIT, 0, 0, 0, 0 };
 
   /* --- Parse options for the subcommand --- */
@@ -628,11 +673,12 @@ static int cmd_add(int argc, char *argv[])
       { "expire",      OPTF_ARGREQ,    0,      'e' },
       { "comment",     OPTF_ARGREQ,    0,      'c' },
       { "tag",         OPTF_ARGREQ,    0,      't' },
+      { "rand-id",     OPTF_ARGREQ,    0,      'r' },
       { "lock",                0,              0,      'l' },
       { "quiet",       0,              0,      'q' },
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:l", opt, 0, 0, 0);
+    int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:r:lq", opt, 0, 0, 0);
     if (i < 0)
       break;
 
@@ -720,6 +766,9 @@ static int cmd_add(int argc, char *argv[])
 
       /* --- Other flags --- */
 
+      case 'r':
+       rtag = optarg;
+       break;
       case 'l':
        k.f |= f_lock;
        break;
@@ -757,6 +806,10 @@ static int cmd_add(int argc, char *argv[])
   doopen(&f, KOPEN_WRITE);
   k.kf = &f;
 
+  /* --- Key the generator --- */
+
+  keyrand(&f, rtag);
+
   for (;;) {
     uint32 id = rand_global.ops->word(&rand_global);
     int err;
@@ -1192,26 +1245,6 @@ static int cmd_setattr(int argc, char *argv[])
 
 /* --- @cmd_finger@ --- */
 
-static int fpkey(key_data *kd, dstr *d, void *p)
-{
-  rmd160_ctx *r = p;
-  switch (kd->e & KF_ENCMASK) {
-    case KENC_BINARY:
-    case KENC_ENCRYPT:
-      rmd160_hash(r, kd->u.k.k, kd->u.k.sz);
-      break;
-    case KENC_MP: {
-      size_t sz = mp_octets(kd->u.m);
-      octet *q = sub_alloc(sz);
-      mp_storeb(kd->u.m, q, sz);
-      rmd160_hash(r, q, sz);
-      memset(q, 0, sz);
-      sub_free(q, sz);
-    } break;
-  }
-  return (0);
-}
-
 static void fingerprint(key *k, const key_filter *kf)
 {
   rmd160_ctx r;
@@ -1219,12 +1252,13 @@ static void fingerprint(key *k, const key_filter *kf)
   dstr d = DSTR_INIT;
   int i;
 
-  if (!key_match(&k->k, kf))
+  if (!key_encode(&k->k, &d, kf))
     return;
   rmd160_init(&r);
-  key_do(&k->k, kf, 0, fpkey, &r);
+  rmd160_hash(&r, d.buf, d.len);
   rmd160_done(&r, hash);
-  
+
+  DRESET(&d);
   key_fulltag(k, &d);
   for (i = 0; i < sizeof(hash); i++) {
     if (i && i % 4 == 0)
@@ -1480,7 +1514,7 @@ static struct cmd {
 } cmds[] = {
   { "add", cmd_add,
     "add [options] type [attr...]\n\
-       Options: [-l] [-a alg] [-b bits] [-p param]\n\
+       Options: [-lq] [-a alg] [-b|-B bits] [-p param] [-r tag]\n\
                 [-e expire] [-t tag] [-c comment]"
   },
   { "expire", cmd_expire, "expire tag..." },
@@ -1493,7 +1527,7 @@ static struct cmd {
   { "list", cmd_list, "list [-uqv] [-f filter] [tag...]" },
   { "fingerprint", cmd_finger, "fingerprint [-f filter] [tag...]" },
   { "tidy", cmd_tidy, "tidy" },
-  { "extract", cmd_extract, "extract file qtag..." },
+  { "extract", cmd_extract, "extract [-f filter] file [tag...]" },
   { "merge", cmd_merge, "merge file" },
   { 0, 0, 0 }
 };
@@ -1506,12 +1540,12 @@ typedef struct cmd cmd;
 
 void usage(FILE *fp)
 {
-  fprintf(fp, "Usage: %s [-k file] command [args]\n", QUIS);
+  pquis(fp, "Usage: $ [-k file] [-i tag] [-t type] command [args]\n");
 }
 
 void version(FILE *fp)
 {
-  fprintf(fp, "%s, Catacomb version " VERSION "\n", QUIS);
+  pquis(fp, "$, Catacomb version " VERSION "\n");
 }
 
 void help(FILE *fp)
@@ -1529,6 +1563,8 @@ recognized are:\n\
 -u, --usage            Display short usage summary.\n\
 \n\
 -k, --keyring=FILE     Read and write keys in FILE.\n\
+-i, --id=TAG           Use key TAG for random number generator.\n\
+-t, --type=TYPE                Use key TYPE for random number generator.\n\
 \n\
 The following commands are understood:\n\n",
        fp);
@@ -1559,11 +1595,6 @@ int main(int argc, char *argv[])
   ego(argv[0]);
   sub_init();
 
-  /* --- Initialize the Catacomb random number generator --- */
-
-  rand_init(RAND_GLOBAL);
-  rand_noisesrc(RAND_GLOBAL, &noise_source);
-
   /* --- Parse command line options --- */
 
   for (;;) {
@@ -1578,12 +1609,14 @@ int main(int argc, char *argv[])
       /* --- Real live useful options --- */
 
       { "keyring",     OPTF_ARGREQ,    0,      'k' },
+      { "id",          OPTF_ARGREQ,    0,      'i' },
+      { "type",                OPTF_ARGREQ,    0,      't' },
 
       /* --- Magic terminator --- */
 
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "+hvu k:", opt, 0, 0, 0);
+    int i = mdwopt(argc, argv, "+hvu k:i:t:", opt, 0, 0, 0);
 
     if (i < 0)
       break;
@@ -1621,6 +1654,11 @@ int main(int argc, char *argv[])
     exit(1);
   }
 
+  /* --- Initialize the Catacomb random number generator --- */
+
+  rand_init(RAND_GLOBAL);
+  rand_noisesrc(RAND_GLOBAL, &noise_source);
+
   /* --- Dispatch to appropriate command handler --- */
 
   argc -= optind;