catcrypt: Implement symmetric key-encapsulation and signature schemes.
[u/mdw/catacomb] / cc-sig.c
index 45679ce..dbcf902 100644 (file)
--- 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);
 }