/* -*-c-*-
*
- * $Id: keyutil.c,v 1.4 1999/12/22 15:48:10 mdw Exp $
+ * $Id: keyutil.c,v 1.10 2000/10/08 12:02:21 mdw Exp $
*
* Simple key manager program
*
/*----- Revision history --------------------------------------------------*
*
* $Log: keyutil.c,v $
+ * Revision 1.10 2000/10/08 12:02:21 mdw
+ * Use @MP_EQ@ instead of @MP_CMP@.
+ *
+ * Revision 1.9 2000/08/15 21:40:49 mdw
+ * Minor formatting change in listing attributes.
+ *
+ * Revision 1.8 2000/07/29 09:59:13 mdw
+ * Support Lim-Lee primes in Diffie-Hellman parameter generation.
+ *
+ * Revision 1.7 2000/07/01 11:18:51 mdw
+ * Use new interfaces for key manipulation.
+ *
+ * Revision 1.6 2000/06/17 11:28:22 mdw
+ * Use secure memory interface from MP library. `rand_getgood' is
+ * deprecated.
+ *
+ * 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.
#include <rand.h>
#include "bbs.h"
+#include "dh.h"
#include "dsa.h"
#include "fibrand.h"
#include "getdate.h"
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@ --- *
enum {
f_bogus = 1, /* Error in parsing */
f_lock = 2, /* Passphrase-lock private key */
- f_quiet = 4 /* Don't show a progress indicator */
+ f_quiet = 4, /* Don't show a progress indicator */
+ f_limlee = 8, /* Generate Lim-Lee primes */
+ f_subgroup = 16 /* Generate a subgroup */
};
/* --- @dolock@ --- *
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)
sz = (k->bits + 7) >> 3;
p = sub_alloc(sz);
m = (1 << (((k->bits - 1) & 7) + 1)) - 1;
- rand_getgood(RAND_GLOBAL, p, sz);
+ rand_get(RAND_GLOBAL, p, sz);
*p &= m;
key_binary(&k->k->k, p, sz);
k->k->k.e |= KCAT_SYMM | KF_BURN;
sz = k->bits / 7;
p = sub_alloc(sz);
- rand_getgood(RAND_GLOBAL, p, sz); /* Too much work done here! */
+ rand_get(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 >> 1) ^ 1;
+ x = x ^ (x >> 1);
p[i] = (p[i] & 0xfe) | (x & 0x01);
}
key_binary(&k->k->k, p, sz);
static void alg_rsa(keyopts *k)
{
- rsa_param rp;
+ rsa_priv rp;
key_data *kd;
/* --- Sanity checking --- */
{
grand *g = fibrand_create(rand_global.ops->word(&rand_global));
- mpmont mm;
+ rsa_pub rpp;
mp *m = mprand_range(MP_NEW, rp.n, g, 0);
mp *c;
- /* --- Encrypt the plaintext --- */
-
- mpmont_create(&mm, rp.n);
- c = mpmont_exp(&mm, MP_NEW, m, rp.e);
- mpmont_destroy(&mm);
+ rpp.n = rp.n;
+ rpp.e = rp.e;
+ c = rsa_qpubop(&rpp, MP_NEW, m);
+ c = rsa_qprivop(&rp, c, c, g);
- /* --- Decrypt the ciphertext --- */
-
- c = rsa_decrypt(&rp, c, c, g);
-
- /* --- Check everything went OK --- */
-
- if (MP_CMP(c, !=, m))
+ if (!MP_EQ(c, m))
die(EXIT_FAILURE, "test encryption failed");
mp_drop(c);
mp_drop(m);
mpkey(kd, "d-mod-q", rp.dq, KCAT_PRIV | KF_BURN);
dolock(k, kd, "private");
- mp_drop(rp.p); mp_drop(rp.q); mp_drop(rp.n); mp_drop(rp.q_inv);
- mp_drop(rp.e); mp_drop(rp.d); mp_drop(rp.dp); mp_drop(rp.dq);
+ rsa_privfree(&rp);
}
static void alg_dsaparam(keyopts *k)
sz = (k->qbits + 7) >> 3;
p = sub_alloc(sz);
- rand_getgood(RAND_GLOBAL, p, sz);
+ rand_get(RAND_GLOBAL, p, sz);
/* --- Allocate the parameters --- */
- if (dsa_seed(&dp, k->qbits, k->bits, 0, p, sz,
- (k->f & f_quiet) ? 0 : pgen_ev, 0))
+ if (dsa_gen(&dp, k->qbits, k->bits, 0, p, sz,
+ (k->f & f_quiet) ? 0 : pgen_ev, 0))
die(EXIT_FAILURE, "DSA parameter generation failed");
/* --- Store the parameters --- */
/* --- Choose a private key --- */
- x = mprand_range(MP_NEW, q, &rand_global, 0);
- mp_burn(x);
+ x = mprand_range(MP_NEWSEC, q, &rand_global, 0);
mpmont_create(&mm, p);
y = mpmont_exp(&mm, MP_NEW, g, x);
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 const char *pl[] = { "p", "g", 0 };
+ static const char *pl[] = { "p", "q", "g", 0 };
if (!copyparam(k, pl)) {
- pgen_safetestctx c;
- mp *p, *q;
+ dh_param dp;
key_data *kd = &k->k->k;
+ int rc;
if (!k->bits)
k->bits = 1024;
/* --- 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 (k->f & f_limlee) {
+ mp **f;
+ size_t nf;
+ if (!k->qbits)
+ k->qbits = 256;
+ rc = dh_limlee(&dp, k->qbits, k->bits,
+ (k->f & f_subgroup) ? DH_SUBGROUP : 0,
+ 0, &rand_global, (k->f & f_quiet) ? 0 : pgen_ev, 0,
+ (k->f & f_quiet) ? 0 : pgen_evspin, 0, &nf, &f);
+ if (!rc) {
+ dstr d = DSTR_INIT;
+ size_t i;
+ for (i = 0; i < nf; i++) {
+ if (i)
+ dstr_puts(&d, ", ");
+ mp_writedstr(f[i], &d, 10);
+ mp_drop(f[i]);
+ }
+ key_putattr(k->kf, k->k, "factors", d.buf);
+ dstr_destroy(&d);
+ }
+ } else
+ rc = dh_gen(&dp, k->qbits, k->bits, 0, &rand_global,
+ (k->f & f_quiet) ? 0 : pgen_ev, 0);
+
+ if (rc)
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;
- mp *p, *g;
+ mp *p, *q, *g;
mpmont mm;
key_data *kd = &k->k->k;
alg_dhparam(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$%.
*/
- y = mp_lsr(MP_NEW, p, 1);
- x = mprand_range(MP_NEW, y, &rand_global, 0);
- mp_burn(x);
+ x = mprand_range(MP_NEWSEC, q, &rand_global, 0);
/* --- 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 --- */
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;
+ bbs_priv bp;
key_data *kd;
- mp *p, *q;
/* --- Sanity checking --- */
/* --- 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");
- mp_drop(p); mp_drop(q);
/* --- Allrighty then --- */
mpkey(kd, "q", bp.q, KCAT_PRIV | KF_BURN);
dolock(k, kd, "private");
- mp_drop(bp.p); mp_drop(bp.q); mp_drop(bp.n);
+ bbs_privfree(&bp);
}
/* --- The algorithm tables --- */
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 --- */
{ "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' },
+ { "lim-lee", 0, 0, 'L' },
+ { "subgroup", 0, 0, 'S' },
{ 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:lqLS", opt, 0, 0, 0);
if (i < 0)
break;
/* --- Other flags --- */
+ case 'r':
+ rtag = optarg;
+ break;
case 'l':
k.f |= f_lock;
break;
case 'q':
k.f |= f_quiet;
break;
+ case 'L':
+ k.f |= f_limlee;
+ break;
+ case 'S':
+ k.f |= f_subgroup;
+ break;
/* --- Other things are bogus --- */
doopen(&f, KOPEN_WRITE);
k.kf = &f;
+ /* --- Key the generator --- */
+
+ keyrand(&f, rtag);
+
for (;;) {
uint32 id = rand_global.ops->word(&rand_global);
int err;
o->f &= ~f_attr;
printf("attributes:");
for (key_mkattriter(&i, k); key_nextattr(&i, &an, &av); ) {
- printf("\n\t%s = %s", an, av);
+ printf("\n %s = %s", an, av);
o->f |= f_attr;
}
if (o->f & f_attr)
/* --- @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;
dstr d = DSTR_INIT;
int i;
- if (!key_match(&k->k, kf))
+ if (!key_encode(&k->k, &d, kf))
return;
rmd160_init(&r);
- key_do(&k->k, kf, 0, fpkey, &r);
+ rmd160_hash(&r, d.buf, d.len);
rmd160_done(&r, hash);
-
+
+ DRESET(&d);
key_fulltag(k, &d);
for (i = 0; i < sizeof(hash); i++) {
if (i && i % 4 == 0)
} cmds[] = {
{ "add", cmd_add,
"add [options] type [attr...]\n\
- Options: [-l] [-a alg] [-b bits] [-p param]\n\
+ Options: [-lqLS] [-a alg] [-b|-B bits] [-p param] [-r tag]\n\
[-e expire] [-t tag] [-c comment]"
},
{ "expire", cmd_expire, "expire tag..." },
{ "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 }
};
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)
{
- fprintf(fp, "%s, Catacomb version " VERSION "\n", QUIS);
+ pquis(fp, "$, Catacomb version " VERSION "\n");
}
void help(FILE *fp)
-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);
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 (;;) {
/* --- 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 }
};
- 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;
exit(1);
}
+ /* --- Initialize the Catacomb random number generator --- */
+
+ rand_noisesrc(RAND_GLOBAL, &noise_source);
+ rand_seed(RAND_GLOBAL, 160);
+
/* --- Dispatch to appropriate command handler --- */
argc -= optind;