progs/key.c: Use `HASH' rather than `HASHALG' to denote a hash-function name.
[catacomb] / progs / key.c
index b2b9080..9c9466b 100644 (file)
@@ -42,6 +42,7 @@
 #include <mLib/base32.h>
 #include <mLib/base64.h>
 #include <mLib/hex.h>
+#include <mLib/macros.h>
 #include <mLib/mdwopt.h>
 #include <mLib/quis.h>
 #include <mLib/report.h>
@@ -63,6 +64,7 @@
 #include "gfreduce.h"
 #include "key.h"
 #include "mp.h"
+#include "mpint.h"
 #include "mpmont.h"
 #include "mprand.h"
 #include "mptext.h"
@@ -70,7 +72,9 @@
 #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"
@@ -195,6 +199,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;
 
@@ -442,11 +447,15 @@ static void alg_rsa(keyopts *k)
   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 --- */
@@ -594,7 +603,7 @@ static void alg_dhparam(keyopts *k)
       group *g;
       const char *e;
 
-      if (strcmp(k->curve, "list") == 0) {
+      if (STRCMP(k->curve, ==, "list")) {
        unsigned i, w;
        LIST("Built-in prime fields", stdout, ptab[i].name, ptab[i].name);
        exit(0);
@@ -762,7 +771,7 @@ static void alg_binparam(keyopts *k)
     /* --- Decide on a field --- */
 
     if (!k->bits) k->bits = 128;
-    if (k->curve && strcmp(k->curve, "list") == 0) {
+    if (k->curve && STRCMP(k->curve, ==, "list")) {
       unsigned i, w;
       LIST("Built-in binary fields", stdout,
           bintab[i].name, bintab[i].name);
@@ -861,7 +870,7 @@ static void alg_ecparam(keyopts *k)
     /* --- Decide on a curve --- */
 
     if (!k->bits) k->bits = 256;
-    if (k->curve && strcmp(k->curve, "list") == 0) {
+    if (k->curve && STRCMP(k->curve, ==, "list")) {
       unsigned i, w;
       LIST("Built-in elliptic curves", stdout,
           ectab[i].name, ectab[i].name);
@@ -938,41 +947,63 @@ static void alg_ec(keyopts *k)
   mp_drop(x);
 }
 
-static void alg_x25519(keyopts *k)
-{
-  key_data *kd, *kkd;
-  octet priv[X25519_KEYSZ], pub[X25519_PUBSZ];
-
-  copyparam(k, 0);
-  k->r->ops->fill(k->r, priv, sizeof(priv));
-  x25519(pub, priv, x25519_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);
-}
-
-static void alg_ed25519(keyopts *k)
-{
-  key_data *kd, *kkd;
-  octet priv[ED25519_KEYSZ], pub[ED25519_PUBSZ];
+#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);                                   \
+  }
 
-  copyparam(k, 0);
-  k->r->ops->fill(k->r, priv, sizeof(priv));
-  ed25519_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)));
+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);                                   \
+  }
 
-  key_setkeydata(k->kf, k->k, kd);
-}
+EDDSAS(EDDSAALG)
+#undef EDDSAALG
 
 /* --- The algorithm tables --- */
 
@@ -995,8 +1026,14 @@ static keyalg algtab[] = {
   { "bindh-param",     alg_binparam,   "Binary-field DH parameters" },
   { "ec-param",                alg_ecparam,    "Elliptic curve parameters" },
   { "ec",              alg_ec,         "Elliptic curve crypto" },
-  { "x25519",          alg_x25519,     "X25519 key exchange" },
-  { "ed25519",         alg_ed25519,    "Ed25519 digital signatures" },
+#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 }
 };
@@ -1013,7 +1050,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;
 
@@ -1034,6 +1071,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' },
@@ -1041,7 +1079,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;
@@ -1056,7 +1094,7 @@ static int cmd_add(int argc, char *argv[])
        keyalg *a;
        size_t sz = strlen(optarg);
 
