Overhaul of key management (again).
authormdw <mdw>
Sat, 12 Feb 2000 18:21:23 +0000 (18:21 +0000)
committermdw <mdw>
Sat, 12 Feb 2000 18:21:23 +0000 (18:21 +0000)
24 files changed:
Makefile.m4
bbs-gen.c
bbs.h
dh-gen.c [new file with mode: 0644]
dh-prime.c [deleted file]
dh.h
dsa-gen.c
key-attr.c
key-binary.c [new file with mode: 0644]
key-data.c
key-data.h [new file with mode: 0644]
key-error.c [new file with mode: 0644]
key-flags.c
key-io.c
key-misc.c
key-text.c [new file with mode: 0644]
key.1
key.h
keyutil.c
pgen-safe.c
pgen.h
rspit.c
strongprime.c
strongprime.h

index 536007d..302e2f4 100644 (file)
@@ -1,6 +1,6 @@
 ## -*-makefile-*-
 ##
 ## -*-makefile-*-
 ##
-## $Id: Makefile.m4,v 1.22 1999/12/22 16:04:06 mdw Exp $
+## $Id: Makefile.m4,v 1.23 2000/02/12 18:21:01 mdw Exp $
 ##
 ## Makefile for Catacomb
 ##
 ##
 ## Makefile for Catacomb
 ##
@@ -29,6 +29,9 @@
 ##----- Revision history ----------------------------------------------------
 ##
 ## $Log: Makefile.m4,v $
 ##----- Revision history ----------------------------------------------------
 ##
 ## $Log: Makefile.m4,v $
+## Revision 1.23  2000/02/12 18:21:01  mdw
+## Overhaul of key management (again).
+##
 ## Revision 1.22  1999/12/22 16:04:06  mdw
 ## Lots of new files.
 ##
 ## Revision 1.22  1999/12/22 16:04:06  mdw
 ## Lots of new files.
 ##
@@ -174,7 +177,7 @@ pkginclude_HEADERS = \
        mprand.h \
        primetab.h pfilt.h primorial.h rabin.h \
        pgen.h prim.h strongprime.h \
        mprand.h \
        primetab.h pfilt.h primorial.h rabin.h \
        pgen.h prim.h strongprime.h \
-       bbs.h rsa.h dsarand.h dsa.h \
+       bbs.h rsa.h dh.h dsarand.h dsa.h \
        allwithsuffix(`ciphers', `cipher_modes', `.h') \
        allwithsuffix(`hashes', `hash_modes', `.h') \
        addsuffix(`cipher_modes', `-def.h') \
        allwithsuffix(`ciphers', `cipher_modes', `.h') \
        allwithsuffix(`hashes', `hash_modes', `.h') \
        addsuffix(`cipher_modes', `-def.h') \
@@ -186,8 +189,8 @@ libcatacomb_la_SOURCES = \
        des-base.c des-base.h des_sp.h bf_ikey.h daftstory.h \
        rc4.c \
        rand.c noise.c \
        des-base.c des-base.h des_sp.h bf_ikey.h daftstory.h \
        rc4.c \
        rand.c noise.c \
-       key-misc.c key-file.c key-data.c key-attr.c key-flags.c \
-               key-io.c key-pass.c key-moan.c \
+       key-data.c key-flags.c key-text.c key-binary.c key-pass.c \
+       key-misc.c key-file.c key-attr.c key-io.c key-moan.c key-error.c \
        passphrase.c pixie-client.c pixie-common.c lmem.c \
        lcrand.c fibrand.c \
        mpx.c mpx-kmul.c mpx-ksqr.c mpscan.c mparena.c \
        passphrase.c pixie-client.c pixie-common.c lmem.c \
        lcrand.c fibrand.c \
        mpx.c mpx-kmul.c mpx-ksqr.c mpscan.c mparena.c \
@@ -202,6 +205,7 @@ libcatacomb_la_SOURCES = \
        pgen.c pgen-stdev.c pgen-safe.c prim.c strongprime.c \
        bbs-rand.c bbs-gen.c bbs-jump.c \
        rsa-decrypt.c rsa-gen.c rsa-recover.c \
        pgen.c pgen-stdev.c pgen-safe.c prim.c strongprime.c \
        bbs-rand.c bbs-gen.c bbs-jump.c \
        rsa-decrypt.c rsa-gen.c rsa-recover.c \
+       dh-gen.c \
        dsarand.c dsa-sign.c dsa-verify.c dsa-gen.c \
        addsuffix(join(`ciphers', `-', `cipher_modes'), `.c') \
        addsuffix(join(`hashes', `-', `hash_modes'), `.c') \
        dsarand.c dsa-sign.c dsa-verify.c dsa-gen.c \
        addsuffix(join(`ciphers', `-', `cipher_modes'), `.c') \
        addsuffix(join(`hashes', `-', `hash_modes'), `.c') \
@@ -212,7 +216,7 @@ mpx.lo: mptypes.h
 
 ## --- Utility programs ---
 
 
 ## --- Utility programs ---
 
-bin_PROGRAMS = key pixie rspit
+bin_PROGRAMS = key pixie rspit distsig
 bin_SCRIPTS = catacomb-config xpixie
 noinst_PROGRAMS = des-mktab genprimes mptypes
 LDADD = libcatacomb.la
 bin_SCRIPTS = catacomb-config xpixie
 noinst_PROGRAMS = des-mktab genprimes mptypes
 LDADD = libcatacomb.la
@@ -224,6 +228,8 @@ pixie_LDADD =
 
 rspit_SOURCES = rspit.c
 
 
 rspit_SOURCES = rspit.c
 
+distsig_SOURCES = distsig.c
+
 des_mktab_SOURCES = des-mktab.c
 des_mktab_LDADD =
 
 des_mktab_SOURCES = des-mktab.c
 des_mktab_LDADD =
 
index 8780274..43b6990 100644 (file)
--- a/bbs-gen.c
+++ b/bbs-gen.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: bbs-gen.c,v 1.2 1999/12/22 15:52:28 mdw Exp $
+ * $Id: bbs-gen.c,v 1.3 2000/02/12 18:21:02 mdw Exp $
  *
  * Generate Blum integers
  *
  *
  * Generate Blum integers
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: bbs-gen.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: bbs-gen.c,v $
+ * Revision 1.3  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.2  1999/12/22 15:52:28  mdw
  * Reworking for new prime-search system.
  *
  * Revision 1.2  1999/12/22 15:52:28  mdw
  * Reworking for new prime-search system.
  *
 #include "mp.h"
 #include "mprand.h"
 #include "pgen.h"
 #include "mp.h"
 #include "mprand.h"
 #include "pgen.h"
+#include "strongprime.h"
 
 /*----- Data structures ---------------------------------------------------*/
 
 typedef struct gcdctx {
 
 /*----- Data structures ---------------------------------------------------*/
 
 typedef struct gcdctx {
-  mp *q;
+  mp *q, *jq;
+  pfilt p, jp;
   mp *r;
   mp *r;
-  pfilt p;
 } gcdctx;
 
 /*----- Custom stepper ----------------------------------------------------*/
 } gcdctx;
 
 /*----- Custom stepper ----------------------------------------------------*/
@@ -66,21 +70,40 @@ static int gcdstep(int rq, pgen_event *ev, void *p)
   mp *z = MP_NEW;
 
   switch (rq) {
   mp *z = MP_NEW;
 
   switch (rq) {
+
+    /* --- Set everything up --- */
+
     case PGEN_BEGIN: {
     case PGEN_BEGIN: {
-      mp *p = ev->m = mp_split(ev->m);
-      p->v[0] |= 3;
-      g->q = mp_lsr(MP_NEW, p, 1);
+      mp *p = ev->m;
+      if ((p->v[0] & 3) != 3)
+       p = mp_add(p, p, g->jp.m);
       rc = pfilt_create(&g->p, p);
       rc = pfilt_create(&g->p, p);
+      g->q = mp_lsr(MP_NEW, p, 1);
+      g->jq = MP_COPY(g->jp.m);
+      pfilt_muladd(&g->jp, &g->jp, 2, 0);
+      g->jq = mp_lsr(MP_NEW, p, 1);
+      mp_drop(p);
     } break;
     } break;
+
+    /* --- Grind through another iteration --- */
+
     case PGEN_TRY:
     case PGEN_TRY:
-      g->q = mp_add(g->q, g->q, MP_FOUR);
-      rc = pfilt_step(&g->p, 4);
+      mp_drop(ev->m);
+      rc = pfilt_jump(&g->p, &g->jp);
+      g->q = mp_add(g->q, g->q, g->jq);
       break;
       break;
+
+    /* --- Finished --- */
+
     case PGEN_DONE:
       pfilt_destroy(&g->p);
       mp_drop(g->q);
     case PGEN_DONE:
       pfilt_destroy(&g->p);
       mp_drop(g->q);
+      mp_drop(g->jq);
       return (PGEN_DONE);
   }
       return (PGEN_DONE);
   }
+
+  /* --- Step on until everything is OK --- */
+
   for (;;) {
     if (rc != PGEN_FAIL) {
       mp_gcd(&z, 0, 0, g->r, g->q);
   for (;;) {
     if (rc != PGEN_FAIL) {
       mp_gcd(&z, 0, 0, g->r, g->q);
@@ -89,12 +112,11 @@ static int gcdstep(int rq, pgen_event *ev, void *p)
     }
     if (rc != PGEN_FAIL)
       break;
     }
     if (rc != PGEN_FAIL)
       break;
-    g->q = mp_add(g->q, g->q, MP_FOUR);
-    rc = pfilt_step(&g->p, 4);
+    rc = pfilt_jump(&g->p, &g->jp);
+    g->q = mp_add(g->q, g->q, g->jq);
   }
 
   mp_drop(z);
   }
 
   mp_drop(z);
-  mp_drop(ev->m);
   ev->m = MP_COPY(g->p.m);
   return (rc);
 }
   ev->m = MP_COPY(g->p.m);
   return (rc);
 }
@@ -104,8 +126,9 @@ static int gcdstep(int rq, pgen_event *ev, void *p)
 /* --- @bbs_gen@ --- *
  *
  * Arguments:  @bbs_param *bp@ = pointer to parameter block
 /* --- @bbs_gen@ --- *
  *
  * Arguments:  @bbs_param *bp@ = pointer to parameter block
- *             @mp *p, *q@ = initial numbers to search from
- *             @size_t n@ = number of attempts to make
+ *             @unsigned nbits@ = number of bits in the modulus
+ *             @grand *r@ = pointer to random number source
+ *             @unsigned n@ = number of attempts to make
  *             @pgen_proc *event@ = event handler function
  *             @void *ectx@ = argument for event handler
  *
  *             @pgen_proc *event@ = event handler function
  *             @void *ectx@ = argument for event handler
  *
@@ -118,38 +141,51 @@ static int gcdstep(int rq, pgen_event *ev, void *p)
  *             Shub pseudorandom bit generator.
  */
 
  *             Shub pseudorandom bit generator.
  */
 
-int bbs_gen(bbs_param *bp, mp *p, mp *q, size_t n,
+int bbs_gen(bbs_param *bp, unsigned nbits, grand *r, unsigned n,
            pgen_proc *event, void *ectx)
 {
            pgen_proc *event, void *ectx)
 {
-  rabin r;
-  pgen_safestepctx c;
+  rabin rb;
+  pgen_safejumpctx j;
   gcdctx g;
   gcdctx g;
+  unsigned nb = nbits/2;
+  mp *x = MP_NEW;
 
   /* --- Generate @p@ --- */
 
 
   /* --- Generate @p@ --- */
 
-  if ((bp->p = pgen("p", MP_NEW, p, event, ectx, n, pgen_safestep, &c,
-                   rabin_iters(mp_bits(p)), pgen_test, &r)) == 0)
+  if ((x = strongprime_setup("p", x, &j.jq, nb, r, n, event, ectx)) == 0)
+    goto fail_x;
+  bp->p = pgen("p", MP_NEW, x, event, ectx, n, pgen_safejump, &j,
+              rabin_iters(nb), pgen_test, &rb);
+  pfilt_destroy(&j.jq);
+  if (!bp->p)
     goto fail_p;
 
   /* --- Generate @q@ --- */
 
     goto fail_p;
 
   /* --- Generate @q@ --- */
 
+  nb = nbits - nb;
+  if ((x = strongprime_setup("q", x, &g.jp, nb, r, n, event, ectx)) == 0)
+    goto fail_q;
   g.r = mp_lsr(MP_NEW, bp->p, 1);
   g.r = mp_lsr(MP_NEW, bp->p, 1);
-  if ((bp->q = pgen("q", MP_NEW, q, event, ectx, n, gcdstep, &g,
-                   rabin_iters(mp_bits(q)), pgen_test, &r)) == 0)
+  bp->q = pgen("q", MP_NEW, x, event, ectx, n, gcdstep, &g,
+              rabin_iters(nb), pgen_test, &rb);
+  pfilt_destroy(&g.jp);
+  mp_drop(g.r);
+  if (!bp->q)
     goto fail_q;
 
   /* --- Compute @n@ --- */
 
   bp->n = mp_mul(MP_NEW, bp->p, bp->q);
     goto fail_q;
 
   /* --- Compute @n@ --- */
 
   bp->n = mp_mul(MP_NEW, bp->p, bp->q);
-  mp_drop(g.r);
+  mp_drop(x);
   return (PGEN_DONE);
 
   /* --- Tidy up if things went wrong --- */
 
 fail_q:
   return (PGEN_DONE);
 
   /* --- Tidy up if things went wrong --- */
 
 fail_q:
-  mp_drop(g.r);
   mp_drop(bp->p);
 fail_p:
   mp_drop(bp->p);
 fail_p:
+  mp_drop(x);
+fail_x:
   return (PGEN_ABORT);
 }
 
   return (PGEN_ABORT);
 }
 
diff --git a/bbs.h b/bbs.h
index 485fb76..6e23d02 100644 (file)
--- a/bbs.h
+++ b/bbs.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: bbs.h,v 1.2 1999/12/22 15:52:08 mdw Exp $
+ * $Id: bbs.h,v 1.3 2000/02/12 18:21:02 mdw Exp $
  *
  * The Blum-Blum-Shub random bit generator
  *
  *
  * The Blum-Blum-Shub random bit generator
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: bbs.h,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: bbs.h,v $
+ * Revision 1.3  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.2  1999/12/22 15:52:08  mdw
  * Rename `bbs_params' to `bbs_param' for consistency.
  *
  * Revision 1.2  1999/12/22 15:52:08  mdw
  * Rename `bbs_params' to `bbs_param' for consistency.
  *
@@ -231,8 +234,9 @@ extern void bbs_rew(bbs */*b*/, bbs_param */*bp*/, unsigned long /*n*/);
 /* --- @bbs_gen@ --- *
  *
  * Arguments:  @bbs_param *bp@ = pointer to parameter block
 /* --- @bbs_gen@ --- *
  *
  * Arguments:  @bbs_param *bp@ = pointer to parameter block
- *             @mp *p, *q@ = initial numbers to search from
- *             @size_t n@ = number of attempts to make
+ *             @unsigned nbits@ = number of bits in the modulus
+ *             @grand *r@ = pointer to random number source
+ *             @unsigned n@ = number of attempts to make
  *             @pgen_proc *event@ = event handler function
  *             @void *ectx@ = argument for event handler
  *
  *             @pgen_proc *event@ = event handler function
  *             @void *ectx@ = argument for event handler
  *
@@ -245,8 +249,8 @@ extern void bbs_rew(bbs */*b*/, bbs_param */*bp*/, unsigned long /*n*/);
  *             Shub pseudorandom bit generator.
  */
 
  *             Shub pseudorandom bit generator.
  */
 
-extern int bbs_gen(bbs_param */*bp*/, mp */*p*/, mp */*q*/, size_t /*n*/,
-                  pgen_proc */*event*/, void */*ectx*/);
+extern int bbs_gen(bbs_param */*bp*/, unsigned /*nbits*/, grand */*r*/,
+                  unsigned /*n*/, pgen_proc */*event*/, void */*ectx*/);
 
 /*----- Generic random number generator interface -------------------------*/
 
 
 /*----- Generic random number generator interface -------------------------*/
 
