Release 2.1.4.
[u/mdw/catacomb] / cc-kem.c
index 8ba29fd..63199fc 100644 (file)
--- a/cc-kem.c
+++ b/cc-kem.c
@@ -7,7 +7,7 @@
  * (c) 2004 Straylight/Edgeware
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of Catacomb.
  *
  * it under the terms of the GNU Library General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
- * 
+ *
  * Catacomb is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Library General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Library General Public
  * License along with Catacomb; if not, write to the Free
  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include <stdlib.h>
 
 #include <mLib/alloc.h>
@@ -169,14 +171,16 @@ typedef struct dh_encctx {
   ge *y;
 } dh_encctx;
 
-static dh_encctx *dh_doinit(key *k, const gprime_param *gp, mp *y)
+static dh_encctx *dh_doinit(key *k, const gprime_param *gp, mp *y,
+                           group *(*makegroup)(const gprime_param *),
+                           const char *what)
 {
   dh_encctx *de = CREATE(dh_encctx);
   dstr t = DSTR_INIT;
 
   key_fulltag(k, &t);
-  if ((de->g = group_prime(gp)) == 0)
-    die(EXIT_FAILURE, "bad prime group in key `%s'", t.buf);
+  if ((de->g = makegroup(gp)) == 0)
+    die(EXIT_FAILURE, "bad %s group in key `%s'", what, t.buf);
   de->x = MP_NEW;
   de->y = G_CREATE(de->g);
   if (G_FROMINT(de->g, de->y, y))
@@ -207,7 +211,14 @@ static dh_encctx *ec_doinit(key *k, const char *cstr, const ec *y)
 static kem *dh_encinit(key *k, void *kd)
 {
   dh_pub *dp = kd;
-  dh_encctx *de = dh_doinit(k, &dp->dp, dp->y);
+  dh_encctx *de = dh_doinit(k, &dp->dp, dp->y, group_prime, "prime");
+  return (&de->k);
+}
+
+static kem *bindh_encinit(key *k, void *kd)
+{
+  dh_pub *dp = kd;
+  dh_encctx *de = dh_doinit(k, &dp->dp, dp->y, group_binary, "binary");
   return (&de->k);
 }
 
@@ -226,7 +237,7 @@ static int dh_encdoit(kem *k, dstr *d, ghash *h)
   ge *y = G_CREATE(de->g);
   size_t n = de->g->noctets;
   buf b;
-  
+
   G_EXP(de->g, x, de->g->g, r);
   G_EXP(de->g, y, de->y, r);
   dstr_ensure(d, n);
@@ -260,6 +271,7 @@ static void dh_encdestroy(kem *k)
   G_DESTROY(de->g, de->y);
   mp_drop(de->x);
   G_DESTROYGROUP(de->g);
+  DESTROY(de);
 }
 
 static const kemops dh_encops = {
@@ -267,6 +279,11 @@ static const kemops dh_encops = {
   dh_encinit, dh_encdoit, dh_enccheck, dh_encdestroy
 };
 
+static const kemops bindh_encops = {
+  dh_pubfetch, sizeof(dh_pub),
+  bindh_encinit, dh_encdoit, dh_enccheck, dh_encdestroy
+};
+
 static const kemops ec_encops = {
   ec_pubfetch, sizeof(ec_pub),
   ec_encinit, dh_encdoit, dh_enccheck, dh_encdestroy
@@ -275,7 +292,15 @@ static const kemops ec_encops = {
 static kem *dh_decinit(key *k, void *kd)
 {
   dh_priv *dp = kd;
-  dh_encctx *de = dh_doinit(k, &dp->dp, dp->y);
+  dh_encctx *de = dh_doinit(k, &dp->dp, dp->y, group_prime, "prime");
+  de->x = MP_COPY(dp->x);
+  return (&de->k);
+}
+
+static kem *bindh_decinit(key *k, void *kd)
+{
+  dh_priv *dp = kd;
+  dh_encctx *de = dh_doinit(k, &dp->dp, dp->y, group_binary, "binary");
   de->x = MP_COPY(dp->x);
   return (&de->k);
 }
@@ -317,17 +342,85 @@ static const kemops dh_decops = {
   dh_decinit, dh_decdoit, dh_enccheck, dh_encdestroy
 };
 
+static const kemops bindh_decops = {
+  dh_privfetch, sizeof(dh_priv),
+  bindh_decinit, dh_decdoit, dh_enccheck, dh_encdestroy
+};
+
 static const kemops ec_decops = {
   ec_privfetch, sizeof(ec_priv),
   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[] = {
   { "rsa",     &rsa_encops,    &rsa_decops },
   { "dh",      &dh_encops,     &dh_decops },
+  { "bindh",   &bindh_encops,  &bindh_decops },
   { "ec",      &ec_encops,     &ec_decops },
+  { "symm",    &symm_encops,   &symm_decops },
   { 0,         0,              0 }
 };
 
@@ -408,10 +501,18 @@ 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);
+    kp = 0;
+  } 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;
@@ -442,7 +543,7 @@ k_found:;
     die(EXIT_FAILURE, "encryption scheme (KDF) `%s' not found in key `%s'",
        q, t.buf);
   }
-    
+
   dstr_reset(&d);
   if ((q = key_getattr(0, k, "mac")) == 0) {
     dstr_putf(&d, "%s-hmac", kk->h->name);
@@ -516,8 +617,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);
 }