X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/c65df27983057ec76ed0e72bb370f9a5ae7dad28..e4a509b8174c8b2cfc0a084b78c9c7b7d08b624b:/keyutil.c diff --git a/keyutil.c b/keyutil.c index 0b54df2..3be95b3 100644 --- a/keyutil.c +++ b/keyutil.c @@ -31,6 +31,7 @@ #include "config.h" +#include #include #include #include @@ -46,6 +47,7 @@ #include #include +#include "bintab.h" #include "bbs.h" #include "dh.h" #include "dsa.h" @@ -55,6 +57,7 @@ #include "ectab.h" #include "fibrand.h" #include "getdate.h" +#include "gfreduce.h" #include "key.h" #include "mp.h" #include "mpmont.h" @@ -570,18 +573,27 @@ static void alg_dhparam(keyopts *k) 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; @@ -698,6 +710,104 @@ static void alg_bbs(keyopts *k) 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 }; @@ -778,6 +888,7 @@ static void alg_ec(keyopts *k) kkd = key_structcreate(kd, "private"); key_structure(kkd); mpkey(kkd, "x", x, KCAT_PRIV | KF_BURN); + dolock(k, kkd, "private"); /* --- Done --- */ @@ -797,11 +908,13 @@ static keyalg algtab[] = { { "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 } @@ -1583,6 +1696,101 @@ static int cmd_finger(int argc, char *argv[]) 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[]) @@ -1781,7 +1989,7 @@ static int cmd_merge(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)); } @@ -1800,8 +2008,10 @@ static int cmd_merge(int argc, char *argv[]) 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, \ @@ -1835,6 +2045,13 @@ Options:\n\ -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\