diff --git a/dh-gen.c b/dh-gen.c
new file mode 100644 (file)
index 0000000..e909989
--- /dev/null
+++ b/dh-gen.c
@@ -0,0 +1,162 @@
+/* -*-c-*-
+ *
+ * $Id: dh-gen.c,v 1.1 2000/02/12 18:21:02 mdw Exp $
+ *
+ * Generate Diffie-Hellman parameters
+ *
+ * (c) 1999 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.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: dh-gen.c,v $
+ * Revision 1.1  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "dh.h"
+#include "grand.h"
+#include "mp.h"
+#include "mpmont.h"
+#include "mprand.h"
+#include "pfilt.h"
+#include "pgen.h"
+#include "prim.h"
+#include "rabin.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @dh_gen@ --- *
+ *
+ * Arguments:  @dh_param *dp@ = pointer to output parameter block
+ *             @unsigned ql@ = length of %$q$% in bits, or zero
+ *             @unsigned pl@ = length of %$p$% in bits
+ *             @unsigned steps@ = number of steps to go
+ *             @grand *r@ = random number source
+ *             @pgen_proc *event@ = event handler function
+ *             @void *ectx@ = argument for the event handler
+ *
+ * Returns:    @PGEN_DONE@ if it worked, @PGEN_ABORT@ if it didn't.
+ *
+ * Use:                Generates Diffie-Hellman parameters.
+ *
+ *             The parameters are a prime %$q$%, relatively small, and a
+ *             large prime %$p = kq + 1$% for some %$k$%, together with a
+ *             generator %$g$% of the cyclic subgroup of order %$q$%.  These
+ *             are actually the same as the DSA parameter set, but the
+ *             generation algorithm is different.  Also, if @ql@ is zero,
+ *             this algorithm forces %$k = 2$%, and chooses %$g = 4$%.  Make
+ *             sure you have something interesting to do if you choose this
+ *             option.
+ */
+
+int dh_gen(dh_param *dp, unsigned ql, unsigned pl, unsigned steps, grand *r,
+          pgen_proc *event, void *ectx)
+{
+  /* --- If @ql@ is zero, do the time consuming safe-prime thing --- */
+
+  if (!ql) {
+    pgen_safetestctx c;
+
+    mp *m = mprand(MP_NEW, pl, r, 3);
+    dp->p = pgen("p", MP_NEW, m, event, ectx, steps, pgen_safestep, &c.c,
+                rabin_iters(pl), pgen_safetest, &c);
+    mp_drop(m);
+    if (!dp->p)
+      return (PGEN_ABORT);
+    dp->q = mp_lsr(MP_NEW, dp->p, 1);
+    dp->g = MP_FOUR;
+    return (PGEN_DONE);
+  }
+
+  /* --- Otherwise the job is much simpler --- *
+   *
+   * But doesn't look it...
+   */
+
+  else {
+    pgen_filterctx c;
+    pgen_jumpctx j;
+    rabin rb;
+    prim_ctx p;
+    int i;
+    mp *m = MP_NEW;
+    mp *x, *y;
+
+    /* --- Generate @q@ first --- */
+
+    c.step = 2;
+    m = mprand(MP_NEW, ql, r, 1);
+    dp->q = pgen("q", MP_NEW, m, event, ectx, steps, pgen_filter, &c,
+                rabin_iters(ql), pgen_test, &rb);
+    if (!dp->q)
+      goto fail_q;
+
+    /* --- Now pick a suitable @p@ --- */
+
+    m = mp_lsl(m, dp->q, 1);
+    x = mprand(MP_NEW, pl, r, 0);
+    y = MP_NEW; mp_div(0, &y, x, m);
+    x = mp_sub(x, x, y);
+    x = mp_add(x, x, MP_ONE);
+    mp_drop(y);
+    pfilt_create(&c.f, m);
+    j.j = &c.f;
+    dp->p = pgen("p", MP_NEW, x, event, ectx, steps, pgen_jump, &j,
+                rabin_iters(pl), pgen_test, &rb);
+    pfilt_destroy(&c.f);
+    mp_drop(x);
+    if (!dp->p)
+      goto fail_p;
+
+    /* --- And finally a suitable @g@ --- */
+
+    mpmont_create(&p.mm, dp->p);
+    mp_div(&m, 0, dp->p, dp->q);
+    i = 0;
+    p.f = m;
+    p.n = 0;
+    dp->g = pgen("g", MP_NEW, MP_NEW, event, ectx, 0, prim_step, &i,
+                1, prim_test, &p);
+    mpmont_destroy(&p.mm);
+    if (!dp->g)
+      goto fail_g;
+    mp_drop(m);
+    return (PGEN_DONE);
+
+    /* --- Tidy up --- */
+
+  fail_g:
+    mp_drop(dp->q);
+  fail_q:
+    mp_drop(dp->p);
+  fail_p:
+    mp_drop(m);
+    return (PGEN_ABORT);
+  }
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/dh-prime.c b/dh-prime.c
deleted file mode 100644 (file)
index ebe3a33..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/* -*-c-*-
- *
- * $Id: dh-prime.c,v 1.2 1999/12/10 23:18:38 mdw Exp $
- *
- * Generate (safe) Diffie-Hellman primes
- *
- * (c) 1999 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.
- */
-
-/*----- Revision history --------------------------------------------------* 
- *
- * $Log: dh-prime.c,v $
- * Revision 1.2  1999/12/10 23:18:38  mdw
- * Change interface for suggested destinations.
- *
- * Revision 1.1  1999/11/20 22:24:44  mdw
- * Add Diffie-Hellman support.
- *
- */
-
-/*----- Header files ------------------------------------------------------*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dh.h"
-#include "fibrand.h"
-#include "mp.h"
-#include "mprand.h"
-#include "pgen.h"
-#include "rabin.h"
-
-/*----- Main code ---------------------------------------------------------*/
-
-/* --- @dh_prime@ --- *
- *
- * Arguments:  @mp *s@ = start point for search (must be odd)
- *             @size_t n@ = number of concerted attempts to make, or zero
- *             @void (*proc)(int ev, void *p)@ = event handler
- *             @void *p@ = argument for event handler
- *
- * Returns:    A prime number %$p$% where %$p = 2q + 1$% for prime %$q$%.
- *
- * Use:                Finds a safe prime by sequential search from a given starting
- *             point.  If it fails, a null pointer is returned.
- *
- *             The event handler is informed of the progress of the search.
- *             It may abort the search at any time by returning a nonzero
- *             value.
- */
-
-mp *dh_prime(mp *s, size_t n,
-            int (*proc)(int /*ev*/, void */*p*/), void *arg)
-{
-  pgen pq, pp;
-  int rc_q, rc_p;
-  grand *gr = fibrand_create(0);
-  mp *b = MP_NEW;
-  size_t sz = mp_bits(s);
-
-  /* --- Initialize prime generators --- */
-
-  rc_q = pgen_create(&pq, s);
-  rc_p = pgen_muladd(&pp, &pq, 2, 1);
-
-  /* --- Now step along until something crops up --- */
-
-  for (;;) {
-    rabin rq, rp;
-    int i;
-
-    /* --- Don't do expensive testing unless necessary --- */
-
-    if (rc_q == PGEN_PRIME && rc_p == PGEN_PRIME)
-      break;
-    if (rc_q == PGEN_COMPOSITE || rc_p == PGEN_COMPOSITE)
-      goto next;
-
-    /* --- Initialize Rabin-Miller contexts --- */
-
-    if (rc_q == PGEN_MAYBE)
-      rabin_create(&rq, pq.m);
-    if (rc_p == PGEN_MAYBE)
-      rabin_create(&rp, pp.m);
-
-    /* --- Now run tests on each in turn --- *
-     *
-     * On the sorts of modulus sizes which work well in discrete log
-     * problems, five tests should be sufficient.
-     */
-
-    for (i = 0; i < 5; i++) {
-      b = mprand(b, sz, gr, 1);
-      if (rc_q == PGEN_MAYBE &&
-         (rc_q = rabin_test(&rq, b)) == PGEN_COMPOSITE)
-       break;
-      if (rc_p == PGEN_MAYBE &&
-         (rc_p = rabin_test(&rp, b)) == PGEN_COMPOSITE)
-       break;
-      if (proc && proc(DHEV_PASS, arg))
-       break;
-    }
-    if (rc_q != PGEN_PRIME)
-      rabin_destroy(&rq);
-    if (rc_p != PGEN_PRIME)
-      rabin_destroy(&rp);
-
-    /* --- If the tests passed, accept the numbers --- */
-
-    if (i >= 5)
-      break;
-    if (proc && proc(DHEV_FAIL, arg))
-      goto fail;
-    if (n) {
-      n--;
-      if (!n)
-       goto fail;
-    }
-
-    /* --- Step the contexts on --- */
-
-  next:
-    rc_q = pgen_step(&pq, 2);
-    rc_p = pgen_step(&pp, 4);
-  }
-
-  /* --- Return a result --- */
-
-  {
-    mp *p = MP_COPY(pp.m);
-    pgen_destroy(&pq);
-    pgen_destroy(&pp);
-    mp_drop(b);
-    gr->ops->destroy(gr);
-    return (p);
-  }
-
-  /* --- Failure --- */
-
-fail:
-  pgen_destroy(&pq);
-  pgen_destroy(&pp);
-  mp_drop(b);
-  gr->ops->destroy(gr);
-  return (0);
-}
-
-/*----- That's all, folks -------------------------------------------------*/
diff --git a/dh.h b/dh.h
index bf8d79a..465f59f 100644 (file)
--- a/dh.h
+++ b/dh.h
@@ -1,8 +1,9 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: dh.h,v 1.2 1999/12/10 23:29:48 mdw Exp $
+ * $Id: dh.h,v 1.3 2000/02/12 18:21:02 mdw Exp $
+ *
+ * Diffie-Hellman and related public-key systems
  *
  *
- * [Diffie-Hellman key negotiation *
  * (c) 1999 Straylight/Edgeware
  */
 
  * (c) 1999 Straylight/Edgeware
  */
 
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: dh.h,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: dh.h,v $
- * Revision 1.2  1999/12/10 23:29:48  mdw
- * Change header file guard names.
- *
- * Revision 1.1  1999/11/20 22:24:44  mdw
- * Add Diffie-Hellman support.
+ * Revision 1.3  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
  *
  */
 
  *
  */
 
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
-#ifndef CATACOMB_MP_H
-#  include "mp.h"
+#ifndef CATACOMB_GRAND_H
+#  include "grand.h"
 #endif
 
 #endif
 
-/*----- Event codes -------------------------------------------------------*/
+#ifndef CATACOMB_PGEN_H
+#  include "pgen.h"
+#endif
 
 
-enum {
-  DHEV_OK,
+/*----- Data structures ---------------------------------------------------*/
 
 
-  DHEV_FAIL,
-  DHEV_PASS
-};
+typedef struct dh_param {
+  mp *p, *q;
+  mp *g;
+} dh_param;
 
 /*----- Functions provided ------------------------------------------------*/
 
 
 /*----- Functions provided ------------------------------------------------*/
 
-/* --- @dh_prime@ --- *
+/* --- @dh_gen@ --- *
  *
  *
- * Arguments:  @mp *s@ = start point for search (must be odd)
- *             @size_t n@ = number of concerted attempts to make, or zero
- *             @void (*proc)(int ev, void *p)@ = event handler
- *             @void *p@ = argument for event handler
+ * Arguments:  @dh_param *dp@ = pointer to output parameter block
+ *             @unsigned ql@ = length of %$q$% in bits, or zero
+ *             @unsigned pl@ = length of %$p$% in bits
+ *             @unsigned steps@ = number of steps to go
+ *             @grand *r@ = random number source
+ *             @pgen_proc *event@ = event handler function
+ *             @void *ectx@ = argument for the event handler
  *
  *
- * Returns:    A prime number %$p$% where %$p = 2q + 1$% for prime %$q$%.
+ * Returns:    @PGEN_DONE@ if it worked, @PGEN_ABORT@ if it didn't.
  *
  *
- * Use:                Finds a safe prime by sequential search from a given starting
- *             point.  If it fails, a null pointer is returned.
+ * Use:                Generates Diffie-Hellman parameters.
  *
  *
- *             The event handler is informed of the progress of the search.
- *             It may abort the search at any time by returning a nonzero
- *             value.
+ *             The parameters are a prime %$q$%, relatively small, and a
+ *             large prime %$p = kq + 1$% for some %$k$%, together with a
+ *             generator %$g$% of the cyclic subgroup of order %$q$%.  These
+ *             are actually the same as the DSA parameter set, but the
+ *             generation algorithm is different.  Also, if @ql@ is zero,
+ *             this algorithm forces %$k = 2$%, and chooses %$g = 4$%.  Make
+ *             sure you have something interesting to do if you choose this
+ *             option.
  */
 
  */
 
-extern mp *dh_prime(mp */*s*/, size_t /*n*/,
-                   int (*proc)(int /*ev*/, void */*p*/), void */*p*/);
+extern int dh_gen(dh_param */*dp*/, unsigned /*ql*/, unsigned /*pl*/,
+                 unsigned /*steps*/, grand */*r*/, pgen_proc */*event*/,
+                 void */*ectx*/);
 
 /*----- That's all, folks -------------------------------------------------*/
 
 
 /*----- That's all, folks -------------------------------------------------*/
 
index d26bfe4..40454d8 100644 (file)
--- a/dsa-gen.c
+++ b/dsa-gen.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: dsa-gen.c,v 1.4 1999/12/22 15:52:44 mdw Exp $
+ * $Id: dsa-gen.c,v 1.5 2000/02/12 18:21:02 mdw Exp $
  *
  * Generate DSA shared parameters
  *
  *
  * Generate DSA shared parameters
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: dsa-gen.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: dsa-gen.c,v $
+ * Revision 1.5  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.4  1999/12/22 15:52:44  mdw
  * Reworking for new prime-search system.
  *
  * Revision 1.4  1999/12/22 15:52:44  mdw
  * Reworking for new prime-search system.
  *
@@ -141,7 +144,12 @@ int dsa_step(int rq, pgen_event *ev, void *p)
  * Returns:    @PGEN_DONE@ if everything worked ok; @PGEN_ABORT@ otherwise.
  *
  * Use:                Generates the DSA shared parameters from a given seed value.
  * Returns:    @PGEN_DONE@ if everything worked ok; @PGEN_ABORT@ otherwise.
  *
  * Use:                Generates the DSA shared parameters from a given seed value.
- *             This can take quite a long time.
+ *
+ *             The parameters are a prime %$q$%, relatively small, and a
+ *             large prime %$p = kq + 1$% for some %$k$%, together with a
+ *             generator %$g$% of the cyclic subgroup of order %$q$%.  These
+ *             are actually the same as the Diffie-Hellman parameter set,
+ *             but the generation algorithm is different.
  *
  *             The algorithm used is a compatible extension of the method
  *             described in the DSA standard, FIPS 186.  The standard
  *
  *             The algorithm used is a compatible extension of the method
  *             described in the DSA standard, FIPS 186.  The standard
index 3737a5d..b779323 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: key-attr.c,v 1.1 1999/12/22 15:47:48 mdw Exp $
+ * $Id: key-attr.c,v 1.2 2000/02/12 18:21:02 mdw Exp $
  *
  * Key attribute manipulation
  *
  *
  * Key attribute manipulation
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-attr.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-attr.c,v $
+ * Revision 1.2  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
@@ -43,7 +46,7 @@
 #include <string.h>
 #include <time.h>
 
 #include <string.h>
 #include <time.h>
 
-#include <mLib/alloc.h>
+#include <mLib/dstr.h>
 #include <mLib/sym.h>
 
 #include "key.h"
 #include <mLib/sym.h>
 
 #include "key.h"
diff --git a/key-binary.c b/key-binary.c
new file mode 100644 (file)
index 0000000..4459ff1
--- /dev/null
@@ -0,0 +1,251 @@
+/* -*-c-*-
+ *
+ * $Id: key-binary.c,v 1.1 2000/02/12 18:21:02 mdw Exp $
+ *
+ * Key binary encoding
+ *
+ * (c) 1999 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.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: key-binary.c,v $
+ * Revision 1.1  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+#include <mLib/dstr.h>
+#include <mLib/sub.h>
+#include <mLib/sym.h>
+
+#include "key-data.h"
+#include "mp.h"
+#include "mptext.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @key_decode@ --- *
+ *
+ * Arguments:  @const void *p@ = pointer to buffer to read
+ *             @size_t sz@ = size of the buffer
+ *             @key_data *k@ = pointer to key data block to write to
+ *
+ * Returns:    Zero if everything worked, nonzero otherwise.
+ *
+ * Use:                Decodes a binary representation of a key.
+ */
+
+int key_decode(const void *p, size_t sz, key_data *k)
+{
+  const octet *q = p;
+  size_t psz;
+  unsigned e;
+
+  /* --- Parse the header information --- *
+   *
+   * Make sure the size matches external reality.  Security holes have been
+   * known to creep in without this sort of check.  (No, this isn't an after-
+   * the-fact patch-up.)
+   */
+
+  e = LOAD16(q);
+  psz = LOAD16(q + 2);
+  if (psz + 4 > sz)
+    return (-1);
+  k->e = e;
+
+  /* --- Now decide what to do --- */
+
+  switch (e & KF_ENCMASK) {
+
+    /* --- Plain binary data --- */
+
+    case KENC_BINARY:
+    case KENC_ENCRYPT:
+      k->u.k.k = sub_alloc(psz);
+      memcpy(k->u.k.k, q + 4, psz);
+      k->u.k.sz = psz;
+      break;
+
+    /* --- Multiprecision integer data --- */
+
+    case KENC_MP:
+      k->u.m = mp_loadb(MP_NEW, q + 4, psz);
+      if (k->e & KF_BURN)
+       mp_burn(k->u.m);
+      break;
+
+    /* --- Structured key data --- */
+
+    case KENC_STRUCT: {
+      dstr d = DSTR_INIT;
+      key_struct *ks;
+      unsigned f;
+
+      if ((k->e & ~KF_ENCMASK) || (psz & 3))
+       return (-1);
+      q += 4;
+      sym_create(&k->u.s);
+
+      while (psz) {
+
+       /* --- Read the tag string --- */
+
+       DRESET(&d);
+       sz = LOAD8(q);
+       if (sz >= psz)
+         goto fail;
+       DPUTM(&d, q + 1, sz);
+       DPUTZ(&d);
+       sz = (sz + 4) & ~3;
+       q += sz; psz -= sz;
+
+       /* --- Read the encoding and size --- */
+
+       e = LOAD16(q);
+       sz = (LOAD16(q + 2) + 7) & ~3;
+       if (sz > psz)
+         goto fail;
+
+       /* --- Create a table node and fill it in --- */
+
+       ks = sym_find(&k->u.s, d.buf, d.len + 1, sizeof(*ks), &f);
+       if (f)
+         goto fail;
+       if (key_decode(q, sz, &ks->k)) {
+         sym_remove(&k->u.s, ks);
+         goto fail;
+       }
+       psz -= sz;
+       q += sz;
+      }
+      dstr_destroy(&d);
+      break;
+
+      /* --- Tidy up after a failure --- */
+
+    fail:
+      dstr_destroy(&d);
+      key_destroy(k);
+      return (-1);
+    } break;
+
+    /* --- Everything else --- */
+
+    default:
+      return (-1);
+  }
+
+  /* --- OK, that was good --- */
+
+  return (0);
+}
+
+/* --- @key_encode@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @dstr *d@ = pointer to destination string
+ *             @const key_filter *kf@ = pointer to key selection block
+ *
+ * Returns:    Nonzero if an item was actually written.
+ *
+ * Use:                Encodes a key block as binary data.
+ */
+
+int key_encode(key_data *k, dstr *d, const key_filter *kf)
+{
+  int rc = 0;
+  if (!KEY_MATCH(k, kf))
+    return (0);
+  switch (k->e & KF_ENCMASK) {
+    case KENC_BINARY:
+    case KENC_ENCRYPT: {
+      char *p;
+
+      DENSURE(d, (k->u.k.sz + 7) & ~3);
+      p = d->buf + d->len;
+      STORE16(p, k->e);
+      STORE16(p + 2, k->u.k.sz);
+      d->len += 4;
+      DPUTM(d, k->u.k.k, k->u.k.sz);
+      rc = 1;
+    } break;
+
+    case KENC_MP: {
+      char *p;
+      size_t sz = mp_octets(k->u.m);
+
+      DENSURE(d, (sz + 7) & ~3);
+      p = d->buf + d->len;
+      STORE16(p, k->e);
+      STORE16(p + 2, sz);
+      mp_storeb(k->u.m, p + 4, sz);
+      d->len += sz + 4;
+      rc = 1;
+    } break;
+
+    case KENC_STRUCT: {
+      size_t n;
+      char *p;
+      key_struct *ks;
+      sym_iter i;
+
+      n = d->len;
+      DENSURE(d, 4);
+      p = d->buf + n;
+      STORE16(p, k->e & KF_ENCMASK);
+      d->len += 4;
+      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
+       size_t o = d->len;
+       DENSURE(d, 1);
+       *(octet *)(d->buf + d->len++) = strlen(SYM_NAME(ks));
+       DPUTS(d, SYM_NAME(ks));
+       while (d->len & 3)
+         DPUTC(d, 0);
+       if (key_encode(&ks->k, d, kf))
+         rc = 1;
+       else
+         d->len = o;
+      }
+      if (!rc)
+        d->len = n;
+      else {
+       p = d->buf + n + 2;
+       n = d->len - n - 4;
+       STORE16(p,  n);
+      }
+    } break;
+  }
+  while (d->len & 3)
+    DPUTC(d, 0);
+  return (rc);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
index 01def8c..5da8b38 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: key-data.c,v 1.1 1999/12/22 15:47:48 mdw Exp $
+ * $Id: key-data.c,v 1.2 2000/02/12 18:21:02 mdw Exp $
  *
  * Encoding and decoding of key data
  *
  *
  * Encoding and decoding of key data
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-data.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-data.c,v $
+ * Revision 1.2  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
 #include <stdlib.h>
 #include <string.h>
 
 #include <stdlib.h>
 #include <string.h>
 
-#include <mLib/alloc.h>
 #include <mLib/base64.h>
 #include <mLib/bits.h>
 #include <mLib/dstr.h>
 #include <mLib/sub.h>
 #include <mLib/sym.h>
 
 #include <mLib/base64.h>
 #include <mLib/bits.h>
 #include <mLib/dstr.h>
 #include <mLib/sub.h>
 #include <mLib/sym.h>
 
-#include "key.h"
+#include "key-data.h"
 #include "mp.h"
 #include "mptext.h"
 
 #include "mp.h"
 #include "mptext.h"
 
-/*----- Disposal ----------------------------------------------------------*/
-
-/* --- @key_destroy@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data to destroy
- *
- * Returns:    ---
- *
- * Use:                Destroys a lump of key data.
- */
-
-void key_destroy(key_data *k)
-{
-  switch (k->e & KF_ENCMASK) {
-    case KENC_BINARY:
-    case KENC_ENCRYPT:
-      if (k->e & KF_BURN)
-       memset(k->u.k.k, 0, k->u.k.sz);
-      sub_free(k->u.k.k, k->u.k.sz);
-      break;
-    case KENC_MP:
-      mp_drop(k->u.m);
-      break;
-    case KENC_STRUCT: {
-      sym_iter i;
-      key_struct *ks;
-
-      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; )
-       key_destroy(&ks->k);
-      sym_destroy(&k->u.s);
-    } break;
-  }
-}
-
 /*----- Setting new values ------------------------------------------------*/
 
 /* --- @key_binary@ --- *
 /*----- Setting new values ------------------------------------------------*/
 
 /* --- @key_binary@ --- *
@@ -194,35 +162,44 @@ key_data *key_structcreate(key_data *k, const char *tag)
   ks = sym_find(&k->u.s, tag, -1, sizeof(*ks), &f);
   if (f)
     key_destroy(&ks->k);
   ks = sym_find(&k->u.s, tag, -1, sizeof(*ks), &f);
   if (f)
     key_destroy(&ks->k);
-  ks->k.e = 0;
+  ks->k.e = KF_TEMP;
   return (&ks->k);
 }
 
   return (&ks->k);
 }
 
-/* --- @key_match@ --- *
+/*----- Miscellaneous operations ------------------------------------------*/
+
+/* --- @key_destroy@ --- *
  *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const key_filter *kf@ = pointer to filter block
+ * Arguments:  @key_data *k@ = pointer to key data to destroy
  *
  *
- * Returns:    Nonzero if the key matches the filter.
+ * Returns:    ---
  *
  *
- * Use:                Checks whether a key matches a filter.
+ * Use:                Destroys a lump of key data.
  */
 
  */
 
-int key_match(key_data *k, const key_filter *kf)
+void key_destroy(key_data *k)
 {
 {
-  sym_iter i;
-  key_struct *ks;
-
-  if (!kf)
-    return (1);
-  if ((k->e & KF_ENCMASK) != KENC_STRUCT)
-    return ((k->e & kf->m) == kf->f);
+  switch (k->e & KF_ENCMASK) {
+    case KENC_BINARY:
+    case KENC_ENCRYPT:
+      if (k->e & KF_BURN)
+       memset(k->u.k.k, 0, k->u.k.sz);
+      sub_free(k->u.k.k, k->u.k.sz);
+      break;
+    case KENC_MP:
+      mp_drop(k->u.m);
+      break;
+    case KENC_STRUCT: {
+      sym_iter i;
+      key_struct *ks;
 
 
-  for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
-    if (key_match(&ks->k, kf))
-      return (1);
+      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
+       if (!(ks->k.e & KF_TEMP))
+         key_destroy(&ks->k);
+      }
+      sym_destroy(&k->u.s);
+    } break;
   }
   }
-  return (0);
 }
 
 /* --- @key_do@ --- *
 }
 
 /* --- @key_do@ --- *
@@ -266,8 +243,6 @@ int key_do(key_data *k, const key_filter *kf, dstr *d,
   }
 }
 
   }
 }
 
-/*----- Copying -----------------------------------------------------------*/
-
 /* --- @key_copy@ --- *
  *
  * Arguments:  @key_data *kd@ = pointer to destination data block
 /* --- @key_copy@ --- *
  *
  * Arguments:  @key_data *kd@ = pointer to destination data block
@@ -329,455 +304,4 @@ int key_copy(key_data *kd, key_data *k, const key_filter *kf)
   return (1);
 }
 
   return (1);
 }
 
-/*----- Textual encoding --------------------------------------------------*/
-
-/* --- @key_read@ --- *
- *
- * Arguments:  @const char *p@ = pointer to textual key representation
- *             @key_data *k@ = pointer to output block for key data
- *             @char **pp@ = where to store the end pointer
- *
- * Returns:    Zero if all went well, nonzero if there was a problem.
- *
- * Use:                Parses a textual key description.
- */
-
-int key_read(const char *p, key_data *k, char **pp)
-{
-  unsigned e;
-
-  /* --- Read the encoding type --- *
-   *
-   * The key format is `[FLAGS:]DATA'.  If there is no encoding type
-   * named, assume that it's `binary' for backwards compatibility.
-   */
-
-  if (strchr(p, ':') == 0)
-    e = 0;
-  else {
-    char *q;
-    if (key_readflags(p, &q, &e, 0))
-      return (-1);
-    p = q + 1;
-  }
-
-  /* --- Now scan the data based on the encoding type --- */
-
-  k->e = e;
-  switch (e & KF_ENCMASK) {
-
-    /* --- Binary encoding --- *
-     *
-     * Simply read out the Base64-encoded data.  Since `,' and `]' are our
-     * delimeter characters, and they can't appear in Base64-encoded data, I
-     * can just do a simple search to find the end of the encoded data.
-     */
-
-    case KENC_BINARY:
-    case KENC_ENCRYPT: {
-      dstr d = DSTR_INIT;
-      base64_ctx b;
-      size_t sz = strcspn(p, ",]");
-
-      base64_init(&b);
-      base64_decode(&b, p, sz, &d);
-      base64_decode(&b, 0, 0, &d);
-      k->u.k.k = sub_alloc(d.len);
-      k->u.k.sz = d.len;
-      memcpy(k->u.k.k, d.buf, d.len);
-      dstr_destroy(&d);
-      p += sz;
-    } break;
-
-    /* --- Multiprecision integer encoding --- *
-     *
-     * Multiprecision integers have a convenient reading function.
-     */
-
-    case KENC_MP: {
-      char *q;
-      mp *m = mp_readstring(MP_NEW, p, &q, 0);
-      if (!m)
-       return (-1);
-      if (k->e & KF_BURN)
-       mp_burn(m);
-      k->u.m = m;
-      p = q;
-    } break;
-
-    /* --- Structured information encoding --- *
-     *
-     * The format for structured key data is `[NAME=KEY,...]', where the
-     * brackets are part of the syntax.  Structured keys have no flags apart
-     * from the encoding.
-     *
-     * The binary encoding only allows names up to 255 bytes long.  Check for
-     * this here.
-     */
-
-    case KENC_STRUCT: {
-      dstr d = DSTR_INIT;
-      char *q;
-
-      /* --- Read the opening bracket --- */
-
-      k->e &= KF_ENCMASK;
-      if (*p != '[')
-       return (-1);
-      p++;
-      sym_create(&k->u.s);
-
-      /* --- Read named key subparts --- */
-
-      for (;;) {
-       size_t sz;
-       key_struct *ks;
-
-       /* --- Stop if there's a close-bracket --- *
-        *
-        * This allows `[]' to be an empty structured key, which is good.  It
-        * also makes `[foo=enc:bar,]' legal, and that's less good but I can
-        * live with it.
-        */
-
-       if (*p == ']')
-         break;
-
-       /* --- Read the name out and check the length --- */
-
-       if ((q = strchr(p, '=')) == 0)
-         goto fail;
-       sz = q - p;
-       if (sz >= 256)
-         goto fail;
-       DRESET(&d);
-       DPUTM(&d, p, sz);
-       DPUTZ(&d);
-
-       /* --- Add an appropriate block to the key table --- *
-        *
-        * Simply destroy old data if there's already a match.
-        */
-
-       {
-         unsigned f;
-         ks = sym_find(&k->u.s, d.buf, d.len + 1, sizeof(*ks), &f);
-         if (f)
-           key_destroy(&ks->k);
-       }
-
-       /* --- Read the key data for the subkey --- */
-
-       if (key_read(q + 1, &ks->k, &q)) {
-         sym_remove(&k->u.s, ks);
-         goto fail;
-       }
-       p = q;
-
-       /* --- Read the comma or close-bracket --- */
-
-       if (*p == ']')
-         break;
-       else if (*p == ',')
-         p++;
-       else
-         goto fail;
-      }
-
-      /* --- Step past the close bracket --- */
-
-      p++;
-      dstr_destroy(&d);
-      break;
-
-      /* --- Tidy up after a failure --- */
-
-    fail:
-      dstr_destroy(&d);
-      key_destroy(k);
-      return (-1);
-    } break;
-
-    /* --- Anything else is unknown --- */
-
-    default:
-      return (-1);
-  }
-
-  /* --- Return the end pointer --- */
-
-  if (pp)
-    *pp = (char *)p;
-  return (0);
-}
-
-/* --- @key_write@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data
- *             @dstr *d@ = destination string to write on
- *             @const key_filter *kf@ = pointer to key selection block
- *
- * Returns:    Nonzero if an item was actually written.
- *
- * Use:                Writes a key in a textual encoding.
- */
-int key_write(key_data *k, dstr *d, const key_filter *kf)
-{
-  int rc = 0;
-  if (!KEY_MATCH(k, kf))
-    return (0);
-  switch (k->e & KF_ENCMASK) {
-    case KENC_BINARY:
-    case KENC_ENCRYPT: {
-      base64_ctx b;
-
-      if ((k->e & KF_ENCMASK) == KENC_BINARY)
-       key_writeflags(k->e, d);
-      else
-       DPUTS(d, "encrypt,secret");
-      DPUTC(d, ':');
-      base64_init(&b);
-      b.indent = "";
-      b.maxline = 0;
-      base64_encode(&b, k->u.k.k, k->u.k.sz, d);
-      base64_encode(&b, 0, 0, d);
-      rc = 1;
-    } break;
-    case KENC_MP:
-      key_writeflags(k->e, d);
-      DPUTC(d, ':');
-      mp_writedstr(k->u.m, d, 10);
-      rc = 1;
-      break;
-    case KENC_STRUCT: {
-      sym_iter i;
-      key_struct *ks;
-      char del = 0;
-      size_t n = d->len;
-
-      DPUTS(d, "struct:[");
-      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
-       size_t o = d->len;
-       if (del)
-         DPUTC(d, del);
-       DPUTS(d, SYM_NAME(ks));
-       DPUTC(d, '=');
-       if (!key_write(&ks->k, d, kf))
-         d->len = o;
-       else {
-         del = ',';
-         rc = 1;
-       }
-      }
-      if (!rc)
-       d->len = n;
-      else
-       DPUTC(d, ']');
-    } break;
-  }
-  DPUTZ(d);
-
-  return (rc);
-}
-
-/*----- Binary encoding ---------------------------------------------------*/
-
-/* --- @key_decode@ --- *
- *
- * Arguments:  @const void *p@ = pointer to buffer to read
- *             @size_t sz@ = size of the buffer
- *             @key_data *k@ = pointer to key data block to write to
- *
- * Returns:    Zero if everything worked, nonzero otherwise.
- *
- * Use:                Decodes a binary representation of a key.
- */
-
-int key_decode(const void *p, size_t sz, key_data *k)
-{
-  const octet *q = p;
-  size_t psz;
-  unsigned e;
-
-  /* --- Parse the header information --- *
-   *
-   * Make sure the size matches external reality.  Security holes have been
-   * known to creep in without this sort of check.  (No, this isn't an after-
-   * the-fact patch-up.)
-   */
-
-  e = LOAD16(q);
-  psz = LOAD16(q + 2);
-  if (psz + 4 > sz)
-    return (-1);
-  k->e = e;
-
-  /* --- Now decide what to do --- */
-
-  switch (e & KF_ENCMASK) {
-
-    /* --- Plain binary data --- */
-
-    case KENC_BINARY:
-    case KENC_ENCRYPT:
-      k->u.k.k = sub_alloc(psz);
-      memcpy(k->u.k.k, q + 4, psz);
-      k->u.k.sz = psz;
-      break;
-
-    /* --- Multiprecision integer data --- */
-
-    case KENC_MP:
-      k->u.m = mp_loadb(MP_NEW, q + 4, psz);
-      if (k->e & KF_BURN)
-       mp_burn(k->u.m);
-      break;
-
-    /* --- Structured key data --- */
-
-    case KENC_STRUCT: {
-      dstr d = DSTR_INIT;
-      key_struct *ks;
-      unsigned f;
-
-      if ((k->e & ~KF_ENCMASK) || (psz & 3))
-       return (-1);
-      q += 4;
-      sym_create(&k->u.s);
-
-      while (psz) {
-
-       /* --- Read the tag string --- */
-
-       DRESET(&d);
-       sz = LOAD8(q);
-       if (sz >= psz)
-         goto fail;
-       DPUTM(&d, q + 1, sz);
-       DPUTZ(&d);
-       sz = (sz + 4) & ~3;
-       q += sz; psz -= sz;
-
-       /* --- Read the encoding and size --- */
-
-       e = LOAD16(q);
-       sz = (LOAD16(q + 2) + 7) & ~3;
-       if (sz > psz)
-         goto fail;
-
-       /* --- Create a table node and fill it in --- */
-
-       ks = sym_find(&k->u.s, d.buf, d.len + 1, sizeof(*ks), &f);
-       if (f)
-         goto fail;
-       if (key_decode(q, sz, &ks->k)) {
-         sym_remove(&k->u.s, ks);
-         goto fail;
-       }
-       psz -= sz;
-       q += sz;
-      }
-      dstr_destroy(&d);
-      break;
-
-      /* --- Tidy up after a failure --- */
-
-    fail:
-      dstr_destroy(&d);
-      key_destroy(k);
-      return (-1);
-    } break;
-
-    /* --- Everything else --- */
-
-    default:
-      return (-1);
-  }
-
-  /* --- OK, that was good --- */
-
-  return (0);
-}
-
-/* --- @key_encode@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @dstr *d@ = pointer to destination string
- *             @const key_filter *kf@ = pointer to key selection block
- *
- * Returns:    Nonzero if an item was actually written.
- *
- * Use:                Encodes a key block as binary data.
- */
-
-int key_encode(key_data *k, dstr *d, const key_filter *kf)
-{
-  int rc = 0;
-  if (!KEY_MATCH(k, kf))
-    return (0);
-  switch (k->e & KF_ENCMASK) {
-    case KENC_BINARY:
-    case KENC_ENCRYPT: {
-      char *p;
-
-      DENSURE(d, (k->u.k.sz + 7) & ~3);
-      p = d->buf + d->len;
-      STORE16(p, k->e);
-      STORE16(p + 2, k->u.k.sz);
-      d->len += 4;
-      DPUTM(d, k->u.k.k, k->u.k.sz);
-      rc = 1;
-    } break;
-
-    case KENC_MP: {
-      char *p;
-      size_t sz = mp_octets(k->u.m);
-
-      DENSURE(d, (sz + 7) & ~3);
-      p = d->buf + d->len;
-      STORE16(p, k->e);
-      STORE16(p + 2, sz);
-      mp_storeb(k->u.m, p + 4, sz);
-      d->len += sz + 4;
-      rc = 1;
-    } break;
-
-    case KENC_STRUCT: {
-      size_t n;
-      char *p;
-      key_struct *ks;
-      sym_iter i;
-
-      n = d->len;
-      DENSURE(d, 4);
-      p = d->buf + n;
-      STORE16(p, k->e & KF_ENCMASK);
-      d->len += 4;
-      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
-       size_t o = d->len;
-       DENSURE(d, 1);
-       *(octet *)(d->buf + d->len++) = strlen(SYM_NAME(ks));
-       DPUTS(d, SYM_NAME(ks));
-       while (d->len & 3)
-         DPUTC(d, 0);
-       if (key_encode(&ks->k, d, kf))
-         rc = 1;
-       else
-         d->len = o;
-      }
-      if (!rc)
-        d->len = n;
-      else {
-       p = d->buf + n + 2;
-       n = d->len - n - 4;
-       STORE16(p,  n);
-      }
-    } break;
-  }
-  while (d->len & 3)
-    DPUTC(d, 0);
-  return (rc);
-}
-
 /*----- That's all, folks -------------------------------------------------*/
 /*----- That's all, folks -------------------------------------------------*/
