From 02dfbd5b7af7816959dbd39c1fe628451204e35f Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sat, 13 May 2006 12:49:39 +0100 Subject: [PATCH] catcrypt: Implement symmetric key-encapsulation and signature schemes. For cases where you don't actually want to send messages, just keep stuff lying around locally. --- catcrypt.1 | 25 ++++++++++++++ catsign.1 | 15 +++++++++ catsign.c | 2 +- cc-kem.c | 85 ++++++++++++++++++++++++++++++++++++++++++---- cc-sig.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- cc.h | 1 + 6 files changed, 227 insertions(+), 13 deletions(-) diff --git a/catcrypt.1 b/catcrypt.1 index d4ef3e1..61da7f9 100644 --- a/catcrypt.1 +++ b/catcrypt.1 @@ -184,6 +184,16 @@ Use the algorithm of the .BR key (1)) command to generate the key. +.TP +.B symm +This is a simple symmetric encapsulation scheme. It works by hashing a +binary key with a randomly-generated salt. Use the +.B binary +algorithm of the +.B key add +command (see +.BR key (1)) +to generate the key. .PP As well as the KEM itself, a number of supporting algorithms are used. These are taken from appropriately named attributes on the key or, @@ -335,6 +345,21 @@ algorithm of the command (see .BR key (1)) to generate the key. +.TP +.B mac +This uses a symmetric message-authentication algorithm rather than a +digital signature. The precise message-authentication scheme used is +determined by the +.B mac +attribute on the key, which defaults to +.IB hash -hmac +if unspecified. Use the +.B binary +algorithm of the +.B key add +command (see +.BR key (1)) +to generate the key. .PP As well as the signature algorithm itself, a hash function is used. This is taken from the diff --git a/catsign.1 b/catsign.1 index e762712..3f1cd5e 100644 --- a/catsign.1 +++ b/catsign.1 @@ -243,6 +243,21 @@ algorithm of the command (see .BR key (1)) to generate the key. +.TP +.B mac +This uses a symmetric message-authentication algorithm rather than a +digital signature. The precise message-authentication scheme used is +determined by the +.B mac +attribute on the key, which defaults to +.IB hash -hmac +if unspecified. Use the +.B binary +algorithm of the +.B key add +command (see +.BR key (1)) +to generate the key. .PP As well as the signature algorithm itself, a hash function is used. This is taken from the diff --git a/catsign.c b/catsign.c index 93f3236..727c980 100644 --- a/catsign.c +++ b/catsign.c @@ -367,7 +367,7 @@ static void keyhash(key *k, sig *s, dstr *d) ghash *h; key_filter kf; - h = GH_INIT(GH_CLASS(s->h)); + h = GH_INIT(s->ch); kf.f = KCAT_PUB; kf.m = KF_CATMASK; key_fingerprint(k, h, &kf); diff --git a/cc-kem.c b/cc-kem.c index b6908e5..1766c8e 100644 --- a/cc-kem.c +++ b/cc-kem.c @@ -350,6 +350,67 @@ static const kemops ec_decops = { ec_decinit, dh_decdoit, dh_enccheck, dh_encdestroy }; +/* --- Symmetric --- */ + +typedef struct symm_ctx { + kem k; + key_packdef kp; + key_bin kb; +} symm_ctx; + +static kem *symm_init(key *k, void *kd) +{ + symm_ctx *s; + dstr d = DSTR_INIT; + int err; + + s = CREATE(symm_ctx); + + key_fulltag(k, &d); + s->kp.e = KENC_BINARY; + s->kp.p = &s->kb; + s->kp.kd = 0; + + if ((err = key_unpack(&s->kp, kd, &d)) != 0) { + die(EXIT_FAILURE, "failed to unpack symmetric key `%s': %s", + d.buf, key_strerror(err)); + } + dstr_destroy(&d); + return (&s->k); +} + +static int symm_decdoit(kem *k, dstr *d, ghash *h) +{ + symm_ctx *s = (symm_ctx *)k; + + GH_HASH(h, s->kb.k, s->kb.sz); + GH_HASH(h, d->buf, d->len); + return (0); +} + +static int symm_encdoit(kem *k, dstr *d, ghash *h) +{ + dstr_ensure(d, h->ops->c->hashsz); + d->len += h->ops->c->hashsz; + rand_get(RAND_GLOBAL, d->buf, d->len); + return (symm_decdoit(k, d, h)); +} + +static const char *symm_check(kem *k) { return (0); } + +static void symm_destroy(kem *k) + { symm_ctx *s = (symm_ctx *)k; key_unpackdone(&s->kp); } + +static const kemops symm_encops = { + 0, 0, + symm_init, symm_encdoit, symm_check, symm_destroy +}; + +static const kemops symm_decops = { + 0, 0, + symm_init, symm_decdoit, symm_check, symm_destroy +}; + /* --- The switch table --- */ const struct kemtab kemtab[] = { @@ -357,6 +418,7 @@ const struct kemtab kemtab[] = { { "dh", &dh_encops, &dh_decops }, { "bindh", &bindh_encops, &bindh_decops }, { "ec", &ec_encops, &ec_decops }, + { "symm", &symm_encops, &symm_decops }, { 0, 0, 0 } }; @@ -437,10 +499,17 @@ kem *getkem(key *k, const char *app, int wantpriv) kalg, t.buf); k_found:; ko = wantpriv ? kt->decops : kt->encops; - kd = xmalloc(ko->kdsz); - kp = key_fetchinit(ko->kf, 0, kd); - if ((e = key_fetch(kp, k)) != 0) - die(EXIT_FAILURE, "error fetching key `%s': %s", t.buf, key_strerror(e)); + if (!ko->kf) { + kd = k->k; + key_incref(kd); + } else { + kd = xmalloc(ko->kdsz); + kp = key_fetchinit(ko->kf, 0, kd); + if ((e = key_fetch(kp, k)) != 0) { + die(EXIT_FAILURE, "error fetching key `%s': %s", + t.buf, key_strerror(e)); + } + } kk = ko->init(k, kd); kk->kp = kp; kk->ops = ko; @@ -545,8 +614,12 @@ done: void freekem(kem *k) { - key_fetchdone(k->kp); - xfree(k->kd); + if (!k->ops->kf) + key_drop(k->kd); + else { + key_fetchdone(k->kp); + xfree(k->kd); + } k->ops->destroy(k); } diff --git a/cc-sig.c b/cc-sig.c index 45679ce..dbcf902 100644 --- a/cc-sig.c +++ b/cc-sig.c @@ -570,6 +570,93 @@ static const sigops eckcdsa_vrf = { eckcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigcheck, dsa_sigdestroy }; +/* --- Symmetric message authentication --- */ + +typedef struct mac_ctx { + sig s; + const gcmac *mc; + gmac *m; + key_packdef kp; + key_bin kb; +} mac_ctx; + +static sig *mac_init(key *k, void *kd, const gchash *hc) +{ + mac_ctx *m; + dstr d = DSTR_INIT; + int err; + const char *mm; + + m = CREATE(mac_ctx); + + key_fulltag(k, &d); + m->kp.e = KENC_BINARY; + m->kp.p = &m->kb; + m->kp.kd = 0; + + if ((mm = key_getattr(0 /*yik*/, k, "mac")) == 0) { + dstr_putf(&d, "%s-hmac", hc->name); + mm = d.buf; + } + if ((m->mc = gmac_byname(mm)) == 0) + die(EXIT_FAILURE, "unknown message authentication scheme `%s'", mm); + dstr_reset(&d); + + if ((err = key_unpack(&m->kp, kd, &d)) != 0) { + die(EXIT_FAILURE, "failed to unpack symmetric key `%s': %s", + d.buf, key_strerror(err)); + } + dstr_destroy(&d); + + if (keysz(m->kb.sz, m->mc->keysz) != m->kb.sz) { + die(EXIT_FAILURE, "bad key size %lu for `%s'", + (unsigned long)m->kb.sz, m->mc->name); + } + m->m = GM_KEY(m->mc, m->kb.k, m->kb.sz); + m->s.h = GM_INIT(m->m); + return (&m->s); +} + +static int mac_sigdoit(sig *s, dstr *d) +{ + mac_ctx *m = (mac_ctx *)s; + + dstr_ensure(d, m->mc->hashsz); + GH_DONE(m->s.h, d->buf); + d->len += m->mc->hashsz; + return (0); +} + +static int mac_vrfdoit(sig *s, dstr *d) +{ + mac_ctx *m = (mac_ctx *)s; + const octet *t; + + t = GH_DONE(m->s.h, 0); + if (d->len != m->mc->hashsz || memcmp(d->buf, t, d->len) != 0) + return (-1); + return (0); +} + +static const char *mac_check(sig *s) { return (0); } + +static void mac_destroy(sig *s) +{ + mac_ctx *m = (mac_ctx *)s; + GM_DESTROY(m->m); + key_unpackdone(&m->kp); +} + +static const sigops mac_sig = { + 0, 0, + mac_init, mac_sigdoit, mac_check, mac_destroy +}; + +static const sigops mac_vrf = { + 0, 0, + mac_init, mac_vrfdoit, mac_check, mac_destroy +}; + /* --- The switch table --- */ const struct sigtab sigtab[] = { @@ -581,6 +668,7 @@ const struct sigtab sigtab[] = { { "kcdsa", &kcdsa_sig, &kcdsa_vrf, &has160 }, { "binkcdsa", &binkcdsa_sig, &binkcdsa_vrf, &has160 }, { "eckcdsa", &eckcdsa_sig, &eckcdsa_vrf, &has160 }, + { "mac", &mac_sig, &mac_vrf, &rmd160 }, { 0, 0, 0 } }; @@ -665,16 +753,24 @@ s_found:; /* --- Load the key --- */ - kd = xmalloc(so->kdsz); - kp = key_fetchinit(so->kf, 0, kd); - if ((e = key_fetch(kp, k)) != 0) - die(EXIT_FAILURE, "error fetching key `%s': %s", t.buf, key_strerror(e)); + if (!so->kf) { + kd = k->k; + key_incref(kd); + } else { + kd = xmalloc(so->kdsz); + kp = key_fetchinit(so->kf, 0, kd); + if ((e = key_fetch(kp, k)) != 0) { + die(EXIT_FAILURE, "error fetching key `%s': %s", + t.buf, key_strerror(e)); + } + } s = so->init(k, kd, ch); if (!s->h) s->h = GH_INIT(ch); s->kp = kp; s->ops = so; s->kd = kd; + s->ch = ch; /* --- Free stuff up --- */ @@ -695,8 +791,12 @@ s_found:; void freesig(sig *s) { GH_DESTROY(s->h); - key_fetchdone(s->kp); - xfree(s->kd); + if (!s->ops->kf) + key_drop(s->kd); + else { + key_fetchdone(s->kp); + xfree(s->kd); + } s->ops->destroy(s); } diff --git a/cc.h b/cc.h index 5574e9e..4124b82 100644 --- a/cc.h +++ b/cc.h @@ -82,6 +82,7 @@ typedef struct sig { const struct sigops *ops; key_packdef *kp; void *kd; + gchash *ch; ghash *h; } sig; -- 2.11.0