math/Makefile.am, symm/Makefile.am: Use `--no-install' on oddball tests.
[catacomb] / progs / key.c
index 0549469..0c817d4 100644 (file)
 #include "gfreduce.h"
 #include "key.h"
 #include "mp.h"
+#include "mpint.h"
 #include "mpmont.h"
 #include "mprand.h"
 #include "mptext.h"
 #include "pgen.h"
 #include "ptab.h"
 #include "rsa.h"
+#include "x25519.h"
+#include "x448.h"
+#include "ed25519.h"
+#include "ed448.h"
 
 #include "cc.h"
 #include "sha-mgf.h"
@@ -193,6 +198,7 @@ typedef struct keyopts {
   unsigned bits, qbits;                        /* Bit length for the new key */
   const char *curve;                   /* Elliptic curve name/info */
   grand *r;                            /* Random number source */
+  mp *e;                               /* Public exponent */
   key *p;                              /* Parameters key-data */
 } keyopts;
 
@@ -228,7 +234,7 @@ static void dolock(keyopts *k, key_data **kd, const char *t)
 /* --- @copyparam@ --- *
  *
  * Arguments:  @keyopts *k@ = pointer to key options
- *             @const char **pp@ = checklist of parameters
+ *             @const char **pp@ = checklist of parameters, or null
  *
  * Returns:    Nonzero if parameters copied; zero if you have to generate
  *             them.
@@ -242,6 +248,7 @@ static int copyparam(keyopts *k, const char **pp)
   key_attriter i;
   key_data *kd;
   const char *n, *v;
+  dstr t = DSTR_INIT;
 
   kf.f = KCAT_SHARE;
   kf.m = KF_CATMASK;
@@ -251,23 +258,35 @@ static int copyparam(keyopts *k, const char **pp)
   if (!k->p)
     return (0);
 
-  /* --- Run through the checklist --- */
+  /* --- Copy the key data if there's anything we want --- */
 
-  while (*pp) {
-    key_data *kd = key_structfind(k->p->k, *pp);
-    if (!kd)
-      die(EXIT_FAILURE, "bad parameter key: parameter `%s' not found", *pp);
-    if (!KEY_MATCH(kd, &kf))
-      die(EXIT_FAILURE, "bad parameter key: subkey `%s' is not shared", *pp);
-    pp++;
-  }
+  if (pp) {
 
-  /* --- Copy over the parameters --- */
+    /* --- Run through the checklist --- */
 
-  kd = key_copydata(k->p->k, &kf);
-  assert(kd);
-  key_setkeydata(k->kf, k->k, kd);
-  key_drop(kd);
+    key_fulltag(k->p, &t);
+    if ((k->p->k->e & KF_ENCMASK) != KENC_STRUCT)
+      die(EXIT_FAILURE, "parameter key `%s' is not structured", t.buf);
+    while (*pp) {
+      key_data *kd = key_structfind(k->p->k, *pp);
+      if (!kd) {
+       die(EXIT_FAILURE,
+           "bad parameter key `%s': parameter `%s' not found", t.buf, *pp);
+      }
+      if (!KEY_MATCH(kd, &kf)) {
+       die(EXIT_FAILURE,
+           "bad parameter key `%s': subkey `%s' is not shared", t.buf, *pp);
+      }
+      pp++;
+    }
+
+    /* --- Copy over the parameters --- */
+
+    kd = key_copydata(k->p->k, &kf);
+    assert(kd);
+    key_setkeydata(k->kf, k->k, kd);
+    key_drop(kd);
+  }
 
   /* --- Copy over attributes --- */
 
@@ -276,6 +295,7 @@ static int copyparam(keyopts *k, const char **pp)
 
   /* --- Done --- */
 
+  dstr_destroy(&t);
   return (1);
 }
 
@@ -354,6 +374,13 @@ static void keyrand(key_file *kf, const char *id)
 
 /* --- Key generation algorithms --- */
 