diff --git a/key-data.h b/key-data.h
new file mode 100644 (file)
index 0000000..6cf2439
--- /dev/null
@@ -0,0 +1,399 @@
+/* -*-c-*-
+ *
+ * $Id: key-data.h,v 1.1 2000/02/12 18:21:23 mdw Exp $
+ *
+ * Manipulating key data
+ *
+ * (c) 1999 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.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: key-data.h,v $
+ * Revision 1.1  2000/02/12 18:21:23  mdw
+ * Overhaul of key management (again).
+ *
+ */
+
+#ifndef CATACOMB_KEY_DATA_H
+#define CATACOMB_KEY_DATA_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/dstr.h>
+#include <mLib/sym.h>
+
+#ifndef CATACOMB_MP_H
+#  include "mp.h"
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- Key binary data --- */
+
+typedef struct key_bin {
+  octet *k;                            /* Pointer to key data */
+  size_t sz;                           /* Size of the key data (in bytes) */
+} key_bin;
+
+/* --- Key data structure --- */
+
+typedef struct key_data {
+  unsigned e;                          /* Encoding type for key data */
+  union {
+    key_bin k;                         /* Binary key data */
+    mp *m;                             /* Multiprecision integer */
+    sym_table s;                       /* Structured key data */
+  } u;
+} key_data;
+
+typedef struct key_struct {
+  sym_base _b;
+  key_data k;
+} key_struct;
+
+/* --- Key binary encoding --- *
+ *
+ * The binary encoding consists of a header containing a 16-bit encoding type
+ * and a 16-bit length, followed immediately by the key data, followed by
+ * between zero and three zero bytes to make the total length a multiple of
+ * four.  The format of the following data depends on the encoding type:
+ *
+ * @KENC_BINARY@       Binary data.
+ *
+ * @KENC_MP@           Octet array interpreted in big-endian byte order.
+ *
+ * @KENC_STRUCT@       An array of pairs, each containing a string (8-bit
+ *                     length followed by data and zero-padding to 4-byte
+ *                     boundary) and key binary encodings.
+ *
+ * @KENC_ENCRYPT@      Binary data, format
+ */
+
+/* --- Key encoding methods and other flags--- */
+
+enum {
+
+  /* --- Bottom two bits are the encoding type --- */
+
+  KF_ENCMASK   = 0x03,                 /* Encoding mask */
+  KENC_BINARY  = 0x00,                 /* Plain binary key (@k@) */
+  KENC_MP      = 0x01,                 /* Multiprecision integer (@i@) */
+  KENC_STRUCT  = 0x02,                 /* Structured key data (@s@) */
+  KENC_ENCRYPT = 0x03,                 /* Encrypted key type (@k@) */
+
+  /* --- Key category bits --- */
+
+  KF_CATMASK   = 0x0c,                 /* Category mask */
+  KCAT_SYMM    = 0x00,                 /* Symmetric encryption key */
+  KCAT_PRIV    = 0x04,                 /* Private (asymmetric) key */
+  KCAT_PUB     = 0x08,                 /* Public (asymmetric) key */
+  KCAT_SHARE   = 0x0c,                 /* Shared (asymmetric) key */
+  KF_NONSECRET = 0x08,                 /* Bit flag for non-secret keys */
+
+  /* --- Other flags --- */
+
+  KF_BURN      = 0x10,                 /* Burn key after use */
+  KF_TEMP      = 0x20,                 /* Temporary copy flag */
+
+  /* --- Tag end --- */
+
+  KENC_MAX                             /* Dummy limit constant */
+};
+
+/* --- Key flag filtering --- */
+
+typedef struct key_filter {
+  unsigned f;
+  unsigned m;
+} key_filter;
+
+/* --- Matching aginst key selection --- */
+
+#define KEY_MATCH(kd, kf)                                              \
+  (!(kf) ||                                                            \
+   ((kd)->e & KF_ENCMASK) == KENC_STRUCT ||                            \
+   ((kd)->e & (kf)->m) == (kf)->f)
+
+/*----- Key flags and filtering -------------------------------------------*/
+
+/* --- @key_readflags@ --- *
+ *
+ * Arguments:  @const char *p@ = pointer to string to read
+ *             @char **pp@ = where to store the end pointer
+ *             @unsigned *ff@ = where to store the flags
+ *             @unsigned *mm@ = where to store the mask
+ *
+ * Returns:    Zero if all went well, nonzero if there was an error.
+ *
+ * Use:                Reads a flag string.
+ */
+
+extern int key_readflags(const char */*p*/, char **/*pp*/,
+                        unsigned */*ff*/, unsigned */*mm*/);
+
+/* --- @key_writeflags@ --- *
+ *
+ * Arguments:  @unsigned f@ = flags to write
+ *             @dstr *d@ = pointer to destination string
+ *
+ * Returns:    ---
+ *
+ * Use:                Emits a flags word as a string representation.
+ */
+
+extern void key_writeflags(unsigned /*f*/, dstr */*d*/);
+
+/* --- @key_match@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @const key_filter *kf@ = pointer to filter block
+ *
+ * Returns:    Nonzero if the key matches the filter.
+ *
+ * Use:                Checks whether a key matches a filter.
+ */
+
+extern int key_match(key_data */*k*/, const key_filter */*kf*/);
+
+/*----- Setting new key data ----------------------------------------------*/
+
+/* --- @key_binary@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @const void *p@ = pointer to key data
+ *             @size_t sz@ = size of the key data
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets a binary key in a key data block.
+ */
+
+extern void key_binary(key_data */*k*/, const void */*p*/, size_t /*sz*/);
+
+/* --- @key_encrypted@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @const void *p@ = pointer to key data
+ *             @size_t sz@ = size of the key data
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets an encrypted key in a key data block.
+ */
+
+extern void key_encrypted(key_data */*k*/, const void */*p*/, size_t /*sz*/);
+
+/* --- @key_mp@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @mp *m@ = pointer to the value to set
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets a multiprecision integer key in a key block.
+ */
+
+extern void key_mp(key_data */*k*/, mp */*m*/);
+
+/* --- @key_structure@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes a structured key type.
+ */
+
+extern void key_structure(key_data */*k*/);
+
+/* --- @key_structfind@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @const char *tag@ = pointer to tag string
+ *
+ * Returns:    Pointer to key data block, or null.
+ *
+ * Use:                Looks up the tag in a structured key.
+ */
+
+extern key_data *key_structfind(key_data */*k*/, const char */*tag*/);
+
+/* --- @key_structcreate@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @const char *tag@ = pointer to tag string
+ *
+ * Returns:    Pointer to newly created key data.
+ *
+ * Use:                Creates a new uninitialized subkey.
+ */
+
+extern key_data *key_structcreate(key_data */*k*/, const char */*tag*/);
+
+/*----- Miscellaneous operations ------------------------------------------*/
+
+/* --- @key_destroy@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data to destroy
+ *
+ * Returns:    ---
+ *
+ * Use:                Destroys a lump of key data.
+ */
+
+extern void key_destroy(key_data */*k*/);
+
+/* --- @key_do@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @const key_filter *kf@ = pointer to filter block
+ *             @dstr *d@ = pointer to base string
+ *             @int (*func)(key_data *kd, dstr *d, void *p@ = function
+ *             @void *p@ = argument to function
+ *
+ * Returns:    Nonzero return code from function, or zero.
+ *
+ * Use:                Runs a function over all the leaves of a key. 
+ */
+
+extern int key_do(key_data */*k*/, const key_filter */*kf*/, dstr */*d*/,
+                 int (*/*func*/)(key_data */*kd*/,
+                                 dstr */*d*/, void */*p*/),
+                 void */*p*/);
+
+/* --- @key_copy@ --- *
+ *
+ * Arguments:  @key_data *kd@ = pointer to destination data block
+ *             @key_data *k@ = pointer to source data block
+ *             @const key_filter *kf@ = pointer to filter block
+ *
+ * Returns:    Nonzero if an item was actually copied.
+ *
+ * Use:                Copies a chunk of key data from one place to another.
+ */
+
+extern int key_copy(key_data */*kd*/, key_data */*k*/,
+                   const key_filter */*kf*/);
+
+/*----- Textual encoding --------------------------------------------------*/
+
+/* --- @key_read@ --- *
+ *
+ * Arguments:  @const char *p@ = pointer to textual key representation
+ *             @key_data *k@ = pointer to output block for key data
+ *             @char **pp@ = where to store the end pointer
+ *
+ * Returns:    Zero if all went well, nonzero if there was a problem.
+ *
+ * Use:                Parses a textual key description.
+ */
+
+extern int key_read(const char */*p*/, key_data */*k*/, char **/*pp*/);
+
+/* --- @key_write@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data
+ *             @dstr *d@ = destination string to write on
+ *             @const key_filter *kf@ = pointer to key selection block
+ *
+ * Returns:    Nonzero if any items were actually written.
+ *
+ * Use:                Writes a key in a textual encoding.
+ */
+
+extern int key_write(key_data */*k*/, dstr */*d*/,
+                     const key_filter */*kf*/);
+
+/*----- Key binary encoding -----------------------------------------------*/
+
+/* --- @key_decode@ --- *
+ *
+ * Arguments:  @const void *p@ = pointer to buffer to read
+ *             @size_t sz@ = size of the buffer
+ *             @key_data *k@ = pointer to key data block to write to
+ *
+ * Returns:    Zero if everything worked, nonzero otherwise.
+ *
+ * Use:                Decodes a binary representation of a key.
+ */
+
+extern int key_decode(const void */*p*/, size_t /*sz*/, key_data */*k*/);
+
+/* --- @key_encode@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @dstr *d@ = pointer to destination string
+ *             @const key_filter *kf@ = pointer to key selection block
+ *
+ * Returns:    Nonzero if any items were actually written.
+ *
+ * Use:                Encodes a key block as binary data.
+ */
+
+extern int key_encode(key_data */*k*/, dstr */*d*/,
+                     const key_filter */*kf*/);
+
+/*----- Passphrase encryption ---------------------------------------------*/
+
+/* --- @key_plock@ --- *
+ *
+ * Arguments:  @const char *tag@ = tag to use for passphrase
+ *             @key_data *k@ = source key data block
+ *             @key_data *kt@ = target key data block
+ *
+ * Returns:    Zero if successful, nonzero if there was a problem.
+ *
+ * Use:                Locks a key by encrypting it with a passphrase.
+ */
+
+extern int key_plock(const char */*tag*/, key_data */*k*/, key_data */*kt*/);
+
+/* --- @key_punlock@ --- *
+ *
+ * Arguments:  @const char *tag@ = tag to use for passphrase
+ *             @key_data *k@ = source key data block
+ *             @key_data *kt@ = target key data block
+ *
+ * Returns:    Zero if it worked, nonzero if it didn't.
+ *
+ * Use:                Unlocks a passphrase-locked key.
+ */
+
+extern int key_punlock(const char */*tag*/,
+                      key_data */*k*/, key_data */*kt*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/key-error.c b/key-error.c
new file mode 100644 (file)
index 0000000..8ca934e
--- /dev/null
@@ -0,0 +1,75 @@
+/* -*-c-*-
+ *
+ * $Id: key-error.c,v 1.1 2000/02/12 18:21:02 mdw Exp $
+ *
+ * Translating key error codes into strings
+ *
+ * (c) 2000 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.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: key-error.c,v $
+ * Revision 1.1  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "key.h"
+
+/*----- Error reporting ---------------------------------------------------*/
+
+/* --- @key_strerror@ --- *
+ *
+ * Arguments:  @int err@ = error code from @key_new@
+ *
+ * Returns:    Pointer to error string.
+ *
+ * Use:                Translates a @KERR@ error code into a human-readable
+ *             string.
+ */
+
+const char *key_strerror(int err)
+{
+  char *tab[] = {
+    "No error",
+    "Bad tag string",
+    "Bad type string",
+    "Bad comment string",
+    "Keyid already exists",
+    "Key tag already exists",
+    "Key file is read-only",
+    "Key will eventually expire",
+    "Bad key flags string",
+    "Unknown error code"
+  };
+  
+  unsigned e = -err;
+  if (e >= KERR_MAX)
+    e = KERR_MAX;
+ return (tab[e]);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
index f25bb21..7840462 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: key-flags.c,v 1.1 1999/12/22 15:47:48 mdw Exp $
+ * $Id: key-flags.c,v 1.2 2000/02/12 18:21:02 mdw Exp $
  *
  * Reading and writing key flag strings
  *
  *
  * Reading and writing key flag strings
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-flags.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-flags.c,v $
+ * Revision 1.2  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
@@ -176,4 +179,31 @@ void key_writeflags(unsigned f, dstr *d)
   }
 }
 
   }
 }
 
