#include "config.h"
+#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <noise.h>
#include <rand.h>
+#include "bintab.h"
#include "bbs.h"
#include "dh.h"
#include "dsa.h"
#include "ectab.h"
#include "fibrand.h"
#include "getdate.h"
+#include "gfreduce.h"
#include "key.h"
#include "mp.h"
#include "mpmont.h"
if (k->curve) {
qd_parse qd;
+ group *g;
+ const char *e;
if (strcmp(k->curve, "list") == 0) {
unsigned i, w;
- LIST("Built-in prime groups", stdout, ptab[i].name, ptab[i].name);
+ LIST("Built-in prime fields", stdout, ptab[i].name, ptab[i].name);
exit(0);
}
qd.p = k->curve;
if (dh_parse(&qd, &dp))
- die(EXIT_FAILURE, "error in group spec: %s", qd.e);
+ die(EXIT_FAILURE, "error in field spec: %s", qd.e);
+ if (!qd_eofp(&qd))
+ die(EXIT_FAILURE, "junk at end of field spec");
+ if ((g = group_prime(&dp)) == 0)
+ die(EXIT_FAILURE, "invalid prime field");
+ if (!(k->f & f_quiet) && (e = G_CHECK(g, &rand_global)) != 0)
+ moan("WARNING! group check failed: %s", e);
+ G_DESTROYGROUP(g);
goto done;
}
-
+
if (!k->bits)
k->bits = 1024;
bbs_privfree(&bp);
}
+static void alg_binparam(keyopts *k)
+{
+ static const char *pl[] = { "p", "q", "g", 0 };
+ if (!copyparam(k, pl)) {
+ gbin_param gb;
+ qd_parse qd;
+ group *g;
+ const char *e;
+ key_data *kd = &k->k->k;
+
+ /* --- Decide on a field --- */
+
+ if (!k->bits) k->bits = 128;
+ if (k->curve && strcmp(k->curve, "list") == 0) {
+ unsigned i, w;
+ LIST("Built-in binary fields", stdout,
+ bintab[i].name, bintab[i].name);
+ exit(0);
+ }
+ if (!k->curve) {
+ if (k->bits <= 40) k->curve = "p1363-40";
+ else if (k->bits <= 56) k->curve = "p1363-56";
+ else if (k->bits <= 64) k->curve = "p1363-64";
+ else if (k->bits <= 80) k->curve = "p1363-80";
+ else if (k->bits <= 112) k->curve = "p1363-112";
+ else if (k->bits <= 128) k->curve = "p1363-128";
+ else {
+ die(EXIT_FAILURE,
+ "no built-in binary fields provide %u-bit security",
+ k->bits);
+ }
+ }
+
+ /* --- Check it --- */
+
+ qd.e = 0;
+ qd.p = k->curve;
+ if (dhbin_parse(&qd, &gb))
+ die(EXIT_FAILURE, "error in field spec: %s", qd.e);
+ if (!qd_eofp(&qd))
+ die(EXIT_FAILURE, "junk at end of field spec");
+ if ((g = group_binary(&gb)) == 0)
+ die(EXIT_FAILURE, "invalid binary field");
+ if (!(k->f & f_quiet) && (e = G_CHECK(g, &rand_global)) != 0)
+ moan("WARNING! group check failed: %s", e);
+ G_DESTROYGROUP(g);
+
+ /* --- Write out the answer --- */
+
+ key_structure(kd);
+ mpkey(kd, "p", gb.p, KCAT_SHARE);
+ mpkey(kd, "q", gb.q, KCAT_SHARE);
+ mpkey(kd, "g", gb.g, KCAT_SHARE);
+ mp_drop(gb.q);
+ mp_drop(gb.p);
+ mp_drop(gb.g);
+ }
+}
+
+static void alg_bin(keyopts *k)
+{
+ mp *x, *y;
+ mp *p, *q, *g;
+ gfreduce r;
+ key_data *kd = &k->k->k;
+
+ /* --- Get the shared parameters --- */
+
+ alg_binparam(k);
+ p = getmp(kd, "p");
+ q = getmp(kd, "q");
+ g = getmp(kd, "g");
+
+ /* --- Choose a suitable private key --- *
+ *
+ * Since %$g$% has order %$q$%, choose %$x < q$%.
+ */
+
+ x = mprand_range(MP_NEWSEC, q, k->r, 0);
+
+ /* --- Compute the public key %$y = g^x \bmod p$% --- */
+
+ gfreduce_create(&r, p);
+ y = gfreduce_exp(&r, MP_NEW, g, x);
+ gfreduce_destroy(&r);
+
+ /* --- Store everything away --- */
+
+ mpkey(kd, "y", y, KCAT_PUB);
+
+ kd = key_structcreate(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_ecparam(keyopts *k)
{
static const char *pl[] = { "curve", 0 };
kkd = key_structcreate(kd, "private");
key_structure(kkd);
mpkey(kkd, "x", x, KCAT_PRIV | KF_BURN);
+ dolock(k, kkd, "private");
/* --- Done --- */
{ "binary", alg_binary, "Plain binary data" },
{ "des", alg_des, "Binary with DES-style parity" },
{ "rsa", alg_rsa, "RSA public-key encryption" },
+ { "bbs", alg_bbs, "Blum-Blum-Shub generator" },
{ "dsa", alg_dsa, "DSA digital signatures" },
{ "dsa-param", alg_dsaparam, "DSA shared parameters" },
{ "dh", alg_dh, "Diffie-Hellman key exchange" },
{ "dh-param", alg_dhparam, "Diffie-Hellman parameters" },
- { "bbs", alg_bbs, "Blum-Blum-Shub generator" },
+ { "bindh", alg_bin, "DH over a binary field" },
+ { "bindh-param", alg_binparam, "Binary-field DH parameters" },
{ "ec-param", alg_ecparam, "Elliptic curve parameters" },
{ "ec", alg_ec, "Elliptic curve crypto" },
{ 0, 0 }
return (rc);
}
+/* --- @cmd_verify@ --- */
+
+static unsigned xdigit(char c)
+{
+ if ('A' <= c && c <= 'Z') return (c + 10 - 'A');
+ if ('a' <= c && c <= 'z') return (c + 10 - 'a');
+ if ('0' <= c && c <= '9') return (c - '0');
+ return (~0u);
+}
+
+static void unhexify(octet *q, char *p, size_t n)
+{
+ unsigned a = 0;
+ int i = 0;
+
+ for (;;) {
+ if (*p == '-' || *p == ':' || isspace((unsigned char)*p)) {
+ p++;
+ continue;
+ }
+ if (!n && !*p)
+ break;
+ if (!*p)
+ die(EXIT_FAILURE, "hex string too short");
+ if (!isxdigit((unsigned char)*p))
+ die(EXIT_FAILURE, "bad hex string");
+ if (!n)
+ die(EXIT_FAILURE, "hex string too long");
+ a = (a << 4) | xdigit(*p++);
+ i++;
+ if (i == 2) {
+ *q++ = U8(a);
+ a = 0;
+ i = 0;
+ n--;
+ }
+ }
+}
+
+static int cmd_verify(int argc, char *argv[])
+{
+ key_file f;
+ int rc = 0;
+ const gchash *ch = &rmd160;
+ ghash *h;
+ key *k;
+ octet *buf;
+ const octet *fpr;
+ key_filter kf = { KF_NONSECRET, KF_NONSECRET };
+
+ for (;;) {
+ static struct option opt[] = {
+ { "filter", OPTF_ARGREQ, 0, 'f' },
+ { "algorithm", OPTF_ARGREQ, 0, 'a' },
+ { 0, 0, 0, 0 }
+ };
+ int i = mdwopt(argc, argv, "+f:a:", opt, 0, 0, 0);
+ if (i < 0)
+ break;
+ switch (i) {
+ case 'f': {
+ char *p;
+ int err = key_readflags(optarg, &p, &kf.f, &kf.m);
+ if (err || *p)
+ die(EXIT_FAILURE, "bad filter string `%s'", optarg);
+ } break;
+ case 'a':
+ if ((ch = ghash_byname(optarg)) == 0)
+ die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg);
+ break;
+ default:
+ rc = 1;
+ break;
+ }
+ }
+
+ argv += optind; argc -= optind;
+ if (rc || argc != 2)
+ die(EXIT_FAILURE, "Usage: verify [-f FILTER] TAG FINGERPRINT");
+
+ doopen(&f, KOPEN_READ);
+
+ if ((k = key_bytag(&f, argv[0])) == 0)
+ die(EXIT_FAILURE, "key `%s' not found", argv[0]);
+ buf = xmalloc(ch->hashsz);
+ unhexify(buf, argv[1], ch->hashsz);
+ h = GH_INIT(ch);
+ if (!key_fingerprint(k, h, &kf))
+ die(EXIT_FAILURE, "key has no fingerprintable components (as filtered)");
+ fpr = GH_DONE(h, 0);
+ if (memcmp(fpr, buf, ch->hashsz) != 0)
+ die(EXIT_FAILURE, "key fingerprint mismatch");
+ return (0);
+}
+
/* --- @cmd_comment@ --- */
static int cmd_comment(int argc, char *argv[])
if (strcmp(argv[1], "-") == 0)
fp = stdin;
else if (!(fp = fopen(argv[1], "r"))) {
- die(EXIT_FAILURE, "couldn't open `%s' for writing: %s",
+ die(EXIT_FAILURE, "couldn't open `%s' for reading: %s",
argv[1], strerror(errno));
}
ghashtab[i], ghashtab[i]->name) \
LI("Elliptic curves", ec, \
ectab[i].name, ectab[i].name) \
- LI("Diffie-Hellman groups", dh, \
+ LI("Prime Diffie-Hellman groups", dh, \
ptab[i].name, ptab[i].name) \
+ LI("Binary Diffie-Hellman groups", bindh, \
+ bintab[i].name, bintab[i].name) \
LI("Key-generation algorithms", keygen, \
algtab[i].name, algtab[i].name) \
LI("Random seeding algorithms", seed, \
-a, --algorithm=HASH Use the named HASH algorithm.\n\
($ show hash for list.)\n\
" },
+ { "verify", cmd_verify, "verify [-f FILTER] TAG FINGERPRINT", "\
+Options:\n\
+\n\
+-f, --filter=FILT Only hash key components matching FILT.\n\
+-a, --algorithm=HASH Use the named HASH algorithm.\n\
+ ($ show hash for list.)\n\
+" },
{ "extract", cmd_extract, "extract [-f FILTER] FILE [TAG...]", "\
Options:\n\
\n\