+static void alg_empty(keyopts *k)
+{
+  copyparam(k, 0);
+  key_setkeydata(k->kf, k->k,
+                key_newstring(KCAT_SHARE, k->curve ? k->curve : "."));
+}
+
 static void alg_binary(keyopts *k)
 {
   unsigned sz;
@@ -363,8 +390,7 @@ static void alg_binary(keyopts *k)
 
   if (!k->bits)
     k->bits = 128;
-  if (k->p)
-    die(EXIT_FAILURE, "no shared parameters for binary keys");
+  copyparam(k, 0);
 
   sz = (k->bits + 7) >> 3;
   p = sub_alloc(sz);
@@ -388,8 +414,7 @@ static void alg_des(keyopts *k)
 
   if (!k->bits)
     k->bits = 168;
-  if (k->p)
-    die(EXIT_FAILURE, "no shared parameters for DES keys");
+  copyparam(k, 0);
   if (k->bits % 56 || k->bits > 168)
     die(EXIT_FAILURE, "DES keys must be 56, 112 or 168 bits long");
 
@@ -418,15 +443,18 @@ static void alg_rsa(keyopts *k)
 
   /* --- Sanity checking --- */
 
-  if (k->p)
-    die(EXIT_FAILURE, "no shared parameters for RSA keys");
+  copyparam(k, 0);
   if (!k->bits)
     k->bits = 1024;
+  if (k->bits < 64)
+    die(EXIT_FAILURE, "RSA key too tiny");
+  if (!k->e)
+    k->e = mp_fromulong(MP_NEW, 65537);
 
   /* --- Generate the RSA parameters --- */
 
-  if (rsa_gen(&rp, k->bits, k->r, 0,
-             (k->f & f_quiet) ? 0 : pgen_ev, 0))
+  if (rsa_gen_e(&rp, k->bits, k->e, k->r, 0,
+               (k->f & f_quiet) ? 0 : pgen_ev, 0))
     die(EXIT_FAILURE, "RSA key generation failed");
 
   /* --- Run a test encryption --- */
@@ -703,8 +731,7 @@ static void alg_bbs(keyopts *k)
 
   /* --- Sanity checking --- */
 
-  if (k->p)
-    die(EXIT_FAILURE, "no shared parameters for Blum-Blum-Shub keys");
+  copyparam(k, 0);
   if (!k->bits)
     k->bits = 1024;
 
@@ -919,6 +946,64 @@ static void alg_ec(keyopts *k)
   mp_drop(x);
 }
 