+/* --- @key_match@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @const key_filter *kf@ = pointer to filter block
+ *
+ * Returns:    Nonzero if the key matches the filter.
+ *
+ * Use:                Checks whether a key matches a filter.
+ */
+
+int key_match(key_data *k, const key_filter *kf)
+{
+  sym_iter i;
+  key_struct *ks;
+
+  if (!kf)
+    return (1);
+  if ((k->e & KF_ENCMASK) != KENC_STRUCT)
+    return ((k->e & kf->m) == kf->f);
+
+  for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
+    if (key_match(&ks->k, kf))
+      return (1);
+  }
+  return (0);
+}
+
 /*----- That's all, folks -------------------------------------------------*/
 /*----- That's all, folks -------------------------------------------------*/
index 7ab32f3..6d4876f 100644 (file)
--- a/key-io.c
+++ b/key-io.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: key-io.c,v 1.1 1999/12/22 15:47:48 mdw Exp $
+ * $Id: key-io.c,v 1.2 2000/02/12 18:21:02 mdw Exp $
  *
  * Adding new keys to a key file
  *
  *
  * Adding new keys to a key file
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-io.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-io.c,v $
+ * Revision 1.2  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
@@ -44,7 +47,6 @@
 #include <string.h>
 #include <time.h>
 
 #include <string.h>
 #include <time.h>
 
-#include <mLib/alloc.h>
 #include <mLib/bits.h>
 #include <mLib/crc32.h>
 #include <mLib/dstr.h>
 #include <mLib/bits.h>
 #include <mLib/crc32.h>
 #include <mLib/dstr.h>