-       if (strcmp(optarg, "list") == 0) {
+       if (STRCMP(optarg, ==, "list")) {
          for (a = algtab; a->name; a++)
            printf("%-10s %s\n", a->name, a->help);
          return (0);
@@ -1064,7 +1102,7 @@ static int cmd_add(int argc, char *argv[])
 
        alg = 0;
        for (a = algtab; a->name; a++) {
-         if (strncmp(optarg, a->name, sz) == 0) {
+         if (STRNCMP(optarg, ==, a->name, sz)) {
            if (a->name[sz] == 0) {
              alg = a;
              break;
@@ -1103,7 +1141,7 @@ static int cmd_add(int argc, char *argv[])
       /* --- Expiry dates get passed to @get_date@ for parsing --- */
 
       case 'e':
-       if (strcmp(optarg, "forever") == 0)
+       if (STRCMP(optarg, ==, "forever"))
          exp = KEXP_FOREVER;
        else {
          exp = get_date(optarg, 0);
@@ -1141,7 +1179,7 @@ static int cmd_add(int argc, char *argv[])
 
       case 'A': {
        const struct seedalg *ss;
-       if (strcmp(optarg, "list") == 0) {
+       if (STRCMP(optarg, ==, "list")) {
          printf("Seed algorithms:\n");
          for (ss = seedtab; ss->p; ss++)
            printf("  %s\n", ss->p);
@@ -1150,7 +1188,7 @@ static int cmd_add(int argc, char *argv[])
        if (seed) die(EXIT_FAILURE, "seed already set -- put -A first");
        sa = 0;
        for (ss = seedtab; ss->p; ss++) {
-         if (strcmp(optarg, ss->p) == 0)
+         if (STRCMP(optarg, ==, ss->p))
            sa = ss;
        }
        if (!sa)
@@ -1203,6 +1241,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':
@@ -1274,7 +1321,7 @@ static int cmd_add(int argc, char *argv[])
     if (k.f & f_retag) {
       if ((kk = key_bytag(&f, tag)) != 0 &&
          kk->tag &&
-         strcmp(kk->tag, tag) == 0)
+         STRCMP(kk->tag, ==, tag))
        key_settag(&f, kk, 0);
     }
     if ((err = key_settag(&f, k.k, tag)) != 0)
@@ -1779,7 +1826,7 @@ static const struct fpres *lookup_fpres(const char *name)
 {
   const struct fpres *fpres;
   for (fpres = fprestab; fpres->name; fpres++)
-    if (strcmp(fpres->name, name) == 0) return (fpres);
+    if (STRCMP(fpres->name, ==, name)) return (fpres);
   die(EXIT_FAILURE, "unknown presentation syle `%s'", name);
 }
 
@@ -1824,7 +1871,7 @@ static int cmd_finger(int argc, char *argv[])
   argv += optind; argc -= optind;
   if (rc) {
     die(EXIT_FAILURE,
-       "Usage: fingerprint [-a HASHALG] [-p STYLE] [-f FILTER] [TAG...]");
+       "Usage: fingerprint [-a HASH] [-p STYLE] [-f FILTER] [TAG...]");
   }
 
   doopen(&f, KOPEN_READ);
@@ -1898,7 +1945,7 @@ static int cmd_verify(int argc, char *argv[])
   argv += optind; argc -= optind;
   if (rc || argc != 2) {
     die(EXIT_FAILURE,
-       "Usage: verify [-a HASHALG] [-p STYLE] [-f FILTER] TAG FINGERPRINT");
+       "Usage: verify [-a HASH] [-p STYLE] [-f FILTER] TAG FINGERPRINT");
   }
 
   doopen(&f, KOPEN_READ);
@@ -1923,7 +1970,7 @@ static int cmd_verify(int argc, char *argv[])
   if (!key_fingerprint(k, h, &kf))
     die(EXIT_FAILURE, "key has no fingerprintable components (as filtered)");
   fpr = GH_DONE(h, 0);
-  if (memcmp(fpr, d.buf, ch->hashsz) != 0)
+  if (MEMCMP(fpr, !=, d.buf, ch->hashsz))
     die(EXIT_FAILURE, "key fingerprint mismatch");
   dstr_destroy(&d); dstr_destroy(&dd);
   doclose(&f);
@@ -1982,7 +2029,7 @@ static int cmd_tag(int argc, char *argv[])
     die(EXIT_FAILURE, "Usage: tag [-r] TAG [NEW-TAG]");
   doopen(&f, KOPEN_WRITE);
   if (flags & f_retag) {
-    if ((k = key_bytag(&f, argv[1])) != 0 && strcmp(k->tag, argv[1]) == 0)
+    if ((k = key_bytag(&f, argv[1])) != 0 && STRCMP(k->tag, ==, argv[1]))
       key_settag(&f, k, 0);
   }
   if ((k = key_bytag(&f, argv[0])) == 0)
@@ -2076,7 +2123,7 @@ static int cmd_extract(int argc, char *argv[])
   argv += optind; argc -= optind;
   if (rc || argc < 1)
     die(EXIT_FAILURE, "Usage: extract [-f FILTER] FILE [TAG...]");
-  if (strcmp(*argv, "-") == 0)
+  if (STRCMP(*argv, ==, "-"))
     fp = stdout;
   else {
     outfile = *argv;
@@ -2132,7 +2179,7 @@ static int cmd_merge(int argc, char *argv[])
 
   if (argc != 2)
     die(EXIT_FAILURE, "Usage: merge FILE");
-  if (strcmp(argv[1], "-") == 0)
+  if (STRCMP(argv[1], ==, "-"))
     fp = stdin;
   else if (!(fp = fopen(argv[1], "r"))) {
     die(EXIT_FAILURE, "couldn't open `%s' for reading: %s",
@@ -2187,7 +2234,7 @@ Options:\n\
 -v, --verbose          Show more information.\n\
 " },
   { "fingerprint", cmd_finger,
-    "fingerprint [-a HASHALG] [-p STYLE] [-f FILTER] [TAG...]", "\
+    "fingerprint [-a HASH] [-p STYLE] [-f FILTER] [TAG...]", "\
 Options:\n\
 \n\
 -f, --filter=FILT      Only hash key components matching FILT.\n\