+#define XDHS(_)                                                                \
+  _(x25519, X25519, "X25519")                                          \
+  _(x448, X448, "X448")
+
+#define XDHALG(xdh, XDH, name)                                         \
+                                                                       \
+  static void alg_##xdh(keyopts *k)                                    \
+  {                                                                    \
+    key_data *kd, *kkd;                                                        \
+    octet priv[XDH##_KEYSZ], pub[XDH##_PUBSZ];                         \
+                                                                       \
+    copyparam(k, 0);                                                   \
+    k->r->ops->fill(k->r, priv, sizeof(priv));                         \
+    xdh(pub, priv, xdh##_base);                                                \
+    kkd = key_newstruct();                                             \
+    key_structsteal(kkd, "priv",                                       \
+                   key_newbinary(KCAT_PRIV | KF_BURN,                  \
+                                 priv, sizeof(priv)));                 \
+    kd = key_newstruct();                                              \
+    key_structsteal(kd, "private", kkd);                               \
+    key_structsteal(kd, "pub",                                         \
+                   key_newbinary(KCAT_PUB, pub, sizeof(pub)));         \
+                                                                       \
+    key_setkeydata(k->kf, k->k, kd);                                   \
+  }
+
+XDHS(XDHALG)
+#undef XDHALG
+
+#define EDDSAS(_)                                                      \
+  _(ed25519, ED25519, "Ed25519")                                       \
+  _(ed448, ED448, "Ed448")
+
+#define EDDSAALG(ed, ED, name)                                         \
+                                                                       \
+  static void alg_##ed(keyopts *k)                                     \
+  {                                                                    \
+    key_data *kd, *kkd;                                                        \
+    octet priv[ED##_KEYSZ], pub[ED##_PUBSZ];                           \
+                                                                       \
+    copyparam(k, 0);                                                   \
+    k->r->ops->fill(k->r, priv, sizeof(priv));                         \
+    ed##_pubkey(pub, priv, sizeof(priv));                              \
+    kkd = key_newstruct();                                             \
+    key_structsteal(kkd, "priv",                                       \
+                   key_newbinary(KCAT_PRIV | KF_BURN,                  \
+                                 priv, sizeof(priv)));                 \
+    kd = key_newstruct();                                              \
+    key_structsteal(kd, "private", kkd);                               \
+    key_structsteal(kd, "pub",                                         \
+                   key_newbinary(KCAT_PUB, pub, sizeof(pub)));         \
+                                                                       \
+    key_setkeydata(k->kf, k->k, kd);                                   \
+  }
+
+EDDSAS(EDDSAALG)
+#undef EDDSAALG
+
 /* --- The algorithm tables --- */
 
 typedef struct keyalg {
@@ -940,6 +1025,15 @@ static keyalg algtab[] = {
   { "bindh-param",     alg_binparam,   "Binary-field DH parameters" },
   { "ec-param",                alg_ecparam,    "Elliptic curve parameters" },
   { "ec",              alg_ec,         "Elliptic curve crypto" },
+#define XDHTAB(xdh, XDH, name)                                         \
+  { #xdh,              alg_##xdh,      "" name " key exchange" },
+  XDHS(XDHTAB)
+#undef XDHTAB
+#define EDDSATAB(ed, ED, name)                                         \
+  { #ed,               alg_##ed,       "" name " digital signatures" },
+  EDDSAS(EDDSATAB)
+#undef EDDSATAB
+  { "empty",           alg_empty,      "Empty parametrs-only key" },
   { 0,                 0 }
 };
 
@@ -955,7 +1049,7 @@ static int cmd_add(int argc, char *argv[])
   keyalg *alg = algtab;
   const char *rtag = 0;
   const struct seedalg *sa = SEEDALG_DEFAULT;
-  keyopts k = { 0, 0, DSTR_INIT, 0, 0, 0, 0, 0 };
+  keyopts k = { 0, 0, DSTR_INIT, 0, 0, 0, 0, 0, 0 };
   const char *seed = 0;
   k.r = &rand_global;
 
@@ -976,6 +1070,7 @@ static int cmd_add(int argc, char *argv[])
       { "seedalg",     OPTF_ARGREQ,    0,      'A' },
       { "seed",                OPTF_ARGREQ,    0,      's' },
       { "newseed",     OPTF_ARGREQ,    0,      'n' },
+      { "public-exponent", OPTF_ARGREQ, 0,     'E' },
       { "lock",                0,              0,      'l' },
       { "quiet",       0,              0,      'q' },
       { "lim-lee",     0,              0,      'L' },
@@ -983,7 +1078,7 @@ static int cmd_add(int argc, char *argv[])
       { "kcdsa",       0,              0,      'K' },
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:R:I:C:A:s:n:lqrLKS",
+    int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:R:I:C:A:s:n:E:lqrLKS",
                   opt, 0, 0, 0);
     if (i < 0)
       break;
@@ -1145,6 +1240,15 @@ static int cmd_add(int argc, char *argv[])
        kid = id;
       } break;
 
+      /* --- Public exponent --- */
+
+      case 'E': {
+       char *p;
+       k.e = mp_readstring(k.e, optarg, &p, 0);
+       if (!k.e || *p || MP_CMP(k.e, <, MP_THREE) || MP_EVENP(k.e))
+         die(EXIT_FAILURE, "bad exponent `%s'", optarg);
+      } break;
+
       /* --- Other flags --- */
 
       case 'R':
@@ -1239,12 +1343,8 @@ static int cmd_add(int argc, char *argv[])
 
   /* --- Find the parameter key --- */
 
-  if (ptag) {
-    if ((k.p = key_bytag(&f, ptag)) == 0)
-      die(EXIT_FAILURE, "parameter key `%s' not found", ptag);
-    if ((k.p->k->e & KF_ENCMASK) != KENC_STRUCT)
-      die(EXIT_FAILURE, "parameter key `%s' is not structured", ptag);
-  }
+  if (ptag && (k.p = key_bytag(&f, ptag)) == 0)
+    die(EXIT_FAILURE, "parameter key `%s' not found", ptag);
 
   /* --- Now generate the actual key data --- */