index 2d9c855..12a5f21 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: key-misc.c,v 1.1 1999/12/22 15:47:48 mdw Exp $
+ * $Id: key-misc.c,v 1.2 2000/02/12 18:21:02 mdw Exp $
  *
  * Simple key management
  *
  *
  * Simple key management
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-misc.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key-misc.c,v $
+ * Revision 1.2  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
  * Revision 1.1  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
@@ -42,7 +45,6 @@
 #include <string.h>
 #include <time.h>
 
 #include <string.h>
 #include <time.h>
 
-#include <mLib/alloc.h>
 #include <mLib/bits.h>
 #include <mLib/hash.h>
 #include <mLib/sub.h>
 #include <mLib/bits.h>
 #include <mLib/hash.h>
 #include <mLib/sub.h>
 
 #define KEY_LOAD(n) ((n) * 2)
 
 
 #define KEY_LOAD(n) ((n) * 2)
 
-/*----- Error reporting ---------------------------------------------------*/
-
-/* --- @key_strerror@ --- *
- *
- * Arguments:  @int err@ = error code from @key_new@
- *
- * Returns:    Pointer to error string.
- *
- * Use:                Translates a @KERR@ error code into a human-readable
- *             string.
- */
-
-const char *key_strerror(int err)
-{
-  char *tab[] = {
-    "No error",
-    "Bad tag string",
-    "Bad type string",
-    "Bad comment string",
-    "Keyid already exists",
-    "Key tag already exists",
-    "Key file is read-only",
-    "Key will eventually expire",
-    "Bad key flags string",
-    "Unknown error code"
-  };
-  
-  unsigned e = -err;
-  if (e >= KERR_MAX)
-    e = KERR_MAX;
- return (tab[e]);
-}
-
 /*----- Iteration and iterators -------------------------------------------*/
 
 /* --- @key_mkiter@ --- *
 /*----- Iteration and iterators -------------------------------------------*/
 
 /* --- @key_mkiter@ --- *
diff --git a/key-text.c b/key-text.c
new file mode 100644 (file)
index 0000000..490b00b
--- /dev/null
@@ -0,0 +1,305 @@
+/* -*-c-*-
+ *
+ * $Id: key-text.c,v 1.1 2000/02/12 18:21:02 mdw Exp $
+ *
+ * Key textual encoding
+ *
+ * (c) 1999 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.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: key-text.c,v $
+ * Revision 1.1  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/base64.h>
+#include <mLib/bits.h>
+#include <mLib/dstr.h>
+#include <mLib/sub.h>
+#include <mLib/sym.h>
+
+#include "key-data.h"
+#include "mp.h"
+#include "mptext.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @key_read@ --- *
+ *
+ * Arguments:  @const char *p@ = pointer to textual key representation
+ *             @key_data *k@ = pointer to output block for key data
+ *             @char **pp@ = where to store the end pointer
+ *
+ * Returns:    Zero if all went well, nonzero if there was a problem.
+ *
+ * Use:                Parses a textual key description.
+ */
+
+int key_read(const char *p, key_data *k, char **pp)
+{
+  unsigned e;
+
+  /* --- Read the encoding type --- *
+   *
+   * The key format is `[FLAGS:]DATA'.  If there is no encoding type
+   * named, assume that it's `binary' for backwards compatibility.
+   */
+
+  if (strchr(p, ':') == 0)
+    e = 0;
+  else {
+    char *q;
+    if (key_readflags(p, &q, &e, 0))
+      return (-1);
+    p = q + 1;
+  }
+
+  /* --- Now scan the data based on the encoding type --- */
+
+  k->e = e;
+  switch (e & KF_ENCMASK) {
+
+    /* --- Binary encoding --- *
+     *
+     * Simply read out the Base64-encoded data.  Since `,' and `]' are our
+     * delimeter characters, and they can't appear in Base64-encoded data, I
+     * can just do a simple search to find the end of the encoded data.
+     */
+
+    case KENC_BINARY:
+    case KENC_ENCRYPT: {
+      dstr d = DSTR_INIT;
+      base64_ctx b;
+      size_t sz = strcspn(p, ",]");
+
+      base64_init(&b);
+      base64_decode(&b, p, sz, &d);
+      base64_decode(&b, 0, 0, &d);
+      k->u.k.k = sub_alloc(d.len);
+      k->u.k.sz = d.len;
+      memcpy(k->u.k.k, d.buf, d.len);
+      dstr_destroy(&d);
+      p += sz;
+    } break;
+
+    /* --- Multiprecision integer encoding --- *
+     *
+     * Multiprecision integers have a convenient reading function.
+     */
+
+    case KENC_MP: {
+      char *q;
+      mp *m = mp_readstring(MP_NEW, p, &q, 0);
+      if (!m)
+       return (-1);
+      if (k->e & KF_BURN)
+       mp_burn(m);
+      k->u.m = m;
+      p = q;
+    } break;
+
+    /* --- Structured information encoding --- *
+     *
+     * The format for structured key data is `[NAME=KEY,...]', where the
+     * brackets are part of the syntax.  Structured keys have no flags apart
+     * from the encoding.
+     *
+     * The binary encoding only allows names up to 255 bytes long.  Check for
+     * this here.
+     */
+
+    case KENC_STRUCT: {
+      dstr d = DSTR_INIT;
+      char *q;
+
+      /* --- Read the opening bracket --- */
+
+      k->e &= KF_ENCMASK;
+      if (*p != '[')
+       return (-1);
+      p++;
+      sym_create(&k->u.s);
+
+      /* --- Read named key subparts --- */
+
+      for (;;) {
+       size_t sz;
+       key_struct *ks;
+
+       /* --- Stop if there's a close-bracket --- *
+        *
+        * This allows `[]' to be an empty structured key, which is good.  It
+        * also makes `[foo=enc:bar,]' legal, and that's less good but I can
+        * live with it.
+        */
+
+       if (*p == ']')
+         break;
+
+       /* --- Read the name out and check the length --- */
+
+       if ((q = strchr(p, '=')) == 0)
+         goto fail;
+       sz = q - p;
+       if (sz >= 256)
+         goto fail;
+       DRESET(&d);
+       DPUTM(&d, p, sz);
+       DPUTZ(&d);
+
+       /* --- Add an appropriate block to the key table --- *
+        *
+        * Simply destroy old data if there's already a match.
+        */
+
+       {
+         unsigned f;
+         ks = sym_find(&k->u.s, d.buf, d.len + 1, sizeof(*ks), &f);
+         if (f)
+           key_destroy(&ks->k);
+       }
+
+       /* --- Read the key data for the subkey --- */
+
+       if (key_read(q + 1, &ks->k, &q)) {
+         sym_remove(&k->u.s, ks);
+         goto fail;
+       }
+       p = q;
+
+       /* --- Read the comma or close-bracket --- */
+
+       if (*p == ']')
+         break;
+       else if (*p == ',')
+         p++;
+       else
+         goto fail;
+      }
+
+      /* --- Step past the close bracket --- */
+
+      p++;
+      dstr_destroy(&d);
+      break;
+
+      /* --- Tidy up after a failure --- */
+
+    fail:
+      dstr_destroy(&d);
+      key_destroy(k);
+      return (-1);
+    } break;
+
+    /* --- Anything else is unknown --- */
+
+    default:
+      return (-1);
+  }
+
+  /* --- Return the end pointer --- */
+
+  if (pp)
+    *pp = (char *)p;
+  return (0);
+}
+
+/* --- @key_write@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data
+ *             @dstr *d@ = destination string to write on
+ *             @const key_filter *kf@ = pointer to key selection block
+ *
+ * Returns:    Nonzero if an item was actually written.
+ *
+ * Use:                Writes a key in a textual encoding.
+ */
+int key_write(key_data *k, dstr *d, const key_filter *kf)
+{
+  int rc = 0;
+  if (!KEY_MATCH(k, kf))
+    return (0);
+  switch (k->e & KF_ENCMASK) {
+    case KENC_BINARY:
+    case KENC_ENCRYPT: {
+      base64_ctx b;
+
+      if ((k->e & KF_ENCMASK) == KENC_BINARY)
+       key_writeflags(k->e, d);
+      else
+       DPUTS(d, "encrypt,secret");
+      DPUTC(d, ':');
+      base64_init(&b);
+      b.indent = "";
+      b.maxline = 0;
+      base64_encode(&b, k->u.k.k, k->u.k.sz, d);
+      base64_encode(&b, 0, 0, d);
+      rc = 1;
+    } break;
+    case KENC_MP:
+      key_writeflags(k->e, d);
+      DPUTC(d, ':');
+      mp_writedstr(k->u.m, d, 10);
+      rc = 1;
+      break;
+    case KENC_STRUCT: {
+      sym_iter i;
+      key_struct *ks;
+      char del = 0;
+      size_t n = d->len;
+
+      DPUTS(d, "struct:[");
+      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
+       size_t o = d->len;
+       if (del)
+         DPUTC(d, del);
+       DPUTS(d, SYM_NAME(ks));
+       DPUTC(d, '=');
+       if (!key_write(&ks->k, d, kf))
+         d->len = o;
+       else {
+         del = ',';
+         rc = 1;
+       }
+      }
+      if (!rc)
+       d->len = n;
+      else
+       DPUTC(d, ']');
+    } break;
+  }
+  DPUTZ(d);
+
+  return (rc);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/key.1 b/key.1
index 95cba9b..2f47eff 100644 (file)
--- a/key.1
+++ b/key.1
@@ -1,4 +1,12 @@
 .\" -*-nroff-*-
 .\" -*-nroff-*-
+.ie t \{\
+.  ds ss \s8\u
+.  ds se \d\s0
+.\}
+.el \{\
+.  ds ss ^
+.  ds se
+.\}
 .TH key 1 "5 June 1999" Catacomb
 .SH NAME
 key \- simple key management system
 .TH key 1 "5 June 1999" Catacomb
 .SH NAME
 key \- simple key management system
@@ -13,33 +21,68 @@ where
 is one of:
 .PP
 .B add
 is one of:
 .PP
 .B add
-.RB [ \-b
+.RB [ \-lq ]
+.RB [ \-a
+.IR alg ]
+.RB [ \-b | \-B
 .IR bits ]
 .IR bits ]
+.RB [ \-p
+.IR param ]
+.RB [ \-r
+.IR tag ]
+.br
+\h'8n'
 .RB [ \-e
 .IR expire ]
 .RB [ \-e
 .IR expire ]
+.RB [ \-t
+.IR tag ]
 .RB [ \-c
 .IR comment ]
 .I type
 .IR attr ...
 .br
 .B expire
 .RB [ \-c
 .IR comment ]
 .I type
 .IR attr ...
 .br
 .B expire
-.IR keyid ...
+.IR tag ...
 .br
 .B delete
 .br
 .B delete
-.IR keyid ...
+.IR tag ...
+.br
+.B tag
+.I tag
+.RI [ new-tag ]
+.br
+.B comment
+.I tag
+.RI [ comment ]
 .br
 .B setattr
 .br
 .B setattr
-.I keyid
+.I tag
 .IR attr ...
 .br
 .IR attr ...
 .br
+.B lock
+.I qtag
+.br
+.B unlock
+.I qtag
+.br
 .B list
 .B list
-.RB [ \-quv ]
+.RB [ \-uqv ]
+.RB [ \-f
+.IR filter ]
+.RI [ tag ...]
+.br
+.B fingerprint
+.RB [ \-f
+.IR filter ]
+.RI [ tag ...]
 .br
 .B tidy
 .br
 .B extract
 .br
 .B tidy
 .br
 .B extract
+.RB [ \-f
+.IR filter ]
 .I file
 .I file
-.IR keyid ...
+.RI [ tag ...]
 .br
 .B merge
 .I file
 .br
 .B merge
 .I file
@@ -86,21 +129,72 @@ report a failure.
 In addition to the actual key data itself, a Catacomb key has a number
 of other pieces of information attached to it:
 .TP
 In addition to the actual key data itself, a Catacomb key has a number
 of other pieces of information attached to it:
 .TP
-.B keyid
-Every key has a 32-bit identifying number, written in hexadecimal.  The
-keyid is derived from the actual key contents (although knowledge of a
-key's keyid doesn't help one to guess the key itself).  Applications use
-keyids to refer to specific keys.  A
+.B "keyid"
+Every key has a 32-bit identifying number, written in hexadecimal.
+Keyids are not actually related to the key contents: they're generated
+randomly.  Applications use keyids to refer to specific keys; users are
+probably better off with tags and types.  A
 .I deleted
 key cannot be looked up by keyid.
 .TP
 .I deleted
 key cannot be looked up by keyid.
 .TP
-.B type
+.B "tag"
+A key's tag is a unique string which can be used by users and
+applications to identify the key.  Tag strings may not contain spaces,
+colons or dots.  A
+.I deleted
+key cannot be looked up by tag.  Whenever a tag name is wanted, a hex
+keyid or key type string can be given instead.
+.TP
+.B "type"
 A key's type string describes what the key may be used for.  The type
 string is arbitrary, except that it may not contain whitespace
 A key's type string describes what the key may be used for.  The type
 string is arbitrary, except that it may not contain whitespace
-characters.  Applications use key types to obtain an arbitrary but
-suitable key for some purpose.  An
+characters, dots or colons.  Applications use key types to obtain an
+arbitrary but suitable key for some purpose.  An
 .I expired
 .I expired
-key cannot be looked up by type, but may be looked up by keyid.
+key cannot be looked up by type, but may be looked up by keyid or tag.
+.TP
+.B "key encoding"
+There are a number of different ways in which keys can be represented,
+according to the uses to which the key will be put.  Most symmetric
+algorithms use
+.I binary
+keys.  Keys used with number-theoretic systems (like most common
+public-key systems) use
+.I "multiprecision integer"
+keys.  Algorithms which require several key constituents (again, like
+most public-key systems) use
+.I structured
+keys, which consist of a collection of named parts.  Finally, keys
+(including structured keys) can be encrypted.
+.TP
+.B "filter"
+Keys and key components may be selected by a filter expression, a
+sequence of flag names separated by commas.  Flags are:
+.BR binary ,
+.BR integer ,
+.B struct
+or
+.B encrypt
+(describing the key encoding);
+.BR symmetric ,
+.BR private ,
+.B public
+or
+.B shared
+(describing the category of key);
+.B burn
+and its negation
+.B \-burn
+(whether the key should be erased from memory after use); and
+.B secret
+and its negation
+.B \-secret
+(whether the key is safe to divulge).
+.TP
+.B "qualified tag"
+A key component may be identified by the key's tag (or keyid, or type).
+Subcomponents of structured keys are identified by following the tag by
+a dot and the name of the subcomponent.
 .TP
 .B "expiry time"
 Most keys expire after a certain amount of time.  Once a key has
 .TP
 .B "expiry time"
 Most keys expire after a certain amount of time.  Once a key has
@@ -112,19 +206,17 @@ reached.
 A key's deletion time is the latest expiry time of any of the objects
 which require that key.  For example, a key used for authenticating
 cryptographic cookies should have its deletion time set to the longest
 A key's deletion time is the latest expiry time of any of the objects
 which require that key.  For example, a key used for authenticating
 cryptographic cookies should have its deletion time set to the longest
-expiry time of any of the cookies it can authenticate.  A key is never
-deleted until it has also expired.  Once a key has expired
-.I and
-its deletion time is passed, it can no longer be referred to by
+expiry time of any of the cookies it can authenticate.  Once a key's
+deletion time is passed, it can no longer be referred to by
 applications, and will be removed from the keyring next time it's
 written to disk.
 .TP
 applications, and will be removed from the keyring next time it's
 written to disk.
 .TP
-.B comment
+.B "comment"
 A key may be given a comment when it's created.  The comment is for the
 benefit of users, and isn't interpreted by applications at all.
 (Hopefully.)
 .TP
 A key may be given a comment when it's created.  The comment is for the
 benefit of users, and isn't interpreted by applications at all.
 (Hopefully.)
 .TP
-.B attributes
+.B "attributes"
 A key as zero or more name/value pairs.  The names and values are
 arbitrary strings, except they may not contain null bytes.  Some
 attributes may have meaning for particular applications or key types;
 A key as zero or more name/value pairs.  The names and values are
 arbitrary strings, except they may not contain null bytes.  Some
 attributes may have meaning for particular applications or key types;
@@ -136,10 +228,22 @@ The
 command creates a new key and adds it to the keyring.  The command
 accepts the following options:
 .TP
 command creates a new key and adds it to the keyring.  The command
 accepts the following options:
 .TP
+.BI "\-a, \-\-algorithm " alg
+Selects a key generation algorithm.  The default algorithm is
+.BR binary ;
+the different algorithms are described below.
+.TP
 .BI "\-b, \-\-bits " bits
 The length of the key to generate, in bits.  The default, if this option
 .BI "\-b, \-\-bits " bits
 The length of the key to generate, in bits.  The default, if this option
-is not supplied, is 128 bits.  The bit length must be nonzero, and must
-be a multiple of 8.
+is not supplied, depends on the key-generation algorithm.
+.TP
+.BI "\-B, \-\-qbits " bits
+The length of the subsidiary key or parameter, in bits.  Not all
+key-generation algorithms have a subsidiary key size.
+.TP
+.BI "\-p, \-\-parameters " tag
+Selects a key containing parameter values to copy.  Not all
+key-generation algorithms allow the use of shared parameters.
 .TP
 .BI "\-e, \-\-expire " expire
 The expiry date for the generated key.  This may be the string
 .TP
 .BI "\-e, \-\-expire " expire
 The expiry date for the generated key.  This may be the string
@@ -159,6 +263,28 @@ The default is to allow a 2 week expiry, which isn't useful.
 .TP
 .BI "\-c, \-\-comment " comment
 Sets a comment for the key.  The default is not to attach a comment.
 .TP
 .BI "\-c, \-\-comment " comment
 Sets a comment for the key.  The default is not to attach a comment.
+.TP
+.BI "\-t, \-\-tag " tag
+Selects a tag string for the key.  The default is not to set a tag.  It
+is an error to select a tag which already exists.
+.TP
+.BI "\-r, \-\-rand-id " tag
+Selects the key to use for the random number generator.  Catacomb's
+random number generator can be
+.IR keyed ,
+so that, even if the inputs to the generator are compromised, knowledge
+of the key is also necessary to be able to predict the output.  By
+default, the latest-expiring key with type
+.B catacomb-rand
+is used, if present; if not, no key is used.
+.TP
+.BI "\-l, \-\-lock"
+Requests that the secret parts of the newly-generated key be encrypted
+using a passphrase.
+.TP
+.BI "\-q, \-\-quiet"
+Suppresses the progress indication which is usually generated while
+time-consuming key generation tasks are being performed.
 .PP
 The key's type is given by the required
 .I type
 .PP
 The key's type is given by the required
 .I type
@@ -167,36 +293,236 @@ attached to the key in the same way as for the
 .B setattr
 command.
 .PP
 .B setattr
 command.
 .PP
-The
-.B key
-program only generates random bitstrings, which are suitable for most
-symmetric algorithms but not for public key cryptography.  Generating
-keys for more exotic algorithms is a feature which will be added later.
-The keys are generated using the Catacomb random number generator, using
-the
-.B rand_goodbits
-function.  The Catacomb generator is believed to be strong.
-.SS expire
+The key-generation algorithms supported are as follows:
+.TP
+.B "binary"
+Generates a plain binary key of the requested length.  If the requested
+key length is not a multiple of eight, the high-order bits of the first
+octet of the key are zeroed.  The default key length is 128 bits.
+.TP
+.B "des"
+Generates a DES key, with parity bits.  The key length must be 56, 112
+or 168; the default is 56.  The low-order bit of each octet is ignored by
+the DES algorithm; it is used to give each octet odd parity.
+.TP
+.B "rsa"
+Generates a public/private key pair for use with the RSA algorithm.
+.IP
+The key components are
+.I p
+and
+.IR q ,
+a pair of prime numbers;
+.IR n ,
+the product of
+.I p
+and
+.IR q ;
+.IR e ,
+the public exponent;
+.IR d ,
+the private exponent, chosen such that
+.IR ed \ \(==\ 1
+(mod
+.RI ( p \ \-\ 1)( q \ \-\ 1));
+and some other values useful for optimizing private-key operations:
+.IR q \*(ss\-1\*(se\ mod\  p ,
+.IR d \ mod\  p \ \-\ 1,
+and
+.IR d \ mod\  q \ \-\ 1.
+The values
+.I n
+and
+.I e
+constitute the public key; the rest must be kept secret.  The key size
+requested by the
+.B \-b
+option determines the size of the modulus
+.IR n ;
+the default is 1024 bits.
+.IP
+The key generation algorithm chooses
+.I p
+and
+.I q
+to be
+.I strong
+primes: both
+.IR p \ \-\ 1
+and
+.IR p \ +\ 1
+have large prime factors \- call them
+.I r
+and
+.I s
+respectively \- and
+.IR r \ \-\ 1
+also has a large prime factor;
+.I q
+has similar properties.
+.IP
+The modulus
+.I n
+cannot be sensibly used as a shared parameter, since knowledge of
+corrssponding public and private exponents is sufficient to be able to
+factor the modulus and recover other users' private keys.
+.TP
+.B "dh-params"
+Generates parameters for use with the Diffie-Hellman key exchange
+protocol, and many related systems, such as ElGamal encryption and
+signatures, and even DSA (although the DSA algorithm is probably better
+for this).  The parameters are a prime number
+.IR q ,
+a larger prime number
+.IR p ,
+and a generator
+.I g
+of the
+.RI order- q
+subgroup of the integers
+.RI mod\  p .
+.IP
+The key size set by the
+.B \-b
+option determines the size of the modulus
+.IR p ;
+the size of the generator order
+.I q
+is set by the
+.B \-B
+option.  The default modulus size is 1024 bits; if no size is specified
+for
+.IR q ,
+the parameters are chosen such that
+.IR p \ =\ 2 q \ +\ 1,
+and
+.I
+g
+is assigned the value 4.  This takes much longer.
+.IP
+If used with the
+.B \-p
+option, the algorithm simply copies the parameters from an existing key.
+.TP
+.B "dh"
+Generates a public/private key pair for use with offline Diffie-Hellman,
+ElGamal, DSA or similar discrete-logarithm-based systems.  It selects a
+private key
+.IR x \ <\  q ,
+and computes the public key
+.IR y \ =\  g\*(ssx\*(se \ mod\  p .
+.TP
+.B "dsa-param"
+Generates parameters for the DSA algorithm.  DSA parameters are also
+suitable for use with Diffie-Hellman and ElGamal system.
+.IP
+The main difference between DSA and Diffie-Hellman parameter generation
+is thatthe DSA parameter generation
+algorithm creates a
+.I seed
+from which the parameters are derived, and, assuming that the SHA-1 hash
+function is strong, it's not feasible to construct a seed from which
+deliberately weak parameters are derived.  The algorithm used is the one
+described in the DSA standard, FIPS\ 186, extended only to allow
+sequential search for a prime
+.I q
+and to allow arbitrary parameter sizes.  The seed is stored,
+Base64-encoded, as the value of the attribute
+.BR seed .
+.IP
+The default lengths for
+.I p
+and
+.I q
+are 768 and 160 bits respectively, since the DSA standard specifies that
+.I q
+be 160 bits, and the choice of 768 bits for
+.I p
+gives commensurate security.
+.TP
+.B "dsa"
+Generates a public/private key pair for DSA.  As for Diffie-Hellman
+keys, it selects a
+private key
+.IR x \ <\  q ,
+and computes the public key
+.IR y \ =\  g\*(ssx\*(se \ mod\  p .
+.TP
+.B "bbs"
+Generates a public/private key pair for the Blum-Blum-Shub random-number
+generator, and the Blum-Goldwasser semantically-secure public-key
+encryption system.
+.IP
+The key components are prime numbers
+.I p
+and
+.IR q ,
+both congruent to 3 (mod\ 4), and their product
+.IR n .
+The public key is simply the modulus
+.IR n ;
+the factors
+.I p
+and
+.I q
+are the private key.
+.IP
+The key-generation algorithm ensures that the two primes
+.I p
+and
+.I q
+are
+.I strong
+(see the discussion of strong primes above, in the section on RSA keys),
+and that
+.RI ( p \ \-\ 1)/2
+and
+.RI ( q \ \-\ 1)/2
+are relatively prime, giving a maximum possible period length.
+.IP
+The key size requested by the
+.B \-b
+option determines the length of the modulus
+.IR n ;
+the default length is 1024 bits.
+.SS "expire"
 Forces keys to immediately expire.  An expired key is not chosen when a
 program requests a key by its type.  The keys to expire are listed by
 their
 Forces keys to immediately expire.  An expired key is not chosen when a
 program requests a key by its type.  The keys to expire are listed by
 their
-.IR keyid s.
-.SS delete
+.IR tag s.
+.SS "delete"
 Deletes keys immediately.  The keys to delete are listed by their
 Deletes keys immediately.  The keys to delete are listed by their
-.IR keyid s.
+.IR tag s.
 Be careful when deleting keys.  It might be a better idea
 to expire keys rather than deleting them.
 Be careful when deleting keys.  It might be a better idea
 to expire keys rather than deleting them.
-.SS setattr
+.SS "tag"
+Sets, deletes or changes the tag attached to a key.  The first tag or
+keyid names the key to be modified; the second, if present specifies the
+new tag to be set.  If no second argument is given, the existing tag, if
+any, is removed and no new tag is set.
+.SS "setattr"
 Attaches attributes to a key.  The key to which the attributes should be
 attached is given by its
 Attaches attributes to a key.  The key to which the attributes should be
 attached is given by its
-.IR keyid .
+.IR tag .
 Each attribute has the form
 .IB name = value\fR.
 An attribute can be deleted by assigning it an empty value.  Although
 the keyring file format is capable of representing an attribute with an
 empty value as distinct from a nonexistant attribute, this interface
 does not allow empty attributes to be set.
 Each attribute has the form
 .IB name = value\fR.
 An attribute can be deleted by assigning it an empty value.  Although
 the keyring file format is capable of representing an attribute with an
 empty value as distinct from a nonexistant attribute, this interface
 does not allow empty attributes to be set.
-.SS list
+.SS "comment"
+Sets, deletes or changes the comment attached to a key.  The first
+argument is a key tag or keyid which names the key to be modified; the
+second, if present, is the new comment.  If no second argument is given,
+the existing comment, if any, is removed, and no new comment is set.
+.SS "lock"
+Locks a key or key component using a passphrase.  If the key is already
+locked, the existing passphrase is requested, and a new passphrase is
+set.
+.SS "unlock"
+Unlocks a passphrase-locked key or key component.  If the key is not
+locked, an error is reported.
+.SS "list"
 Lists the keys in the keyring.  A couple of options are supported:
 .TP
 .B "\-v, \-\-verbose"
 Lists the keys in the keyring.  A couple of options are supported:
 .TP
 .B "\-v, \-\-verbose"
@@ -211,24 +537,48 @@ option.
 .TP
 .B "\-u, \-\-utc"
 Display key expiry times as UTC rather than using the local time zone.
 .TP
 .B "\-u, \-\-utc"
 Display key expiry times as UTC rather than using the local time zone.
+.TP
+.BI "\-f, \-\-filter " filter
+Specifies a filter.  Only keys and key components which match the filter
+are listed.
 .PP
 By default, a single line of output is generated for each, showing
 keyids, types, expiry and deletion dates, and comments.  Additional
 .RB ` \-v '
 options show more information, such as the exact time of day for expiry
 .PP
 By default, a single line of output is generated for each, showing
 keyids, types, expiry and deletion dates, and comments.  Additional
 .RB ` \-v '
 options show more information, such as the exact time of day for expiry
-and deletion, key attributes, and a hex dump of the actual key data.
-.SS tidy
+and deletion, key attributes, and a dump of the actual key data.  If the
+verbosity level is sufficiently high, passphrases are requested to
+decrypt locked keys.  Make sure nobody is looking over your shoulder
+when you do this!
+.SS "fingerprint"
+Reports a fingerprint (secure hash) on components of requested keys.
+The following option is supported:
+.TP
+.BI "\-f, \-\-filter " filter
+Specifies a filter.  Only keys and key components which match the filter
+are fingerprinted.  The default is to only fingerprint nonsecret
+components.
+.PP
+The keys to be fingerprinted are named by their tags or keyids given as
+command line arguments.  If no key tags are given, all keys which match
+the filter are fingerprinted.
+.SS "tidy"
 Simply reads the keyring from file and writes it back again.  This has
 the effect of removing any deleted keys from the file.
 Simply reads the keyring from file and writes it back again.  This has
 the effect of removing any deleted keys from the file.
-.SS extract
-Writes a selection of keys to the named
-.IR file ,
+.SS "extract"
+Writes a selection of keys to a file.  An option is supported:
+.TP
+.BI "\-f, \-\-filter " filter
+Specifies a filter.  Only keys and key components which match the filter
+are written.
+.PP
+Keys extracted are written to the file named by the first argument,
 which may be
 .RB ` \- '
 to designate standard output.  The keys to extract are listed by their
 which may be
 .RB ` \- '
 to designate standard output.  The keys to extract are listed by their
-.IR keyid s.
-The output is a valid keyring file.
-.SS merge
+tags; if no tags are given, all keys which match the filter are
+extracted.  The output is a valid keyring file.
+.SS "merge"
 Merges the keys from the named
 .IR file ,
 which may be
 Merges the keys from the named
 .IR file ,
 which may be
@@ -236,11 +586,6 @@ which may be
 to designate standard input, with the keyring.  Keys already in the
 keyring are not overwritten: you must explicitly remove them first if
 you want them to be replaced during the merge.
 to designate standard input, with the keyring.  Keys already in the
 keyring are not overwritten: you must explicitly remove them first if
 you want them to be replaced during the merge.
-.SH BUGS
-The ability to generate keys for specific algorithms ought to be added,
-for DES (setting the parity bits correctly), RSA, ElGamal and DSA, at
-the very least.  (None of these systems are actually implemented in
-Catacomb at the moment, however.)
 .SH "SEE ALSO"
 .BR keyring (5).
 .SH AUTHOR
 .SH "SEE ALSO"
 .BR keyring (5).
 .SH AUTHOR
diff --git a/key.h b/key.h
index 6a17ded..d779489 100644 (file)
--- a/key.h
+++ b/key.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: key.h,v 1.3 1999/12/22 15:47:48 mdw Exp $
+ * $Id: key.h,v 1.4 2000/02/12 18:21:02 mdw Exp $
  *
  * Simple key management
  *
  *
  * Simple key management
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key.h,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: key.h,v $
+ * Revision 1.4  2000/02/12 18:21:02  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.3  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
  * Revision 1.3  1999/12/22 15:47:48  mdw
  * Major key-management revision.
  *
 #include <mLib/hash.h>
 #include <mLib/sym.h>
 
 #include <mLib/hash.h>
 #include <mLib/sym.h>
 
+#ifndef CATACOMB_KEY_DATA_H
+#  include "key-data.h"
+#endif
+
 #ifndef CATACOMB_MP_H
 #  include "mp.h"
 #endif
 #ifndef CATACOMB_MP_H
 #  include "mp.h"
 #endif
@@ -76,99 +83,6 @@ typedef struct key_attr {
   char *p;                             /* Pointer to attribute value */
 } key_attr;
 
   char *p;                             /* Pointer to attribute value */
 } key_attr;
 
-/* --- Key data structure --- */
-
-typedef struct key_data {
-  unsigned e;                          /* Encoding type for key data */
-  union {
-
-    /* --- Plain binary key data --- *
-     *
-     * Also used for encrypted key types.
-     */
-
-    struct {
-      octet *k;                                /* Actual key data */
-      size_t sz;                       /* Size of the key data */
-    } k;                               /* Plain binary key */
-
-    /* --- Multiprecision integer keys --- */
-
-    mp *m;                             /* Multiprecision integer */
-
-    /* --- Structured key data --- */
-
-    sym_table s;                       /* Structured key data */
-  } u;
-} key_data;
-
-typedef struct key_struct {
-  sym_base _b;
-  key_data k;
-} key_struct;
-
-/* --- Key binary encoding --- *
- *
- * The binary encoding consists of a header containing a 16-bit encoding type
- * and a 16-bit length, followed immediately by the key data, followed by
- * between zero and three zero bytes to make the total length a multiple of
- * four.  The format of the following data depends on the encoding type:
- *
- * @KENC_BINARY@       Binary data.
- *
- * @KENC_MP@           Octet array interpreted in big-endian byte order.
- *
- * @KENC_STRUCT@       An array of pairs, each containing a string (8-bit
- *                     length followed by data and zero-padding to 4-byte
- *                     boundary) and key binary encodings.
- *
- * @KENC_ENCRYPT@      Binary data, format
- */
-
-/* --- Key encoding methods and other flags--- */
-
-enum {
-
-  /* --- Bottom two bits are the encoding type --- */
-
-  KF_ENCMASK   = 0x03,                 /* Encoding mask */
-  KENC_BINARY  = 0x00,                 /* Plain binary key (@k@) */
-  KENC_MP      = 0x01,                 /* Multiprecision integer (@i@) */
-  KENC_STRUCT  = 0x02,                 /* Structured key data (@s@) */
-  KENC_ENCRYPT = 0x03,                 /* Encrypted key type (@k@) */
-
-  /* --- Key category bits --- */
-
-  KF_CATMASK   = 0x0c,                 /* Category mask */
-  KCAT_SYMM    = 0x00,                 /* Symmetric encryption key */
-  KCAT_PRIV    = 0x04,                 /* Private (asymmetric) key */
-  KCAT_PUB     = 0x08,                 /* Public (asymmetric) key */
-  KCAT_SHARE   = 0x0c,                 /* Shared (asymmetric) key */
-  KF_NONSECRET = 0x08,                 /* Bit flag for non-secret keys */
-
-  /* --- Other flags --- */
-
-  KF_BURN      = 0x10,                 /* Burn key after use */
-
-  /* --- Tag end --- */
-
-  KENC_MAX                             /* Dummy limit constant */
-};
-
-/* --- Key flag filtering --- */
-
-typedef struct key_filter {
-  unsigned f;
-  unsigned m;
-} key_filter;
-
-/* --- Matching aginst key selection --- */
-
-#define KEY_MATCH(kd, kf)                                              \
-  (!(kf) ||                                                            \
-   ((kd)->e & KF_ENCMASK) == KENC_STRUCT ||                            \
-   ((kd)->e & (kf)->m) == (kf)->f)
-
 /* --- Main key structure --- *
  *
  * Each key is stored in two symbol tables, one indexed by keyid, and the
 /* --- Main key structure --- *
  *
  * Each key is stored in two symbol tables, one indexed by keyid, and the
@@ -250,7 +164,7 @@ enum {
 /* --- Key error codes --- */
 
 enum {
 /* --- Key error codes --- */
 
 enum {
-  KERR_OK,                             /* No error */
+  KERR_OK = 0,                         /* No error */
   KERR_BADTAG = -1,                    /* Malformed tag string */
   KERR_BADTYPE = -2,                   /* Malformed type string */
   KERR_BADCOMMENT = -3,                        /* Malformed comment string */
   KERR_BADTAG = -1,                    /* Malformed tag string */
   KERR_BADTYPE = -2,                   /* Malformed type string */
   KERR_BADCOMMENT = -3,                        /* Malformed comment string */
@@ -260,6 +174,9 @@ enum {
   KERR_WILLEXPIRE = -7,                        /* Key will eventually expire */
   KERR_EXPIRED = -8,                   /* Key has already expired */
   KERR_BADFLAGS = -9,                  /* Error in flags string */
   KERR_WILLEXPIRE = -7,                        /* Key will eventually expire */
   KERR_EXPIRED = -8,                   /* Key has already expired */
   KERR_BADFLAGS = -9,                  /* Error in flags string */
+  KERR_BADPASS = -10,                  /* Error decrypting locked key */
+  KERR_BADTYPE = -11,                  /* Key has incorrect type */
+  KERR_NOTFOUND = -12,                 /* Key couldn't be found */
   KERR_MAX                             /* Largest possible error */
 };
 
   KERR_MAX                             /* Largest possible error */
 };
 
@@ -281,244 +198,6 @@ typedef void key_reporter(const char */*file*/, int /*line*/,
 #define KEY_EXPIRED(now, exp)                                          \
   ((exp) == KEXP_EXPIRE || ((exp) != KEXP_FOREVER && (exp) < (now)))
 
 #define KEY_EXPIRED(now, exp)                                          \
   ((exp) == KEXP_EXPIRE || ((exp) != KEXP_FOREVER && (exp) < (now)))
 
-/*----- Key data manipulation ---------------------------------------------*/
-
-/* --- @key_destroy@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data to destroy
- *
- * Returns:    ---
- *
- * Use:                Destroys a lump of key data.
- */
-
-extern void key_destroy(key_data */*k*/);
-
-/* --- @key_readflags@ --- *
- *
- * Arguments:  @const char *p@ = pointer to string to read
- *             @char **pp@ = where to store the end pointer
- *             @unsigned *ff@ = where to store the flags
- *             @unsigned *mm@ = where to store the mask
- *
- * Returns:    Zero if all went well, nonzero if there was an error.
- *
- * Use:                Reads a flag string.
- */
-
-extern int key_readflags(const char */*p*/, char **/*pp*/,
-                        unsigned */*ff*/, unsigned */*mm*/);
-
-/* --- @key_writeflags@ --- *
- *
- * Arguments:  @unsigned f@ = flags to write
- *             @dstr *d@ = pointer to destination string
- *
- * Returns:    ---
- *
- * Use:                Emits a flags word as a string representation.
- */
-
-extern void key_writeflags(unsigned /*f*/, dstr */*d*/);
-
-/* --- @key_binary@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const void *p@ = pointer to key data
- *             @size_t sz@ = size of the key data
- *
- * Returns:    ---
- *
- * Use:                Sets a binary key in a key data block.
- */
-
-extern void key_binary(key_data */*k*/, const void */*p*/, size_t /*sz*/);
-
-/* --- @key_encrypted@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const void *p@ = pointer to key data
- *             @size_t sz@ = size of the key data
- *
- * Returns:    ---
- *
- * Use:                Sets an encrypted key in a key data block.
- */
-
-extern void key_encrypted(key_data */*k*/, const void */*p*/, size_t /*sz*/);
-
-/* --- @key_mp@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @mp *m@ = pointer to the value to set
- *
- * Returns:    ---
- *
- * Use:                Sets a multiprecision integer key in a key block.
- */
-
-extern void key_mp(key_data */*k*/, mp */*m*/);
-
-/* --- @key_structure@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *
- * Returns:    ---
- *
- * Use:                Initializes a structured key type.
- */
-
-extern void key_structure(key_data */*k*/);
-
-/* --- @key_structfind@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const char *tag@ = pointer to tag string
- *
- * Returns:    Pointer to key data block, or null.
- *
- * Use:                Looks up the tag in a structured key.
- */
-
-extern key_data *key_structfind(key_data */*k*/, const char */*tag*/);
-
-/* --- @key_structcreate@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const char *tag@ = pointer to tag string
- *
- * Returns:    Pointer to newly created key data.
- *
- * Use:                Creates a new uninitialized subkey.
- */
-
-extern key_data *key_structcreate(key_data */*k*/, const char */*tag*/);
-
-/* --- @key_match@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const key_filter *kf@ = pointer to filter block
- *
- * Returns:    Nonzero if the key matches the filter.
- *
- * Use:                Checks whether a key matches a filter.
- */
-
-extern int key_match(key_data */*k*/, const key_filter */*kf*/);
-
-/* --- @key_do@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const key_filter *kf@ = pointer to filter block
- *             @dstr *d@ = pointer to base string
- *             @int (*func)(key_data *kd, dstr *d, void *p@ = function
- *             @void *p@ = argument to function
- *
- * Returns:    Nonzero return code from function, or zero.
- *
- * Use:                Runs a function over all the leaves of a key. 
- */
-
-extern int key_do(key_data */*k*/, const key_filter */*kf*/, dstr */*d*/,
-                 int (*/*func*/)(key_data */*kd*/,
-                                 dstr */*d*/, void */*p*/),
-                 void */*p*/);
-
-/* --- @key_copy@ --- *
- *
- * Arguments:  @key_data *kd@ = pointer to destination data block
- *             @key_data *k@ = pointer to source data block
- *             @const key_filter *kf@ = pointer to filter block
- *
- * Returns:    Nonzero if an item was actually copied.
- *
- * Use:                Copies a chunk of key data from one place to another.
- */
-
-extern int key_copy(key_data */*kd*/, key_data */*k*/,
-                   const key_filter */*kf*/);
-
-/* --- @key_read@ --- *
- *
- * Arguments:  @const char *p@ = pointer to textual key representation
- *             @key_data *k@ = pointer to output block for key data
- *             @char **pp@ = where to store the end pointer
- *
- * Returns:    Zero if all went well, nonzero if there was a problem.
- *
- * Use:                Parses a textual key description.
- */
-
-extern int key_read(const char */*p*/, key_data */*k*/, char **/*pp*/);
-
-/* --- @key_write@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data
- *             @dstr *d@ = destination string to write on
- *             @const key_filter *kf@ = pointer to key selection block
- *
- * Returns:    Nonzero if any items were actually written.
- *
- * Use:                Writes a key in a textual encoding.
- */
-
-extern int key_write(key_data */*k*/, dstr */*d*/,
-                     const key_filter */*kf*/);
-
-/* --- @key_decode@ --- *
- *
- * Arguments:  @const void *p@ = pointer to buffer to read
- *             @size_t sz@ = size of the buffer
- *             @key_data *k@ = pointer to key data block to write to
- *
- * Returns:    Zero if everything worked, nonzero otherwise.
- *
- * Use:                Decodes a binary representation of a key.
- */
-
-extern int key_decode(const void */*p*/, size_t /*sz*/, key_data */*k*/);
-
-/* --- @key_encode@ --- *
- *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @dstr *d@ = pointer to destination string
- *             @const key_filter *kf@ = pointer to key selection block
- *
- * Returns:    Nonzero if any items were actually written.
- *
- * Use:                Encodes a key block as binary data.
- */
-
-extern int key_encode(key_data */*k*/, dstr */*d*/,
-                     const key_filter */*kf*/);
-
-/* --- @key_plock@ --- *
- *
- * Arguments:  @const char *tag@ = tag to use for passphrase
- *             @key_data *k@ = source key data block
- *             @key_data *kt@ = target key data block
- *
- * Returns:    Zero if successful, nonzero if there was a problem.
- *
- * Use:                Locks a key by encrypting it with a passphrase.
- */
-
-extern int key_plock(const char */*tag*/, key_data */*k*/, key_data */*kt*/);
-
-/* --- @key_punlock@ --- *
- *
- * Arguments:  @const char *tag@ = tag to use for passphrase
- *             @key_data *k@ = source key data block
- *             @key_data *kt@ = target key data block
- *
- * Returns:    Zero if it worked, nonzero if it didn't.
- *
- * Use:                Unlocks a passphrase-locked key.
- */
-
-extern int key_punlock(const char */*tag*/,
-                      key_data */*k*/, key_data */*kt*/);
-
 /*----- Reading and writing keys and files --------------------------------*/
 
 /* --- @key_merge@ --- *
 /*----- Reading and writing keys and files --------------------------------*/
 
 /* --- @key_merge@ --- *
index b6b1bf9..673f4ea 100644 (file)
--- a/keyutil.c
+++ b/keyutil.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-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
  *
  *
  * Simple key manager program
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: keyutil.c,v $
 /*----- 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.
  * 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 <rand.h>
 
 #include "bbs.h"
+#include "dh.h"
 #include "dsa.h"
 #include "fibrand.h"
 #include "getdate.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))
 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@ --- *
 }
 
 /* --- @doclose@ --- *
@@ -268,6 +272,58 @@ static mp *getmp(key_data *k, const char *tag)
   return (k->u.m);
 }
 
   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)
 /* --- 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++) {
   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 >> 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);
     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");
   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 void alg_dhparam(keyopts *k)
 {
-  static const char *pl[] = { "p", "g", 0 };
+  static const char *pl[] = { "p", "q", "g", 0 };
   if (!copyparam(k, pl)) {
   if (!copyparam(k, pl)) {
-    pgen_safetestctx c;
-    mp *p, *q;
+    dh_param dp;
     key_data *kd = &k->k->k;
 
     if (!k->bits)
     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 --- */
 
 
     /* --- 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);
       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;
   }    
 }
 
 static void alg_dh(keyopts *k)
 {
   mp *x, *y;
-  mp *p, *g;
+  mp *p, *q, *g;
   mpmont mm;
   key_data *kd = &k->k->k;
 
   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");
 
   alg_dhparam(k);
   p = getmp(kd, "p");
+  q = getmp(kd, "q");
   g = getmp(kd, "g");
 
   /* --- Choose a suitable private key --- *
   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$%.
    */
 
    * 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);
   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 --- */
   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");
   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;
 }
 
 static void alg_bbs(keyopts *k)
 {
   bbs_param bp;
   key_data *kd;
-  mp *p, *q;
 
   /* --- Sanity checking --- */
 
 
   /* --- Sanity checking --- */
 
@@ -564,12 +611,9 @@ static void alg_bbs(keyopts *k)
 
   /* --- Generate the BBS parameters --- */
 
 
   /* --- 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");
     die(EXIT_FAILURE, "Blum-Blum-Shub key generation failed");
-  mp_drop(p); mp_drop(q);
 
   /* --- Allrighty then --- */
 
 
   /* --- 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 *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 --- */
   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' },
       { "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 }
     };
       { "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;
 
     if (i < 0)
       break;
 
@@ -720,6 +766,9 @@ static int cmd_add(int argc, char *argv[])
 
       /* --- Other flags --- */
 
 
       /* --- Other flags --- */
 
+      case 'r':
+       rtag = optarg;
+       break;
       case 'l':
        k.f |= f_lock;
        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;
 
   doopen(&f, KOPEN_WRITE);
   k.kf = &f;
 
+  /* --- Key the generator --- */
+
+  keyrand(&f, rtag);
+
   for (;;) {
     uint32 id = rand_global.ops->word(&rand_global);
     int err;
   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@ --- */
 
 
 /* --- @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;
 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;
 
   dstr d = DSTR_INIT;
   int i;
 
-  if (!key_match(&k->k, kf))
+  if (!key_encode(&k->k, &d, kf))
     return;
   rmd160_init(&r);
     return;
   rmd160_init(&r);
-  key_do(&k->k, kf, 0, fpkey, &r);
+  rmd160_hash(&r, d.buf, d.len);
   rmd160_done(&r, hash);
   rmd160_done(&r, hash);
-  
+
+  DRESET(&d);
   key_fulltag(k, &d);
   for (i = 0; i < sizeof(hash); i++) {
     if (i && i % 4 == 0)
   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\
 } 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..." },
                 [-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" },
   { "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 }
 };
   { "merge", cmd_merge, "merge file" },
   { 0, 0, 0 }
 };
@@ -1506,12 +1540,12 @@ typedef struct cmd cmd;
 
 void usage(FILE *fp)
 {
 
 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)
 {
 }
 
 void version(FILE *fp)
 {
-  fprintf(fp, "%s, Catacomb version " VERSION "\n", QUIS);
+  pquis(fp, "$, Catacomb version " VERSION "\n");
 }
 
 void help(FILE *fp)
 }
 
 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\
 -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);
 \n\
 The following commands are understood:\n\n",
        fp);
@@ -1559,11 +1595,6 @@ int main(int argc, char *argv[])
   ego(argv[0]);
   sub_init();
 
   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 (;;) {
   /* --- Parse command line options --- */
 
   for (;;) {
@@ -1578,12 +1609,14 @@ int main(int argc, char *argv[])
       /* --- Real live useful options --- */
 
       { "keyring",     OPTF_ARGREQ,    0,      'k' },
       /* --- 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 }
     };
 
       /* --- 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;
 
     if (i < 0)
       break;
@@ -1621,6 +1654,11 @@ int main(int argc, char *argv[])
     exit(1);
   }
 
     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;
   /* --- Dispatch to appropriate command handler --- */
 
   argc -= optind;
index 32b91e3..a8c5ac7 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: pgen-safe.c,v 1.1 1999/12/22 16:01:34 mdw Exp $
+ * $Id: pgen-safe.c,v 1.2 2000/02/12 18:21:03 mdw Exp $
  *
  * Safe prime generation
  *
  *
  * Safe prime generation
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: pgen-safe.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: pgen-safe.c,v $
+ * Revision 1.2  2000/02/12 18:21:03  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.1  1999/12/22 16:01:34  mdw
  * Find `safe' primes (i.e., %$p = 2q + 1$%).
  *
  * Revision 1.1  1999/12/22 16:01:34  mdw
  * Find `safe' primes (i.e., %$p = 2q + 1$%).
  *
 int pgen_safestep(int rq, pgen_event *ev, void *p)
 {
   pgen_safestepctx *c = p;
 int pgen_safestep(int rq, pgen_event *ev, void *p)
 {
   pgen_safestepctx *c = p;
-  int prc = PGEN_ABORT, qrc;
+  int rc = PGEN_ABORT, qrc = 0;
 
   switch (rq) {
 
   switch (rq) {
+
+    /* --- Set up the contexts --- */
+
     case PGEN_BEGIN: {
       mp *p = mp_split(MP_COPY(ev->m));
       mp *q;
       p->v[0] |= 3;
       q = mp_lsr(MP_NEW, p, 1);
     case PGEN_BEGIN: {
       mp *p = mp_split(MP_COPY(ev->m));
       mp *q;
       p->v[0] |= 3;
       q = mp_lsr(MP_NEW, p, 1);
+      rc = pfilt_create(&c->p, p);
       qrc = pfilt_create(&c->q, q);
       qrc = pfilt_create(&c->q, q);
-      prc = pfilt_create(&c->p, p);
-      mp_drop(p);
-      mp_drop(q);
-    } goto step;
+      mp_drop(p); mp_drop(q);
+    } break;
+
+    /* --- Step along --- */
+
     case PGEN_TRY:
     case PGEN_TRY:
-    again:
-      qrc = pfilt_step(&c->q, 2);
-      prc = pfilt_step(&c->p, 4);
-    step:
-      if (qrc == PGEN_FAIL || prc == PGEN_FAIL)
-       goto again;
       mp_drop(ev->m);
       mp_drop(ev->m);
-      ev->m = MP_COPY(c->p.m);
-      if (qrc == PGEN_TRY)
-       prc = PGEN_TRY;
+      rc = pfilt_step(&c->p, 4);
+      qrc = pfilt_step(&c->q, 2);
+      break;
+
       break;
       break;
+
+    /* --- Tidy the toys away --- */
+
     case PGEN_DONE:
       pfilt_destroy(&c->q);
       pfilt_destroy(&c->p);
     case PGEN_DONE:
       pfilt_destroy(&c->q);
       pfilt_destroy(&c->p);
+      return (PGEN_DONE);
+  }
+
+  /* --- Continue stepping if necessary --- */
+
+  while (rc == PGEN_FAIL || qrc == PGEN_FAIL) {
+    rc = pfilt_step(&c->p, 4);
+    qrc = pfilt_step(&c->q, 2);
+  }
+
+  ev->m = MP_COPY(c->p.m);
+  if (qrc == PGEN_TRY)
+    rc = PGEN_TRY;
+  return (rc);
+}
+
+/* --- @pgen_safejump@ --- *
+ *
+ * Jumps two numbers, %$q$% and %$p = 2q + 1$% such that neither has any
+ * small factors.
+ */
+
+int pgen_safejump(int rq, pgen_event *ev, void *p)
+{
+  pgen_safejumpctx *j = p;
+  int rc = PGEN_ABORT, qrc = 0;
+
+  switch (rq) {
+
+    /* --- Set up the jump contexts --- *
+     *
+     * The jump in @j.q@ is congruent to 2 (mod 4); see @strongprime_setup@.
+     * If @p@ is initially 1 (mod 4) then add @j.q@.  Then double @j.q@ to
+     * ensure that the step is 0 (mod 4).
+     */
+
+    case PGEN_BEGIN: {
+      mp *p = ev->m;
+      mp *q;
+      if ((p->v[0] & 3) != 3)
+       p = mp_add(p, p, j->jq.m);
+      rc = pfilt_create(&j->p, p);
+      pfilt_muladd(&j->jp, &j->jq, 2, 0);
+      q = mp_lsr(MP_NEW, p, 1);
+      qrc = pfilt_create(&j->q, q);
+      mp_drop(p);
+      mp_drop(q);
+    } break;
+
+    /* --- Step on one place --- */
+
+    case PGEN_TRY:
+      mp_drop(ev->m);
+      rc = pfilt_jump(&j->p, &j->jp);
+      qrc = pfilt_jump(&j->q, &j->jq);
       break;
       break;
+
+    /* --- Tidy everything up --- */
+
+    case PGEN_DONE:
+      pfilt_destroy(&j->jp);
+      pfilt_destroy(&j->p);
+      pfilt_destroy(&j->q);
+      return (PGEN_DONE);
   }
   }
-  return (prc);
+
+  /* --- Step on while @p@ or @q@ have small factors --- */
+
+  while (rc == PGEN_FAIL || qrc == PGEN_FAIL) {
+    rc = pfilt_jump(&j->p, &j->jp);
+    qrc = pfilt_jump(&j->q, &j->jq);
+  }
+  ev->m = MP_COPY(j->p.m);
+  if (qrc == PGEN_TRY)
+    rc = PGEN_TRY;
+  return (rc);
 }
 
 /* --- @pgen_safetest@ --- *
 }
 
 /* --- @pgen_safetest@ --- *
diff --git a/pgen.h b/pgen.h
index 9ce4e86..05d0a2c 100644 (file)
--- a/pgen.h
+++ b/pgen.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: pgen.h,v 1.4 1999/12/22 16:01:11 mdw Exp $
+ * $Id: pgen.h,v 1.5 2000/02/12 18:21:03 mdw Exp $
  *
  * Prime generation glue
  *
  *
  * Prime generation glue
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: pgen.h,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: pgen.h,v $
+ * Revision 1.5  2000/02/12 18:21:03  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.4  1999/12/22 16:01:11  mdw
  * Same file, completely different code.  Main interface for new prime-
  * search system.
  * Revision 1.4  1999/12/22 16:01:11  mdw
  * Same file, completely different code.  Main interface for new prime-
  * search system.
@@ -191,6 +194,19 @@ typedef struct pgen_safestepctx {
 
 extern int pgen_safestep(int /*rq*/, pgen_event */*ev*/, void */*p*/);
 
 
 extern int pgen_safestep(int /*rq*/, pgen_event */*ev*/, void */*p*/);
 
+/* --- @pgen_safejump@ --- *
+ *
+ * Jumps two numbers, %$q$% and %$p = 2q + 1$% such that neither has any
+ * small factors.
+ */
+
+typedef struct pgen_safejumpctx {
+  pfilt q, jq;
+  pfilt p, jp;
+} pgen_safejumpctx;
+
+extern int pgen_safejump(int /*rq*/, pgen_event */*ev*/, void */*p*/);
+
 /* --- @pgen_safetest@ --- *
  *
  * Applies Rabin-Miller tests to %$p$% and %$(p - 1)/2$%.
 /* --- @pgen_safetest@ --- *
  *
  * Applies Rabin-Miller tests to %$p$% and %$(p - 1)/2$%.
diff --git a/rspit.c b/rspit.c
index 3c14ab4..ec55707 100644 (file)
--- a/rspit.c
+++ b/rspit.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: rspit.c,v 1.2 1999/12/22 15:59:51 mdw Exp $
+ * $Id: rspit.c,v 1.3 2000/02/12 18:21:03 mdw Exp $
  *
  * Spit out random numbers
  *
  *
  * Spit out random numbers
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: rspit.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: rspit.c,v $
+ * Revision 1.3  2000/02/12 18:21:03  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.2  1999/12/22 15:59:51  mdw
  * New prime-search system.  Read BBS keys from key files.
  *
  * Revision 1.2  1999/12/22 15:59:51  mdw
  * New prime-search system.  Read BBS keys from key files.
  *
@@ -441,11 +444,10 @@ static grand *gen_bbs(unsigned i)
     m = MP_COPY(kd->u.m);
     key_close(&kf);
   } else {
     m = MP_COPY(kd->u.m);
     key_close(&kf);
   } else {
-    mp *p = mprand(MP_NEW, bits / 2, &rand_global, 3);
-    mp *q = mprand(MP_NEW, bits - bits / 2, &rand_global, 3);
     bbs_param bp;
 
     bbs_param bp;
 
-    if (bbs_gen(&bp, p, q, 0, (flags & f_progress) ? pgen_ev : 0, 0))
+    if (bbs_gen(&bp, bits, &rand_global, 0,
+               (flags & f_progress) ? pgen_ev : 0, 0))
       die(EXIT_FAILURE, "modulus generation failed");
     m = bp.n;
 
       die(EXIT_FAILURE, "modulus generation failed");
     m = bp.n;
 
@@ -459,8 +461,6 @@ static grand *gen_bbs(unsigned i)
       fputc('\n', stderr);
     }
 
       fputc('\n', stderr);
     }
 
-    mp_drop(p);
-    mp_drop(q);
     mp_drop(bp.p);
     mp_drop(bp.q);
   }
     mp_drop(bp.p);
     mp_drop(bp.q);
   }
index 4a7ddb8..a5f6052 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: strongprime.c,v 1.1 1999/12/22 15:51:22 mdw Exp $
+ * $Id: strongprime.c,v 1.2 2000/02/12 18:21:03 mdw Exp $
  *
  * Generate `strong' prime numbers
  *
  *
  * Generate `strong' prime numbers
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: strongprime.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: strongprime.c,v $
+ * Revision 1.2  2000/02/12 18:21:03  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.1  1999/12/22 15:51:22  mdw
  * Find `strong' RSA primes using Gordon's algorithm.
  *
  * Revision 1.1  1999/12/22 15:51:22  mdw
  * Find `strong' RSA primes using Gordon's algorithm.
  *
 
 /*----- Main code ---------------------------------------------------------*/
 
 
 /*----- Main code ---------------------------------------------------------*/
 
-/* --- @strongprime@ --- *
+/* --- @strongprime_setup@ --- *
  *
  * Arguments:  @const char *name@ = pointer to name root
  *
  * Arguments:  @const char *name@ = pointer to name root
- *             @mp *d@ = destination integer
+ *             @mp *d@ = destination for search start point
+ *             @pfilt *f@ = where to store filter jump context
  *             @unsigned nbits@ = number of bits wanted
  *             @grand *r@ = random number source
  *             @unsigned n@ = number of attempts to make
  *             @pgen_proc *event@ = event handler function
  *             @void *ectx@ = argument for the event handler
  *
  *             @unsigned nbits@ = number of bits wanted
  *             @grand *r@ = random number source
  *             @unsigned n@ = number of attempts to make
  *             @pgen_proc *event@ = event handler function
  *             @void *ectx@ = argument for the event handler
  *
- * Returns:    A `strong' prime, or zero.
- *
- * Use:                Finds `strong' primes.  A strong prime %$p$% is such that
- *
- *               * %$p - 1$% has a large prime factor %$r$%,
- *               * %$p + 1$% has a large prime factor %$s$%, and
- *               * %$r - 1$% has a large prime factor %$t$%.
+ * Returns:    A starting point for a `strong' prime search, or zero.
  *
  *
- *             The numbers produced may be slightly larger than requested,
- *             by a few bits.
+ * Use:                Sets up for a strong prime search, so that primes with
+ *             particular properties can be found.  It's probably important
+ *             to note that the number left in the filter context @f@ is
+ *             congruent to 2 (mod 4).
  */
 
  */
 
-mp *strongprime(const char *name, mp *d, unsigned nbits, grand *r,
-               unsigned n, pgen_proc *event, void *ectx)
+mp *strongprime_setup(const char *name, mp *d, pfilt *f, unsigned nbits,
+                     grand *r, unsigned n, pgen_proc *event, void *ectx)
 {
 {
-  mp *s, *t, *q, *p = 0;
+  mp *s, *t, *q;
   dstr dn = DSTR_INIT;
 
   dstr dn = DSTR_INIT;
 
-  mp *rr = MP_NEW;
+  mp *rr = d;
   pgen_filterctx c;
   pgen_filterctx c;
-  pgen_jumpctx cj;
+  pgen_jumpctx j;
   rabin rb;
 
   /* --- The bitslop parameter --- *
   rabin rb;
 
   /* --- The bitslop parameter --- *
@@ -91,7 +91,7 @@ mp *strongprime(const char *name, mp *d, unsigned nbits, grand *r,
    * numbers around 10 seem to be good.
    */
 
    * numbers around 10 seem to be good.
    */
 
-#define BITSLOP 10
+#define BITSLOP 12
 
   /* --- Choose two primes %$s$% and %$t$% of half the required size --- */
 
 
   /* --- Choose two primes %$s$% and %$t$% of half the required size --- */
 
@@ -101,7 +101,7 @@ mp *strongprime(const char *name, mp *d, unsigned nbits, grand *r,
   rr = mprand(rr, nbits, r, 1);
   DRESET(&dn); dstr_putf(&dn, "%s [s]", name);
   if ((s = pgen(dn.buf, MP_NEW, rr, event, ectx, n, pgen_filter, &c,
   rr = mprand(rr, nbits, r, 1);
   DRESET(&dn); dstr_putf(&dn, "%s [s]", name);
   if ((s = pgen(dn.buf, MP_NEW, rr, event, ectx, n, pgen_filter, &c,
-               rabin_iters(nbits), pgen_test, &rb)) == 0)
+          rabin_iters(nbits), pgen_test, &rb)) == 0)
     goto fail_s;
   mp_burn(s);
 
     goto fail_s;
   mp_burn(s);
 
@@ -119,12 +119,13 @@ mp *strongprime(const char *name, mp *d, unsigned nbits, grand *r,
   rr = mp_lsl(rr, rr, BITSLOP - 1);
   rr = mp_add(rr, rr, MP_ONE);
   DRESET(&dn); dstr_putf(&dn, "%s [r]", name);
   rr = mp_lsl(rr, rr, BITSLOP - 1);
   rr = mp_add(rr, rr, MP_ONE);
   DRESET(&dn); dstr_putf(&dn, "%s [r]", name);
-  cj.j = &c.f;
+  j.j = &c.f;
   nbits += BITSLOP;
   nbits += BITSLOP;
-  if ((q = pgen(dn.buf, MP_NEW, rr, event, ectx, n, pgen_jump, &cj,
-               rabin_iters(nbits), pgen_test, &rb)) == 0)
-    goto fail_r;
+  q = pgen(dn.buf, MP_NEW, rr, event, ectx, n, pgen_jump, &j,
+          rabin_iters(nbits), pgen_test, &rb);
   pfilt_destroy(&c.f);
   pfilt_destroy(&c.f);
+  if (!q)
+    goto fail_r;
 
   /* --- Select a suitable starting-point for finding %$p$% --- *
    *
 
   /* --- Select a suitable starting-point for finding %$p$% --- *
    *
@@ -149,32 +150,75 @@ mp *strongprime(const char *name, mp *d, unsigned nbits, grand *r,
     mp *x;
     x = mp_mul(MP_NEW, q, s);
     x = mp_lsl(x, x, 1);
     mp *x;
     x = mp_mul(MP_NEW, q, s);
     x = mp_lsl(x, x, 1);
-    pfilt_create(&c.f, x);
+    pfilt_create(f, x);
     x = mp_lsl(x, x, BITSLOP - 1);
     rr = mp_add(rr, rr, x);
     mp_drop(x);
   }
 
     x = mp_lsl(x, x, BITSLOP - 1);
     rr = mp_add(rr, rr, x);
     mp_drop(x);
   }
 
-  if ((p = pgen(name, d, rr, event, ectx, n, pgen_jump, &cj,
-               rabin_iters(nbits * 2), pgen_test, &rb)) == 0)
-    goto fail_p;
+  /* --- Return the result --- */
 
 
-  /* --- Tidy up because we've finished --- */
+#if 0
+fputs("r = ", stdout); mp_writefile(q, stdout, 10); putchar('\n');
+fputs("s = ", stdout); mp_writefile(s, stdout, 10); putchar('\n');
+fputs("t = ", stdout); mp_writefile(t, stdout, 10); putchar('\n');
+#endif
 
 
-fail_p:
   mp_drop(q);
   mp_drop(q);
+  mp_drop(t);
+  mp_drop(s);
+  dstr_destroy(&dn);
+  return (rr);
+
+  /* --- Tidy up if something failed --- */
+
 fail_r:
 fail_r:
-  pfilt_destroy(&c.f);
   mp_drop(t);
 fail_t:
   mp_drop(s);
 fail_s:
   mp_drop(rr);
   dstr_destroy(&dn);
   mp_drop(t);
 fail_t:
   mp_drop(s);
 fail_s:
   mp_drop(rr);
   dstr_destroy(&dn);
-
-  return (p);
+  return (0);
 
 #undef BITSLOP
 }
 
 
 #undef BITSLOP
 }
 
+/* --- @strongprime@ --- *
+ *
+ * Arguments:  @const char *name@ = pointer to name root
+ *             @mp *d@ = destination integer
+ *             @unsigned nbits@ = number of bits wanted
+ *             @grand *r@ = random number source
+ *             @unsigned n@ = number of attempts to make
+ *             @pgen_proc *event@ = event handler function
+ *             @void *ectx@ = argument for the event handler
+ *
+ * Returns:    A `strong' prime, or zero.
+ *
+ * Use:                Finds `strong' primes.  A strong prime %$p$% is such that
+ *
+ *               * %$p - 1$% has a large prime factor %$r$%,
+ *               * %$p + 1$% has a large prime factor %$s$%, and
+ *               * %$r - 1$% has a large prime factor %$t$%.
+ *
+ *             The numbers produced may be slightly larger than requested,
+ *             by a few bits.
+ */
+
+mp *strongprime(const char *name, mp *d, unsigned nbits, grand *r,
+               unsigned n, pgen_proc *event, void *ectx)
+{
+  pfilt f;
+  pgen_jumpctx j;
+  rabin rb;
+  
+  d = strongprime_setup(name, d, &f, nbits, r, n, event, ectx);
+  j.j = &f;
+  d = pgen(name, d, d, event, ectx, n, pgen_jump, &j,
+          rabin_iters(nbits), pgen_test, &rb);
+  pfilt_destroy(&f);
+  return (d);
+}
+
 /*----- That's all, folks -------------------------------------------------*/
 /*----- That's all, folks -------------------------------------------------*/
index 6f06cda..0b53a79 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: strongprime.h,v 1.1 1999/12/22 15:51:22 mdw Exp $
+ * $Id: strongprime.h,v 1.2 2000/02/12 18:21:03 mdw Exp $
  *
  * Generate `strong' prime numbers
  *
  *
  * Generate `strong' prime numbers
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: strongprime.h,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: strongprime.h,v $
+ * Revision 1.2  2000/02/12 18:21:03  mdw
+ * Overhaul of key management (again).
+ *
  * Revision 1.1  1999/12/22 15:51:22  mdw
  * Find `strong' RSA primes using Gordon's algorithm.
  *
  * Revision 1.1  1999/12/22 15:51:22  mdw
  * Find `strong' RSA primes using Gordon's algorithm.
  *
 
 /*----- Functions provided ------------------------------------------------*/
 
 
 /*----- Functions provided ------------------------------------------------*/
 
+/* --- @strongprime_setup@ --- *
+ *
+ * Arguments:  @const char *name@ = pointer to name root
+ *             @mp *d@ = destination for search start point
+ *             @pfilt *f@ = where to store filter jump context
+ *             @unsigned nbits@ = number of bits wanted
+ *             @grand *r@ = random number source
+ *             @unsigned n@ = number of attempts to make
+ *             @pgen_proc *event@ = event handler function
+ *             @void *ectx@ = argument for the event handler
+ *
+ * Returns:    A starting point for a `strong' prime search, or zero.
+ *
+ * Use:                Sets up for a strong prime search, so that primes with
+ *             particular properties can be found.  It's probably important
+ *             to note that the number left in the filter context @f@ is
+ *             congruent to 2 (mod 4).
+ */
+
+extern mp *strongprime_setup(const char */*name*/, mp */*d*/, pfilt */*f*/,
+                            unsigned /*nbits*/, grand */*r*/,
+                            unsigned /*n*/, pgen_proc */*event*/,
+                            void */*ectx*/);
+
 /* --- @strongprime@ --- *
  *
  * Arguments:  @const char *name@ = pointer to name root
 /* --- @strongprime@ --- *
  *
  * Arguments:  @const char *name@ = pointer to name root