Add simple public-key encryption program `catcrypt'.
authormdw <mdw>
Sat, 17 Apr 2004 09:58:37 +0000 (09:58 +0000)
committermdw <mdw>
Sat, 17 Apr 2004 09:58:37 +0000 (09:58 +0000)
15 files changed:
Makefile.m4
blkc.h
catcrypt.c [new file with mode: 0644]
cbc-def.h
cc-enc.c [new file with mode: 0644]
cc-kem.c [new file with mode: 0644]
cc-sig.c [new file with mode: 0644]
cc.h [new file with mode: 0644]
cfb-def.h
dsig.c
ec-info.c
ecb-def.h
g-ec.c
group-stdops.c
group.h

index bb976cc..066ef52 100644 (file)
@@ -1,6 +1,6 @@
 ## -*-m4-*-
 ##
-## $Id: Makefile.m4,v 1.81 2004/04/08 16:17:32 mdw Exp $
+## $Id: Makefile.m4,v 1.82 2004/04/17 09:58:36 mdw Exp $
 ##
 ## Makefile for Catacomb
 ##
@@ -245,14 +245,15 @@ patsubst(MP_SOURCES, `\.c\>', `.lo') dsig.o keyutil.o rspit.o: \
 
 ## --- Utility programs ---
 
-bin_PROGRAMS = dsig key pixie rspit factorial hashsum mkphrase
+bin_PROGRAMS = dsig key pixie rspit factorial hashsum mkphrase catcrypt
 bin_SCRIPTS = catacomb-config xpixie
 noinst_PROGRAMS = \
        genprimes mptypes serpent-check bittest mpdump \
        addsuffix(`gen_tables', `-mktab')
 LDADD = libcatacomb.la
 
-dsig_SOURCES = dsig.c getdate.y getdate.h
+dsig_SOURCES = dsig.c cc.h cc-sig.c getdate.y getdate.h
+catcrypt_SOURCES = catcrypt.c cc.h cc-sig.c cc-kem.c cc-enc.c
 key_SOURCES = keyutil.c getdate.y getdate.h
 hashsum_SOURCES = hashsum.c
 rspit_SOURCES = rspit.c
diff --git a/blkc.h b/blkc.h
index dfbd4f7..77ecf0e 100644 (file)
--- a/blkc.h
+++ b/blkc.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: blkc.h,v 1.7 2004/04/08 01:36:15 mdw Exp $
+ * $Id: blkc.h,v 1.8 2004/04/17 09:58:36 mdw Exp $
  *
  * Common definitions for block ciphers
  *
   BLKC_GLUE(BLKC_STEP_X_, BLKC_ENDIAN(PRE))                            \
     (PRE, w)
 
+#define BLKC_ZERO(PRE, w)                                              \
+  BLKC_GLUE(BLKC_ZERO_, BLKC_TYPE(PRE))                                        \
+    (PRE, w, BLKC_BITS(PRE))
+
 #define BLKC_SET(PRE, w, x)                                            \
   BLKC_GLUE(BLKC_SET_X_, BLKC_ENDIAN(PRE))                             \
     (PRE, w, x)
   BLKC_SKEL_X(PRE, BLKC_W(w); const BLKC_WX(wx);,                      \
              *_w ^= *_wx; _w++; _wx++; )                               \
 
+#define BLKC_ZERO_X(PRE, w, n)                                         \
+  BLKC_SKEL_X(PRE, BLKC_W(w);, *_w++ = 0;)
+
 #define BLKC_STEP_X_B(PRE, w) do {                                     \
   unsigned _i = PRE##_BLKSZ / 4; BLKC_W(w); uint32 _x = 0;             \
   while (_i && !_x) { _i--; _w[_i] = _x = U32(_w[_i] + 1); }           \
 #define BLKC_XLOAD_GUTS(op, i) _w[i] ^= op(_p + 4 * i)
 #define BLKC_MOVE_GUTS(op, i) _w[i] = _wx[i]
 #define BLKC_XMOVE_GUTS(op, i) _w[i] ^= _wx[i]
+#define BLKC_ZERO_GUTS(op, i) _w[i] = 0
 
 #define BLKC_STORE_N(PRE, b, w, op, n)                                 \
   BLKC_GLUE(BLKC_SKEL_, n)                                             \
   BLKC_GLUE(BLKC_SKEL_, n)                                             \
     (PRE, BLKC_W(w); const BLKC_WX(wx);, op, BLKC_MOVE_GUTS)
 
+#define BLKC_ZERO_N(PRE, w, n)                                         \
+  BLKC_GLUE(BLKC_SKEL_, n)                                             \
+    (PRE, BLKC_W(w); , op, BLKC_ZERO_GUTS)
+
 #define BLKC_XMOVE_N(PRE, w, wx, n)                                    \
   BLKC_GLUE(BLKC_SKEL_, n)                                             \
     (PRE, BLKC_W(w); const BLKC_WX(wx);, op, BLKC_XMOVE_GUTS)
diff --git a/catcrypt.c b/catcrypt.c
new file mode 100644 (file)
index 0000000..1ffae77
--- /dev/null
@@ -0,0 +1,757 @@
+/* -*-c-*-
+ *
+ * $Id: catcrypt.c,v 1.1 2004/04/17 09:58:36 mdw Exp $
+ *
+ * Command-line encryption tool
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * 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,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/base64.h>
+#include <mLib/dstr.h>
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+#include <mLib/sub.h>
+
+#include "buf.h"
+#include "rand.h"
+#include "noise.h"
+#include "mprand.h"
+#include "key.h"
+#include "cc.h"
+
+/*----- Utilities ---------------------------------------------------------*/
+
+/* --- @keyreport@ --- *
+ *
+ * Arguments:   @const char *file@ = filename containing the error
+ *              @int line@ = line number in file
+ *              @const char *err@ = error text message
+ *              @void *p@ = unimportant pointer
+ *
+ * Returns:     ---
+ *
+ * Use:         Reports errors during the opening of a key file.
+ */
+
+static void keyreport(const char *file, int line, const char *err, void *p)
+{
+  moan("error in keyring `%s' at line `%s': %s", file, line, err);
+}
+
+/*----- Static variables --------------------------------------------------*/
+
+static const char *keyring = "keyring";
+
+/*----- Data format -------------------------------------------------------*/
+
+/* --- Overview --- *
+ *
+ * The encrypted message is divided into chunks, each preceded by a two-octet
+ * length.  The chunks don't need to be large -- the idea is that we can
+ * stream the chunks in and out.
+ *
+ * The first chunk is a header.  It contains the decryption key-id, and maybe
+ * the verification key-id if the message is signed.
+ *
+ * Next comes the key-encapsulation chunk.  This is decrypted in some
+ * KEM-specific way to yield a secret hash.  This hash is what is signed if
+ * the message is signed.  The hash is expanded using an MGF (or similar) to
+ * make a symmetric encryption and MAC key.
+ *
+ * If the message is signed, there comes a signature chunk.  The signature is
+ * on the secret hash.  This means that the recipient can modify the message
+ * and still have a valid signature, so it's not useful for proving things to
+ * other people; but it also means that the recipient knows that the message
+ * is from someone who knows the hash, which limits the possiblities to (a)
+ * whoever encrypted the message (good!) and (b) whoever knows the
+ * recipient's private key.
+ *
+ * Then come message chunks.  Each one begins with a MAC over an implicit
+ * sequence number and the ciphertext.  The final chunk's ciphertext is
+ * empty; no other chunk is empty.  Thus can the correct end-of-file be
+ * discerned.
+ */
+
+/*----- Chunk I/O ---------------------------------------------------------*/
+
+static void chunk_write(enc *e, buf *b)
+{
+  octet l[2];
+  size_t n = BLEN(b);
+  assert(n <= MASK16);
+  STORE16(l, n);
+  if (e->ops->write(e, l, 2) ||
+      e->ops->write(e, BBASE(b), BLEN(b)))
+    die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+}
+
+static void chunk_read(enc *e, dstr *d, buf *b)
+{
+  octet l[2];
+  size_t n;
+
+  dstr_reset(d);
+  errno = 0;
+  if (e->ops->read(e, l, 2) != 2)
+    goto err;
+  n = LOAD16(l);
+  dstr_ensure(d, n);
+  if (e->ops->read(e, d->buf, n) != n)
+    goto err;
+  d->len = n;
+  buf_init(b, d->buf, d->len);
+  return;
+
+err:
+  if (!errno) die(EXIT_FAILURE, "unexpected end-of-file on input");
+  else die(EXIT_FAILURE, "error reading input: %s", strerror(errno));
+}
+
+/*----- Encryption --------------------------------------------------------*/
+
+static int encrypt(int argc, char *argv[])
+{
+  const char *of = 0, *kn = "ccrypt";
+  FILE *ofp = 0;
+  FILE *fp = 0;
+  const char *ef = "binary";
+  const char *err;
+  int i;
+  size_t n;
+  dstr d = DSTR_INIT;
+  octet *tag, *ct;
+  buf b;
+  size_t seq;
+  char bb[16384];
+  unsigned f = 0;
+  key_file kf;
+  key *k;
+  kem *km;
+  gcipher *cx, *c;
+  gmac *m;
+  ghash *h;
+  const encops *eo;
+  enc *e;
+
+#define f_bogus 1u
+
+  for (;;) {
+    static const struct option opt[] = {
+      { "key",         OPTF_ARGREQ,    0,      'k' },
+      { "armour",      0,              0,      'a' },
+      { "armor",       0,              0,      'a' },
+      { "format",      OPTF_ARGREQ,    0,      'f' },
+      { "output",      OPTF_ARGREQ,    0,      'o' },
+      { 0,             0,              0,      0 }
+    };
+    i = mdwopt(argc, argv, "k:af:o:", opt, 0, 0, 0);
+    if (i < 0) break;
+    switch (i) {
+      case 'k': kn = optarg; break;
+      case 'a': ef = "pem"; break;
+      case 'f': ef = optarg; break;
+      case 'o': of = optarg; break;
+      default: f |= f_bogus; break;
+    }
+  }
+  if (argc - optind > 1 || (f & f_bogus))
+    die(EXIT_FAILURE, "Usage: encrypt [-options] [file]");
+
+  if (key_open(&kf, keyring, KOPEN_READ, keyreport, 0))
+    die(EXIT_FAILURE, "can't open keyring `%s'", keyring);
+  if ((k = key_bytag(&kf, kn)) == 0)
+    die(EXIT_FAILURE, "key `%s' not found", kn);
+
+  if ((eo = getenc(ef)) == 0)
+    die(EXIT_FAILURE, "encoding `%s' not found", ef);
+
+  if (optind == argc)
+    fp = stdin;
+  else if (strcmp(argv[optind], "-") == 0) {
+    fp = stdin;
+    optind++;
+  } else if ((fp = fopen(argv[optind], "rb")) == 0) {
+    die(EXIT_FAILURE, "couldn't open file `%s': %s",
+       argv[optind], strerror(errno));
+  } else
+    optind++;
+
+  if (!of || strcmp(of, "-") == 0)
+    ofp = stdout;
+  else if ((ofp = fopen(of, eo->wmode)) == 0) {
+    die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
+       ofp, strerror(errno));
+  }
+
+  key_fulltag(k, &d);
+  e = initenc(eo, ofp, "CATCRYPT ENCRYPTED MESSAGE", 1);
+  km = getkem(k, "ccrypt", 0);
+  if ((err = km->ops->check(km)) != 0)
+    moan("key `%s' fails check: %s", d.buf, err);
+
+  /* --- Build the header chunk --- */
+
+  dstr_reset(&d);
+  dstr_ensure(&d, 256);
+  buf_init(&b, d.buf, 256);
+  buf_putu32(&b, k->id);
+  assert(BOK(&b));
+  chunk_write(e, &b);
+
+  /* --- Build the KEM chunk --- */
+
+  dstr_reset(&d);
+  if (setupkem(km, &d, &cx, &c, &m))
+    die(EXIT_FAILURE, "failed to encapsulate key");
+  buf_init(&b, d.buf, d.len);
+  BSTEP(&b, d.len);
+  chunk_write(e, &b);
+
+  /* --- Now do the main crypto --- */
+
+  assert(GC_CLASS(c)->blksz <= sizeof(bb));
+  dstr_ensure(&d, sizeof(bb) + GM_CLASS(m)->hashsz);
+  seq = 0;
+  for (;;) {
+    h = GM_INIT(m);
+    STORE32(bb, seq);
+    GH_HASH(h, bb, 4);
+    seq++;
+    if (GC_CLASS(c)->blksz) {
+      GC_ENCRYPT(cx, 0, bb, GC_CLASS(c)->blksz);
+      GC_SETIV(c, bb);
+    }
+    n = fread(bb, 1, sizeof(bb), fp);
+    if (!n) break;
+    buf_init(&b, d.buf, d.sz);
+    tag = buf_get(&b, GM_CLASS(m)->hashsz);
+    ct = buf_get(&b, n);
+    assert(tag); assert(ct);
+    GC_ENCRYPT(c, bb, ct, n);
+    GH_HASH(h, ct, n);
+    GH_DONE(h, tag);
+    GH_DESTROY(h);
+    chunk_write(e, &b);
+  }
+
+  /* --- Final terminator packet --- */
+
+  buf_init(&b, d.buf, d.sz);
+  tag = buf_get(&b, GM_CLASS(m)->hashsz);
+  assert(tag);
+  GH_DONE(h, tag);
+  GH_DESTROY(h);
+  chunk_write(e, &b);
+
+  /* --- All done --- */
+
+  e->ops->encdone(e);
+  GM_DESTROY(m);
+  GC_DESTROY(c);
+  GC_DESTROY(cx);
+  freeenc(e);
+  freekem(km);
+  if (of) fclose(ofp);
+  key_close(&kf);
+  dstr_destroy(&d);
+  return (0);
+
+#undef f_bogus
+}
+
+/*---- Decryption ---------------------------------------------------------*/
+
+static int decrypt(int argc, char *argv[])
+{
+  const char *of = 0;
+  FILE *ofp = 0;
+  FILE *fp = 0;
+  const char *ef = "binary";
+  int i;
+  dstr d = DSTR_INIT;
+  buf b;
+  key_file kf;
+  size_t seq;
+  uint32 id;
+  key *k;
+  kem *km;
+  gcipher *cx;
+  gcipher *c;
+  ghash *h;
+  gmac *m;
+  octet *tag;
+  unsigned f = 0;
+  const encops *eo;
+  enc *e;
+
+#define f_bogus 1u
+
+  for (;;) {
+    static const struct option opt[] = {
+      { "armour",      0,              0,      'a' },
+      { "armor",       0,              0,      'a' },
+      { "format",      OPTF_ARGREQ,    0,      'f' },
+      { "output",      OPTF_ARGREQ,    0,      'o' },
+      { 0,             0,              0,      0 }
+    };
+    i = mdwopt(argc, argv, "af:o:", opt, 0, 0, 0);
+    if (i < 0) break;
+    switch (i) {
+      case 'a': ef = "pem"; break;
+      case 'f': ef = optarg; break;
+      case 'o': of = optarg; break;
+      default: f |= f_bogus; break;
+    }
+  }
+  if (argc - optind > 1 || (f & f_bogus))
+    die(EXIT_FAILURE, "Usage: decrypt [-options] [file]");
+
+  if ((eo = getenc(ef)) == 0)
+    die(EXIT_FAILURE, "encoding `%s' not found", ef);
+
+  if (optind == argc)
+    fp = stdin;
+  else if (strcmp(argv[optind], "-") == 0) {
+    fp = stdin;
+    optind++;
+  } else if ((fp = fopen(argv[optind], eo->rmode)) == 0) {
+    die(EXIT_FAILURE, "couldn't open file `%s': %s",
+       argv[optind], strerror(errno));
+  } else
+    optind++;
+
+  if (key_open(&kf, keyring, KOPEN_READ, keyreport, 0))
+    die(EXIT_FAILURE, "can't open keyring `%s'", keyring);
+
+  e = initenc(eo, fp, "CATCRYPT ENCRYPTED MESSAGE", 0);
+
+  /* --- Read the header chunk --- */
+
+  chunk_read(e, &d, &b);
+  if (buf_getu32(&b, &id))
+    die(EXIT_FAILURE, "malformed header: missing keyid");
+  if (BLEFT(&b))
+    die(EXIT_FAILURE, "malformed header: junk at end");
+
+  /* --- Find the key --- */
+
+  if ((k = key_byid(&kf, id)) == 0)
+    die(EXIT_FAILURE, "key id %08lx not found", (unsigned long)id);
+  km = getkem(k, "ccrypt", 1);
+
+  /* --- Read the KEM chunk --- */
+
+  chunk_read(e, &d, &b);
+  if (setupkem(km, &d, &cx, &c, &m))
+    die(EXIT_FAILURE, "failed to decapsulate key");
+
+  /* --- Now decrypt the main body --- */
+
+  if (!of || strcmp(of, "-") == 0)
+    ofp = stdout;
+  else if ((ofp = fopen(of, "wb")) == 0) {
+    die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
+       ofp, strerror(errno));
+  }
+
+  seq = 0;
+  dstr_ensure(&d, GC_CLASS(c)->blksz);
+  dstr_ensure(&d, 4);
+  for (;;) {
+    if (GC_CLASS(c)->blksz) {
+      GC_ENCRYPT(cx, 0, d.buf, GC_CLASS(c)->blksz);
+      GC_SETIV(c, d.buf);
+    }
+    h = GM_INIT(m);
+    STORE32(d.buf, seq);
+    GH_HASH(h, d.buf, 4);
+    seq++;
+    chunk_read(e, &d, &b);
+    if ((tag = buf_get(&b, GM_CLASS(m)->hashsz)) == 0)
+      die(EXIT_FAILURE, "bad ciphertext chunk: no tag");
+    GH_HASH(h, BCUR(&b), BLEFT(&b));
+    if (memcmp(tag, GH_DONE(h, 0), GM_CLASS(m)->hashsz) != 0)
+      die(EXIT_FAILURE, "bad ciphertext chunk: authentication failure");
+    if (!BLEFT(&b))
+      break;
+    GC_DECRYPT(c, BCUR(&b), BCUR(&b), BLEFT(&b));
+    if (fwrite(BCUR(&b), 1, BLEFT(&b), ofp) != BLEFT(&b))
+      die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+  }
+
+  if (fflush(ofp) || ferror(ofp))
+    die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+    
+  e->ops->decdone(e);
+  freeenc(e);
+  GC_DESTROY(c);
+  GC_DESTROY(cx);
+  GM_DESTROY(m);
+  freekem(km);
+  if (of) fclose(ofp);
+  key_close(&kf);
+  dstr_destroy(&d);
+  return (0);
+
+#undef f_bogus
+}
+
+/*----- Test code ---------------------------------------------------------*/
+
+static int encode(int argc, char *argv[])
+{
+  const char *of = 0;
+  FILE *ofp = 0;
+  FILE *fp = 0;
+  const char *ef = "binary";
+  const char *bd = "MESSAGE";
+  int i;
+  size_t n;
+  char buf[4096];
+  unsigned f = 0;
+  const encops *eo;
+  enc *e;
+
+#define f_bogus 1u
+
+  for (;;) {
+    static const struct option opt[] = {
+      { "format",      OPTF_ARGREQ,    0,      'f' },
+      { "boundary",    OPTF_ARGREQ,    0,      'b' },
+      { "output",      OPTF_ARGREQ,    0,      'o' },
+      { 0,             0,              0,      0 }
+    };
+    i = mdwopt(argc, argv, "f:b:o:", opt, 0, 0, 0);
+    if (i < 0) break;
+    switch (i) {
+      case 'f': ef = optarg; break;
+      case 'b': bd = optarg; break;
+      case 'o': of = optarg; break;
+      default: f |= f_bogus; break;
+    }
+  }
+  if (argc - optind > 1 || (f & f_bogus))
+    die(EXIT_FAILURE, "Usage: encode [-options] [file]");
+
+  if ((eo = getenc(ef)) == 0)
+    die(EXIT_FAILURE, "encoding `%s' not found", ef);
+
+  if (optind == argc)
+    fp = stdin;
+  else if (strcmp(argv[optind], "-") == 0) {
+    fp = stdin;
+    optind++;
+  } else if ((fp = fopen(argv[optind], "rb")) == 0) {
+    die(EXIT_FAILURE, "couldn't open file `%s': %s",
+       argv[optind], strerror(errno));
+  } else
+    optind++;
+
+  if (!of || strcmp(of, "-") == 0)
+    ofp = stdout;
+  else if ((ofp = fopen(of, eo->wmode)) == 0) {
+    die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
+       ofp, strerror(errno));
+  }
+
+  e = initenc(eo, ofp, bd, 1);
+
+  do {
+    n = fread(buf, 1, sizeof(buf), fp);
+    if (e->ops->write(e, buf, n))
+      die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+  } while (n == sizeof(buf));
+  e->ops->encdone(e);
+  freeenc(e);
+  return (0);
+
+#undef f_bogus
+}
+
+static int decode(int argc, char *argv[])
+{
+  const char *of = 0;
+  FILE *ofp = 0;
+  FILE *fp = 0;
+  const char *ef = "binary";
+  const char *bd = 0;
+  int i;
+  char buf[4096];
+  unsigned f = 0;
+  const encops *eo;
+  enc *e;
+
+#define f_bogus 1u
+
+  for (;;) {
+    static const struct option opt[] = {
+      { "format",      OPTF_ARGREQ,    0,      'f' },
+      { "boundary",    OPTF_ARGREQ,    0,      'b' },
+      { "output",      OPTF_ARGREQ,    0,      'o' },
+      { 0,             0,              0,      0 }
+    };
+    i = mdwopt(argc, argv, "f:b:o:", opt, 0, 0, 0);
+    if (i < 0) break;
+    switch (i) {
+      case 'f': ef = optarg; break;
+      case 'b': bd = optarg; break;
+      case 'o': of = optarg; break;
+      default: f |= f_bogus; break;
+    }
+  }
+  if (argc - optind > 1 || (f & f_bogus))
+    die(EXIT_FAILURE, "Usage: decode [-options] [file]");
+
+  if ((eo = getenc(ef)) == 0)
+    die(EXIT_FAILURE, "encoding `%s' not found", ef);
+
+  if (optind == argc)
+    fp = stdin;
+  else if (strcmp(argv[optind], "-") == 0) {
+    fp = stdin;
+    optind++;
+  } else if ((fp = fopen(argv[optind], eo->rmode)) == 0) {
+    die(EXIT_FAILURE, "couldn't open file `%s': %s",
+       argv[optind], strerror(errno));
+  } else
+    optind++;
+
+  if (!of || strcmp(of, "-") == 0)
+    ofp = stdout;
+  else if ((ofp = fopen(of, "wb")) == 0) {
+    die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
+       ofp, strerror(errno));
+  }
+
+  e = initenc(eo, fp, bd, 0);
+
+  do {
+    if ((i = e->ops->read(e, buf, sizeof(buf))) < 0)
+      die(EXIT_FAILURE, "error reading input: %s", strerror(errno));
+    if (fwrite(buf, 1, i, ofp) < i)
+      die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+  } while (i == sizeof(buf));
+  e->ops->decdone(e);
+  freeenc(e);
+  return (0);
+
+#undef f_bogus
+}
+
+/*----- Main code ---------------------------------------------------------*/
+
+typedef struct cmd {
+  const char *name;
+  int (*func)(int /*argc*/, char */*argv*/[]);
+  const char *usage;
+  const char *help;
+} cmd;
+
+static cmd cmdtab[] = {
+  { "encode", encode,
+    "encode [-f format] [-b label] [-o output] [file]",
+    "\
+Options:\n\
+\n\
+-f, --format=FORMAT    Encode to FORMAT.\n\
+-b, --boundary=LABEL   PEM boundary is LABEL.\n\
+-o, --output=FILE      Write output to FILE.\n\
+" },
+  { "decode", decode,
+    "decode [-f format] [-b label] [-o output] [file]",
+    "\
+Options:\n\
+\n\
+-f, --format=FORMAT    Decode from FORMAT.\n\
+-b, --boundary=LABEL   PEM boundary is LABEL.\n\
+-o, --output=FILE      Write output to FILE.\n\
+" },
+  { "encrypt", encrypt,
+    "encrypt [-a] [-k tag] [f format]] [-o output] [file]",
+    "\
+Options:\n\
+\n\
+-a, --armour           Same as `-f pem'.\n\
+-f, --format=FORMAT    Encode as FORMAT.\n\
+-k, --key=TAG          Use public key named by TAG.\n\
+-o, --output=FILE      Write output to FILE.\n\
+" },
+  { "decrypt", decrypt,
+    "decrypt [-t] [-o output] [file]", "\
+Options:\n\
+\n\
+-t, --text             Read PEM-encoded input.\n\
+-o, --output=FILE      Write output to FILE.\n\
+" },
+  { 0, 0, 0 }
+};
+
+/* --- @findcmd@ --- *
+ *
+ * Arguments:  @const char *name@ = a command name
+ *
+ * Returns:    Pointer to the command structure.
+ *
+ * Use:                Looks up a command by name.  If the command isn't found, an
+ *             error is reported and the program is terminated.
+ */
+
+static cmd *findcmd(const char *name)
+{
+  cmd *c, *chosen = 0;
+  size_t sz = strlen(name);
+
+  for (c = cmdtab; c->name; c++) {
+    if (strncmp(name, c->name, sz) == 0) {
+      if (c->name[sz] == 0) {
+       chosen = c;
+       break;
+      } else if (chosen)
+       die(EXIT_FAILURE, "ambiguous command name `%s'", name);
+      else
+       chosen = c;
+    }
+  }
+  if (!chosen)
+    die(EXIT_FAILURE, "unknown command name `%s'", name);
+  return (chosen);
+}
+
+static void version(FILE *fp)
+{
+  pquis(fp, "$, Catacomb version " VERSION "\n");
+}
+
+static void usage(FILE *fp)
+{
+  pquis(fp, "Usage: $ [-k keyring] command [args]\n");
+}
+
+static void help(FILE *fp, char **argv)
+{
+  cmd *c;
+
+  if (*argv) {
+    c = findcmd(*argv);
+    fprintf(fp, "Usage: %s [-k keyring] %s\n", QUIS, c->usage);
+    if (c->help) {
+      fputc('\n', fp); 
+      fputs(c->help, fp);
+    }
+  } else {
+    version(fp);
+    fputc('\n', fp);
+    usage(fp);
+    fputs("\n\
+Create and verify signatures on lists of files.\n\
+\n", fp);
+    for (c = cmdtab; c->name; c++)
+      fprintf(fp, "%s\n", c->usage);
+  }
+}
+
+/* --- @main@ --- *
+ *
+ * Arguments:  @int argc@ = number of command line arguments
+ *             @char *argv[]@ = vector of command line arguments
+ *
+ * Returns:    Zero if successful, nonzero otherwise.
+ *
+ * Use:                Signs or verifies signatures on lists of files.  Useful for
+ *             ensuring that a distribution is unmolested.
+ */
+
+int main(int argc, char *argv[])
+{
+  unsigned f = 0;
+
+#define f_bogus 1u
+
+  /* --- Initialize the library --- */
+
+  ego(argv[0]);
+  sub_init();
+  rand_noisesrc(RAND_GLOBAL, &noise_source);
+  rand_seed(RAND_GLOBAL, 160);
+
+  /* --- Parse options --- */
+
+  for (;;) {
+    static struct option opts[] = {
+      { "help",                0,              0,      'h' },
+      { "version",     0,              0,      'v' },
+      { "usage",       0,              0,      'u' },
+      { "keyring",     OPTF_ARGREQ,    0,      'k' },
+      { 0,             0,              0,      0 }
+    };
+    int i = mdwopt(argc, argv, "+hvu k:", opts, 0, 0, 0);
+    if (i < 0)
+      break;
+    switch (i) {
+      case 'h':
+       help(stdout, argv + optind);
+       exit(0);
+       break;
+      case 'v':
+       version(stdout);
+       exit(0);
+       break;
+      case 'u':
+       usage(stdout);
+       exit(0);
+      case 'k':
+       keyring = optarg;
+       break;
+      default:
+       f |= f_bogus;
+       break;
+    }
+  }
+
+  argc -= optind;
+  argv += optind;
+  optind = 0;
+  if (f & f_bogus || argc < 1) {
+    usage(stderr);
+    exit(EXIT_FAILURE);
+  }
+
+  /* --- Dispatch to the correct subcommand handler --- */
+
+  return (findcmd(argv[0])->func(argc, argv));
+
+#undef f_bogus
+}
+
+/*----- That's all, folks -------------------------------------------------*/
index c0fc600..00695ae 100644 (file)
--- a/cbc-def.h
+++ b/cbc-def.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: cbc-def.h,v 1.5 2004/04/08 01:36:15 mdw Exp $
+ * $Id: cbc-def.h,v 1.6 2004/04/17 09:58:36 mdw Exp $
  *
  * Definitions for cipher block chaining mode
  *
@@ -179,8 +179,10 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                           \
                                                                        \
     pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv);                           \
     BLKC_STORE(PRE, b, ctx->iv);                                       \
-    for (i = 0; i < sz; i++)                                           \
-      d[i] = b[i] ^ s[i];                                              \
+    if (d) {                                                           \
+      for (i = 0; i < sz; i++)                                         \
+        d[i] = b[i] ^ (s ? s[i] : 0);                                  \
+    }                                                                  \
     memmove(b, b + sz, PRE##_BLKSZ - sz);                              \
     memcpy(b + PRE##_BLKSZ - sz, d, sz);                               \
     BLKC_LOAD(PRE, ctx->iv, b);                                                \
@@ -195,11 +197,15 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                          \
    */                                                                  \
                                                                        \
   while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) {                 \
-    BLKC_XLOAD(PRE, ctx->iv, s);                                       \
+    if (s) {                                                           \
+      BLKC_XLOAD(PRE, ctx->iv, s);                                     \
+      s += PRE##_BLKSZ;                                                        \
+    }                                                                  \
     pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv);                           \
-    BLKC_STORE(PRE, d, ctx->iv);                                       \
-    s += PRE##_BLKSZ;                                                  \
-    d += PRE##_BLKSZ;                                                  \
+    if (d) {                                                           \
+      BLKC_STORE(PRE, d, ctx->iv);                                     \
+      d += PRE##_BLKSZ;                                                        \
+    }                                                                  \
     sz -= PRE##_BLKSZ;                                                 \
   }                                                                    \
                                                                        \
@@ -224,7 +230,7 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                            \
      * block.                                                          \
      */                                                                        \
                                                                        \
-    BLKC_XLOAD(PRE, ctx->iv, s);                                       \
+    if (s) BLKC_XLOAD(PRE, ctx->iv, s);                                        \
     pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv);                           \
     BLKC_STORE(PRE, b, ctx->iv);                                       \
                                                                        \
@@ -235,16 +241,16 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                          \
      * ciphertext block.                                               \
      */                                                                        \
                                                                        \
-    s += PRE##_BLKSZ;                                                  \
-    d += PRE##_BLKSZ;                                                  \
+    if (s) s += PRE##_BLKSZ;                                           \
+    if (d) d += PRE##_BLKSZ;                                           \
     for (i = 0; i < sz; i++) {                                         \
       register octet x = b[i];                                         \
-      b[i] ^= s[i];                                                    \
-      d[i] = x;                                                                \
+      if (s) b[i] ^= s[i];                                             \
+      if (d) d[i] = x;                                                 \
     }                                                                  \
     BLKC_LOAD(PRE, ctx->iv, b);                                                \
     pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv);                           \
-    BLKC_STORE(PRE, d - PRE##_BLKSZ, ctx->iv);                         \
+    if (d) BLKC_STORE(PRE, d - PRE##_BLKSZ, ctx->iv);                  \
   }                                                                    \
                                                                        \
   /* --- Done --- */                                                   \
diff --git a/cc-enc.c b/cc-enc.c
new file mode 100644 (file)
index 0000000..f44bb33
--- /dev/null
+++ b/cc-enc.c
@@ -0,0 +1,330 @@
+/* -*-c-*-
+ *
+ * $Id: cc-enc.c,v 1.1 2004/04/17 09:58:37 mdw Exp $
+ *
+ * Catcrypt data encoding
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * 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,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+
+#include <mLib/alloc.h>
+#include <mLib/base64.h>
+#include <mLib/dstr.h>
+#include <mLib/report.h>
+#include <mLib/sub.h>
+
+#include "cc.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- Binary --- */
+
+static enc *bin_init(FILE *fp, const char *msg)
+  { enc *e = CREATE(enc); return (e); }
+
+static int bin_read(enc *e, void *p, size_t sz)
+{
+  size_t n;
+  
+  if (!sz) return (0);
+  n = fread(p, 1, sz, e->fp);
+  if (!n || ferror(e->fp)) return (-1);
+  return (n);
+}
+
+static int bin_write(enc *e, const void *p, size_t sz)
+  { if (sz && fwrite(p, 1, sz, e->fp) < sz) return (-1); return (0); }
+
+static int bin_done(enc *e) { return (0); }
+
+static void bin_destroy(enc *e) { DESTROY(e); }
+
+/* --- PEM --- */
+
+typedef struct pem_encctx {
+  enc e;
+  char *msg;
+  unsigned f;
+  base64_ctx b;
+  dstr d;
+  size_t n;
+#define PEMF_NL 1u
+#define PEMF_EOF 2u
+} pem_encctx;
+
+static enc *pem_encinit(FILE *fp, const char *msg)
+{
+  pem_encctx *pe = CREATE(pem_encctx);
+  base64_init(&pe->b);
+  fprintf(fp, "-----BEGIN %s-----\n", msg);
+  pe->msg = xstrdup(msg);
+  dstr_create(&pe->d);
+  pe->n = 0;
+  pe->f = 0;
+  return (&pe->e);
+}
+
+static enc *pem_decinit(FILE *fp, const char *msg)
+{
+  char buf[128];
+  int i, d;
+  pem_encctx *pe;
+  int ch;
+
+  /* --- Go until I find a newline and `-----' --- */
+
+top:
+  d = 0;
+  for (;;) {
+    if ((ch = getc(fp)) == EOF) goto fail;
+    switch (ch) {
+      case '\n': d = 0; break;
+      case '-': if (d >= 0) { d++; if (d == 5) goto banner; }; break;
+      default: d = -1; break;
+    }
+  }
+
+  /* --- See what the banner looks like --- */
+
+banner:
+  i = d = 0;
+  for (;;) {
+    if ((ch = getc(fp)) == EOF) goto fail;
+    if (ch == '-') { d++; continue; }
+    if (ch == '\n') break;
+    if (i + d + 1 >= sizeof(buf)) goto top;
+    while (d) { buf[i++] = '-'; d--; }
+    buf[i++] = ch;
+  }
+  buf[i] = 0;
+
+  /* --- Check we have the right framing --- */
+
+  if (d != 5) goto top;
+  if (strncmp(buf, "BEGIN ", 6) != 0 ||
+      (msg && strcmp(buf + 6, msg) != 0))
+    goto top;
+
+  /* --- Ready --- */
+
+  pe = CREATE(pem_encctx);
+  base64_init(&pe->b);
+  pe->msg = xstrdup(buf + 6);
+  dstr_create(&pe->d);
+  pe->n = 0;
+  pe->f = PEMF_NL;
+  return (&pe->e);
+
+  /* --- Failed --- */
+
+fail:
+  die(EXIT_FAILURE, "initial encapsulation boundary not found");
+  return (0);
+}
+
+#define PEM_CHUNKSZ 4096
+
+static int pem_read(enc *e, void *p, size_t sz)
+{
+  pem_encctx *pe = (pem_encctx *)e;
+  char buf[PEM_CHUNKSZ];
+  char *pp = p;
+  int ch;
+  size_t n;
+  int rc = 0;
+
+  for (;;) {
+    n = pe->d.len - pe->n;
+    if (n > sz) n = sz;
+    memcpy(pp, pe->d.buf + pe->n, n);
+    pe->n += n;
+    pp += n;
+    rc += n;
+    sz -= n;
+    if (!sz) break;
+    if (pe->f & PEMF_EOF) return (rc ? rc : -1);
+    dstr_reset(&pe->d);
+    n = 0;
+    for (;;) {
+      if ((ch = getc(pe->e.fp)) == EOF) return (-1);
+      if ((pe->f & PEMF_NL) && ch == '-') {
+       ungetc(ch, pe->e.fp);
+       pe->f |= PEMF_EOF;
+       break;
+      }
+      if (ch == '\n') { pe->f |= PEMF_NL; continue; }
+      pe->f &= ~PEMF_NL;
+      buf[n++] = ch;
+      if (n >= PEM_CHUNKSZ) break;
+    }
+    if (n)
+      base64_decode(&pe->b, buf, n, &pe->d);
+    if (pe->f & PEMF_EOF)
+      base64_decode(&pe->b, 0, 0, &pe->d);
+    pe->n = 0;
+  }
+  return (rc);
+}
+
+static int pem_write(enc *e, const void *p, size_t sz)
+{
+  pem_encctx *pe = (pem_encctx *)e;
+  const char *pp = p;
+  size_t n;
+
+  while (sz) {
+    n = PEM_CHUNKSZ;
+    if (n > sz) n = sz;
+    dstr_reset(&pe->d);
+    base64_encode(&pe->b, pp, n, &pe->d);
+    if (fwrite(pe->d.buf, 1, pe->d.len, pe->e.fp) < pe->d.len)
+      return (-1);
+    pp += n;
+    sz -= n;
+  }
+  return (0);
+}
+
+static int pem_encdone(enc *e)
+{
+  pem_encctx *pe = (pem_encctx *)e;
+  dstr_reset(&pe->d);
+  base64_encode(&pe->b, 0, 0, &pe->d);
+  if (fwrite(pe->d.buf, 1, pe->d.len, pe->e.fp) < pe->d.len)
+    return (-1);
+  if (pe->b.lnlen) fputc('\n', pe->e.fp);
+  fprintf(pe->e.fp, "-----END %s-----\n", pe->msg);
+  return (0);
+}
+
+static int pem_decdone(enc *e)
+{
+  pem_encctx *pe = (pem_encctx *)e;
+  char buf[128];
+  int i, d;
+  int ch;
+
+  for (d = 0; d < 5; d++)
+    if ((ch = getc(pe->e.fp)) != '-') goto fail;
+  i = d = 0;
+  for (;;) {
+    if ((ch = getc(pe->e.fp)) == EOF) goto fail;
+    if (ch == '-') { d++; continue; }
+    if (ch == '\n') break;
+    if (i + d + 1 >= sizeof(buf)) goto fail;
+    while (d) { buf[i++] = '-'; d--; }
+    buf[i++] = ch;
+  }
+  if (d != 5) goto fail;
+  buf[i] = 0;
+  if (strncmp(buf, "END ", 4) != 0 || strcmp(buf + 4, pe->msg) != 0)
+    goto fail;
+  return (0);
+
+fail:
+  die(EXIT_FAILURE, "final encapsulation boundary not found");
+  return (-1);
+}
+
+static void pem_destroy(enc *e)
+{
+  pem_encctx *pe = (pem_encctx *)e;
+  dstr_destroy(&pe->d);
+  xfree(pe->msg);
+  DESTROY(pe);
+}
+
+/* --- Encoder table --- */
+
+static const encops enctab[] = {
+  { "binary", "rb", "wb",
+    bin_init, bin_init,
+    bin_read, bin_write,
+    bin_done, bin_done,
+    bin_destroy },
+  { "pem", "r", "w",
+    pem_encinit, pem_decinit,
+    pem_read, pem_write,
+    pem_encdone, pem_decdone,
+    pem_destroy },
+  { 0 }
+};  
+
+/* --- @getenc@ --- *
+ *
+ * Arguments:  @const char *enc@ = name of wanted encoding
+ *
+ * Returns:    Pointer to encoder operations.
+ *
+ * Use:                Finds a named encoder or decoder.
+ */
+
+const encops *getenc(const char *enc)
+{
+  const encops *eo;
+
+  for (eo = enctab; eo->name; eo++) {
+    if (strcmp(eo->name, enc) == 0)
+      goto e_found;
+  }
+  die(EXIT_FAILURE, "couldn't find encoding `%s'", enc);
+e_found:
+  return (eo);
+}
+
+/* --- @initenc@ --- *
+ *
+ * Arguments:  @const encops *eo@ = operations (from @getenc@)
+ *             @FILE *fp@ = file handle to attach
+ *             @const char *msg@ = banner message
+ *             @int wantenc@ = nonzero if we want to encode
+ *
+ * Returns:    The encoder object.
+ *
+ * Use:                Initializes an encoder.
+ */
+
+enc *initenc(const encops *eo, FILE *fp, const char *msg, int wantenc)
+{
+  enc *e = (wantenc ? eo->initenc : eo->initdec)(fp, msg);
+  e->ops = eo;
+  e->fp = fp;
+  return (e);  
+}
+
+/* --- @freeenc@ --- *
+ *
+ * Arguments:  @enc *e@ = encoder object
+ *
+ * Returns:    ---
+ *
+ * Use:                Frees an encoder object.
+ */
+
+void freeenc(enc *e) { e->ops->destroy(e); }
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/cc-kem.c b/cc-kem.c
new file mode 100644 (file)
index 0000000..4f71d0d
--- /dev/null
+++ b/cc-kem.c
@@ -0,0 +1,528 @@
+/* -*-c-*-
+ *
+ * $Id: cc-kem.c,v 1.1 2004/04/17 09:58:37 mdw Exp $
+ *
+ * Catcrypt key-encapsulation
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * 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,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdlib.h>
+
+#include <mLib/alloc.h>
+#include <mLib/dstr.h>
+#include <mLib/report.h>
+#include <mLib/sub.h>
+
+#include "mprand.h"
+#include "rand.h"
+
+#include "ec.h"
+#include "ec-keys.h"
+#include "dh.h"
+#include "rsa.h"
+
+#include "rmd160.h"
+#include "blowfish-cbc.h"
+
+#include "cc.h"
+
+/*----- Key encapsulation -------------------------------------------------*/
+
+/* --- RSA --- */
+
+typedef struct rsa_encctx {
+  kem k;
+  rsa_pubctx rp;
+} rsa_encctx;
+
+static kem *rsa_encinit(key *k, void *kd)
+{
+  rsa_encctx *re = CREATE(rsa_encctx);
+  rsa_pubcreate(&re->rp, kd);
+  return (&re->k);
+}
+
+static int rsa_encdoit(kem *k, dstr *d, ghash *h)
+{
+  rsa_encctx *re = (rsa_encctx *)k;
+  mp *x = mprand_range(MP_NEW, re->rp.rp->n, &rand_global, 0);
+  mp *y = rsa_pubop(&re->rp, MP_NEW, x);
+  size_t n = mp_octets(re->rp.rp->n);
+  dstr_ensure(d, n);
+  mp_storeb(x, d->buf, n);
+  GH_HASH(h, d->buf, n);
+  mp_storeb(y, d->buf, n);
+  d->len += n;
+  mp_drop(x);
+  mp_drop(y);
+  return (0);
+}
+
+static const char *rsa_lengthcheck(mp *n)
+{
+  if (mp_bits(n) < 1020) return ("key too short");
+  return (0);
+}
+
+static const char *rsa_enccheck(kem *k)
+{
+  rsa_encctx *re = (rsa_encctx *)k;
+  const char *e;
+  if ((e = rsa_lengthcheck(re->rp.rp->n)) != 0) return (e);
+  return (0);
+}
+
+static void rsa_encdestroy(kem *k)
+{
+  rsa_encctx *re = (rsa_encctx *)k;
+  rsa_pubdestroy(&re->rp);
+  DESTROY(re);
+}
+
+static const kemops rsa_encops = {
+  rsa_pubfetch, sizeof(rsa_pub),
+  rsa_encinit, rsa_encdoit, rsa_enccheck, rsa_encdestroy
+};
+
+typedef struct rsa_decctx {
+  kem k;
+  rsa_privctx rp;
+} rsa_decctx;
+
+static kem *rsa_decinit(key *k, void *kd)
+{
+  rsa_decctx *rd = CREATE(rsa_decctx);
+  rsa_privcreate(&rd->rp, kd, &rand_global);
+  return (&rd->k);
+}
+
+static int rsa_decdoit(kem *k, dstr *d, ghash *h)
+{
+  rsa_decctx *rd = (rsa_decctx *)k;
+  mp *x = mp_loadb(MP_NEW, d->buf, d->len);
+  size_t n;
+  char *p;
+
+  if (MP_CMP(x, >=, rd->rp.rp->n)) {
+    mp_drop(x);
+    return (-1);
+  }
+  n = mp_octets(rd->rp.rp->n);
+  p = xmalloc(n);
+  x = rsa_privop(&rd->rp, x, x);
+  mp_storeb(x, p, n);
+  GH_HASH(h, p, n);
+  mp_drop(x);
+  xfree(p);
+  return (0);
+}
+
+static const char *rsa_deccheck(kem *k)
+{
+  rsa_decctx *rd = (rsa_decctx *)k;
+  const char *e;
+  if ((e = rsa_lengthcheck(rd->rp.rp->n)) != 0) return (e);
+  return (0);
+}
+
+static void rsa_decdestroy(kem *k)
+{
+  rsa_decctx *rd = (rsa_decctx *)k;
+  rsa_privdestroy(&rd->rp);
+  DESTROY(rd);
+}
+
+static const kemops rsa_decops = {
+  rsa_privfetch, sizeof(rsa_priv),
+  rsa_decinit, rsa_decdoit, rsa_deccheck, rsa_decdestroy
+};
+
+/* --- DH and EC --- */
+
+typedef struct dh_encctx {
+  kem k;
+  group *g;
+  mp *x;
+  ge *y;
+} dh_encctx;
+
+static dh_encctx *dh_doinit(key *k, const gprime_param *gp, mp *y)
+{
+  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);
+  de->x = MP_NEW;
+  de->y = G_CREATE(de->g);
+  if (G_FROMINT(de->g, de->y, y))
+    die(EXIT_FAILURE, "bad public key `%s'", t.buf);
+  dstr_destroy(&t);
+  return (de);
+}
+
+static dh_encctx *ec_doinit(key *k, const char *cstr, const ec *y)
+{
+  dh_encctx *de = CREATE(dh_encctx);
+  ec_info ei;
+  const char *e;
+  dstr t = DSTR_INIT;
+
+  key_fulltag(k, &t);
+  if ((e = ec_getinfo(&ei, cstr)) != 0 ||
+      (de->g = group_ec(&ei)) == 0)
+    die(EXIT_FAILURE, "bad elliptic curve spec in key `%s': %s", t.buf, e);
+  de->x = MP_NEW;
+  de->y = G_CREATE(de->g);
+  if (G_FROMEC(de->g, de->y, y))
+    die(EXIT_FAILURE, "bad public curve point `%s'", t.buf);
+  dstr_destroy(&t);
+  return (de);
+}
+
+static kem *dh_encinit(key *k, void *kd)
+{
+  dh_pub *dp = kd;
+  dh_encctx *de = dh_doinit(k, &dp->dp, dp->y);
+  return (&de->k);
+}
+
+static kem *ec_encinit(key *k, void *kd)
+{
+  ec_pub *ep = kd;
+  dh_encctx *de = ec_doinit(k, ep->cstr, &ep->p);
+  return (&de->k);
+}
+
+static int dh_encdoit(kem *k, dstr *d, ghash *h)
+{
+  dh_encctx *de = (dh_encctx *)k;
+  mp *r = mprand_range(MP_NEW, de->g->r, &rand_global, 0);
+  ge *x = G_CREATE(de->g);
+  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);
+  buf_init(&b, d->buf, n);
+  G_TORAW(de->g, &b, y);
+  GH_HASH(h, BBASE(&b), BLEN(&b));
+  buf_init(&b, d->buf, n);
+  G_TORAW(de->g, &b, x);
+  GH_HASH(h, BBASE(&b), BLEN(&b));
+  d->len += BLEN(&b);
+  mp_drop(r);
+  G_DESTROY(de->g, x);
+  G_DESTROY(de->g, y);
+  return (0);
+}
+
+static const char *dh_enccheck(kem *k)
+{
+  dh_encctx *de = (dh_encctx *)k;
+  const char *e;
+  if ((e = G_CHECK(de->g, &rand_global)) != 0)
+    return (0);
+  if (group_check(de->g, de->y))
+    return ("public key not in subgroup");
+  return (0);
+}
+
+static void dh_encdestroy(kem *k)
+{
+  dh_encctx *de = (dh_encctx *)k;
+  G_DESTROY(de->g, de->y);
+  mp_drop(de->x);
+  G_DESTROYGROUP(de->g);
+}
+
+static const kemops dh_encops = {
+  dh_pubfetch, sizeof(dh_pub),
+  dh_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
+};
+
+static kem *dh_decinit(key *k, void *kd)
+{
+  dh_priv *dp = kd;
+  dh_encctx *de = dh_doinit(k, &dp->dp, dp->y);
+  de->x = MP_COPY(dp->x);
+  return (&de->k);
+}
+
+static kem *ec_decinit(key *k, void *kd)
+{
+  ec_priv *ep = kd;
+  dh_encctx *de = ec_doinit(k, ep->cstr, &ep->p);
+  de->x = MP_COPY(ep->x);
+  return (&de->k);
+}
+
+static int dh_decdoit(kem *k, dstr *d, ghash *h)
+{
+  dh_encctx *de = (dh_encctx *)k;
+  ge *x = G_CREATE(de->g);
+  size_t n = de->g->noctets;
+  void *p = xmalloc(n);
+  buf b;
+  int rc = -1;
+
+  buf_init(&b, d->buf, d->len);
+  if (G_FROMRAW(de->g, &b, x) || group_check(de->g, x))
+    goto done;
+  G_EXP(de->g, x, x, de->x);
+  buf_init(&b, p, n);
+  G_TORAW(de->g, &b, x);
+  GH_HASH(h, BBASE(&b), BLEN(&b));
+  GH_HASH(h, d->buf, d->len);
+  rc = 0;
+done:
+  G_DESTROY(de->g, x);
+  xfree(p);
+  return (rc);
+}
+
+static const kemops dh_decops = {
+  dh_privfetch, sizeof(dh_priv),
+  dh_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
+};
+
+/* --- The switch table --- */
+
+static const struct kemtab {
+  const char *name;
+  const kemops *encops;
+  const kemops *decops;
+} kemtab[] = {
+  { "rsa",     &rsa_encops,    &rsa_decops },
+  { "dh",      &dh_encops,     &dh_decops },
+  { "ec",      &ec_encops,     &ec_decops },
+  { 0,         0,              0 }
+};
+
+/* --- @getkem@ --- *
+ *
+ * Arguments:  @key *k@ = the key to load
+ *             @const char *app@ = application name
+ *             @int wantpriv@ = nonzero if we want to decrypt
+ *
+ * Returns:    A key-encapsulating thing.
+ *
+ * Use:                Loads a key.
+ */
+
+kem *getkem(key *k, const char *app, int wantpriv)
+{
+  const char *kalg, *halg = 0, *calg = 0;
+  dstr d = DSTR_INIT;
+  dstr t = DSTR_INIT;
+  size_t n;
+  char *p = 0;
+  const char *q;
+  kem *kk;
+  const struct kemtab *kt;
+  const kemops *ko;
+  void *kd;
+  int e;
+  key_packdef *kp;
+
+  /* --- Setup stuff --- */
+
+  key_fulltag(k, &t);
+
+  /* --- Get the KEM name --- *
+   *
+   * Take the attribute if it's there; otherwise use the key type.
+   */
+
+  n = strlen(app);
+  if ((q = key_getattr(0, k, "kem")) != 0) {
+    dstr_puts(&d, q);
+    p = d.buf;
+  } else if (strncmp(k->type, app, n) == 0 && k->type[n] == '-') {
+    dstr_puts(&d, k->type);
+    p = d.buf + n + 1;
+  } else
+    die(EXIT_FAILURE, "no KEM for key `%s'", t.buf);
+  kalg = p;
+
+  /* --- Grab the encryption scheme --- *
+   *
+   * Grab it from the KEM if it's there, but override it from the attribute.
+   */
+
+  if (p && (p = strchr(p, '/')) != 0) {
+    *p++ = 0;
+    calg = p;
+  }
+  if ((q = key_getattr(0, k, "cipher")) != 0)
+    calg = q;
+
+  /* --- Grab the hash function --- */
+
+  if (p && (p = strchr(p, '/')) != 0) {
+    *p++ = 0;
+    halg = p;
+  }
+  if ((q = key_getattr(0, k, "hash")) != 0)
+    halg = q;
+
+  /* --- Instantiate the KEM --- */
+
+  for (kt = kemtab; kt->name; kt++) {
+    if (strcmp(kt->name, kalg) == 0)
+      goto k_found;
+  }
+  die(EXIT_FAILURE, "key encapsulation mechanism `%s' not found in key `%s'",
+      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));
+  kk = ko->init(k, kd);
+  kk->kp = kp;
+  kk->ops = ko;
+  kk->kd = kd;
+
+  /* --- Set up the algorithms --- */
+
+  if (!halg)
+    kk->h = &rmd160;
+  else if ((kk->h = ghash_byname(halg)) == 0) {
+    die(EXIT_FAILURE, "hash algorithm `%s' not found in key `%s'",
+       halg, t.buf);
+  }
+
+  if (!calg)
+    kk->c = &blowfish_cbc;
+  else if ((kk->c = gcipher_byname(calg)) == 0) {
+    die(EXIT_FAILURE, "encryption scheme `%s' not found in key `%s'",
+       calg, t.buf);
+  }
+
+  dstr_reset(&d);
+  if ((q = key_getattr(0, k, "kdf")) == 0) {
+    dstr_putf(&d, "%s-mgf", kk->h->name);
+    q = d.buf;
+  }
+  if ((kk->cx = gcipher_byname(q)) == 0) {
+    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);
+    q = d.buf;
+  }
+  if ((kk->m = gmac_byname(q)) == 0) {
+    die(EXIT_FAILURE,
+       "message authentication code `%s' not found in key `%s'",
+       q, t.buf);
+  }
+
+  /* --- Tidy up --- */
+
+  dstr_destroy(&d);
+  dstr_destroy(&t);
+  return (kk);
+}
+
+/* --- @setupkem@ --- *
+ *
+ * Arguments:  @kem *k@ = key-encapsulation thing
+ *             @dstr *d@ = key-encapsulation data
+ *             @gcipher **cx@ = key-expansion function (for IVs)
+ *             @gcipher **c@ = where to put initialized encryption scheme
+ *             @gmac **m@ = where to put initialized MAC
+ *
+ * Returns:    Zero on success, nonzero on failure.
+ *
+ * Use:                Initializes all the various symmetric things from a KEM.
+ */
+
+int setupkem(kem *k, dstr *d, gcipher **cx, gcipher **c, gmac **m)
+{
+  octet *kd;
+  size_t n, cn, mn;
+  ghash *h;
+  int rc = 0;
+
+  h = GH_INIT(k->h);
+  if (k->ops->doit(k, d, h))
+    goto done;
+  n = keysz(GH_CLASS(h)->hashsz, k->cx->keysz);
+  if (!n)
+    goto done;
+  kd = GH_DONE(h, 0);
+  *cx = GC_INIT(k->cx, kd, n);
+
+  cn = keysz(0, k->c->keysz); n = cn;
+  mn = keysz(0, k->m->keysz); if (mn > n) n = mn;
+  kd = xmalloc(n);
+  GC_ENCRYPT(*cx, 0, kd, cn);
+  *c = GC_INIT(k->c, kd, cn);
+  GC_ENCRYPT(*cx, 0, kd, mn);
+  *m = GM_KEY(k->m, kd, mn);
+  xfree(kd);
+
+  rc = 0;
+done:
+  GH_DESTROY(h);
+  return (rc);
+}
+
+/* --- @freekem@ --- *
+ *
+ * Arguments:  @kem *k@ = key-encapsulation thing
+ *
+ * Returns:    ---
+ *
+ * Use:                Frees up a key-encapsulation thing.
+ */
+
+void freekem(kem *k)
+{
+  key_fetchdone(k->kp);
+  xfree(k->kd);
+  k->ops->destroy(k);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/cc-sig.c b/cc-sig.c
new file mode 100644 (file)
index 0000000..2bfe7e9
--- /dev/null
+++ b/cc-sig.c
@@ -0,0 +1,651 @@
+/* -*-c-*-
+ *
+ * $Id: cc-sig.c,v 1.1 2004/04/17 09:58:37 mdw Exp $
+ *
+ * Catcrypt signatures
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * 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,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdlib.h>
+
+#include <mLib/report.h>
+
+#include "rand.h"
+#include "sha.h"
+#include "has160.h"
+
+#include "ec.h"
+#include "ec-keys.h"
+#include "dh.h"
+#include "gdsa.h"
+#include "gkcdsa.h"
+#include "rsa.h"
+
+#include "cc.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- RSA PKCS1 --- */
+
+typedef struct rsap1_sigctx {
+  sig s;
+  rsa_privctx rp;
+  pkcs1 p1;
+} rsap1_sigctx;
+
+static sig *rsap1_siginit(key *k, void *kd, const gchash *hc)
+{
+  rsap1_sigctx *rs = CREATE(rsap1_sigctx);
+  rsa_privcreate(&rs->rp, kd, &rand_global);
+  rs->p1.r = &rand_global;
+  rs->p1.ep = hc->name;
+  rs->p1.epsz = strlen(hc->name) + 1;
+  rs->s.h = 0;
+  return (&rs->s);
+}
+
+static int rsap1_sigdoit(sig *s, dstr *d)
+{
+  rsap1_sigctx *rs = (rsap1_sigctx *)s;
+  size_t n;
+  mp *m = rsa_sign(&rs->rp, MP_NEW,
+                  GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,
+                  pkcs1_sigencode, &rs->p1);
+  if (!m) return (-1);
+  n = mp_octets(rs->rp.rp->n); dstr_ensure(d, n); mp_storeb(m, d->buf, n);
+  d->len += n; mp_drop(m);
+  return (0);
+}
+
+static const char *rsa_lengthcheck(mp *n)
+{
+  if (mp_bits(n) < 1024) return ("key too short");
+  return (0);
+}
+
+static const char *rsap1_sigcheck(sig *s)
+{
+  rsap1_sigctx *rs = (rsap1_sigctx *)s;
+  const char *e;
+  if ((e = rsa_lengthcheck(rs->rp.rp->n)) != 0) return (e);
+  return (0);
+}
+
+static void rsap1_sigdestroy(sig *s)
+{
+  rsap1_sigctx *rs = (rsap1_sigctx *)s;
+  rsa_privdestroy(&rs->rp);
+  DESTROY(rs);
+}
+
+static const sigops rsap1_sig = {
+  rsa_privfetch, sizeof(rsa_priv),
+  rsap1_siginit, rsap1_sigdoit, rsap1_sigcheck, rsap1_sigdestroy
+};
+
+typedef struct rsap1_vrfctx {
+  sig s;
+  rsa_pubctx rp;
+  pkcs1 p1;
+} rsap1_vrfctx;
+
+static sig *rsap1_vrfinit(key *k, void *kd, const gchash *hc)
+{
+  rsap1_vrfctx *rv = CREATE(rsap1_vrfctx);
+  rsa_pubcreate(&rv->rp, kd);
+  rv->p1.r = &rand_global;
+  rv->p1.ep = hc->name;
+  rv->p1.epsz = strlen(hc->name) + 1;
+  rv->s.h = 0;
+  return (&rv->s);
+}
+
+static int rsap1_vrfdoit(sig *s, dstr *d)
+{
+  rsap1_vrfctx *rv = (rsap1_vrfctx *)s;
+  mp *m = mp_loadb(MP_NEW, d->buf, d->len);
+  int rc = rsa_verify(&rv->rp, m,
+                     GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,
+                     0, pkcs1_sigdecode, &rv->p1);
+  mp_drop(m);
+  return (rc);
+}
+
+static const char *rsap1_vrfcheck(sig *s)
+{
+  rsap1_vrfctx *rv = (rsap1_vrfctx *)s;
+  const char *e;
+  if ((e = rsa_lengthcheck(rv->rp.rp->n)) != 0) return (e);
+  return (0);
+}
+
+static void rsap1_vrfdestroy(sig *s)
+{
+  rsap1_vrfctx *rv = (rsap1_vrfctx *)s;
+  rsa_pubdestroy(&rv->rp);
+  DESTROY(rv);
+}
+
+static const sigops rsap1_vrf = {
+  rsa_pubfetch, sizeof(rsa_pub),
+  rsap1_vrfinit, rsap1_vrfdoit, rsap1_vrfcheck, rsap1_vrfdestroy
+};
+
+/* --- RSA PSS --- */
+
+static const gccipher *getmgf(key *k, const gchash *hc)
+{
+  dstr d = DSTR_INIT;
+  const gccipher *gc;
+  const char *mm;
+
+  if ((mm = key_getattr(0, k, "mgf")) == 0) {
+    dstr_putf(&d, "%s-mgf", hc->name);
+    mm = d.buf;
+  }
+  if ((gc = gcipher_byname(mm)) == 0)
+    die(EXIT_FAILURE, "unknown encryption scheme `%s'", mm);
+  dstr_destroy(&d);
+  return (gc);
+}
+
+typedef struct rsapss_sigctx {
+  sig s;
+  rsa_privctx rp;
+  pss p;
+} rsapss_sigctx;
+
+static sig *rsapss_siginit(key *k, void *kd, const gchash *hc)
+{
+  rsapss_sigctx *rs = CREATE(rsapss_sigctx);
+  rsa_privcreate(&rs->rp, kd, &rand_global);
+  rs->p.r = &rand_global;
+  rs->p.cc = getmgf(k, hc);
+  rs->p.ch = hc;
+  rs->p.ssz = hc->hashsz;
+  rsa_privdestroy(&rs->rp);
+  return (&rs->s);
+}
+
+static int rsapss_sigdoit(sig *s, dstr *d)
+{
+  rsapss_sigctx *rs = (rsapss_sigctx *)s;
+  size_t n;
+  mp *m = rsa_sign(&rs->rp, MP_NEW,
+                  GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,
+                  pss_encode, &rs->p);
+  if (!m) return (-1);
+  n = mp_octets(rs->rp.rp->n); dstr_ensure(d, n); mp_storeb(m, d->buf, n);
+  d->len += n;  mp_drop(m);
+  return (0);
+}
+
+static const char *rsapss_sigcheck(sig *s)
+{
+  rsapss_sigctx *rs = (rsapss_sigctx *)s;
+  const char *e;
+  if ((e = rsa_lengthcheck(rs->rp.rp->n)) != 0) return (e);
+  return (0);
+}
+
+static void rsapss_sigdestroy(sig *s)
+{
+  rsapss_sigctx *rs = (rsapss_sigctx *)s;
+  rsa_privdestroy(&rs->rp);
+  DESTROY(rs);
+}
+
+static const sigops rsapss_sig = {
+  rsa_privfetch, sizeof(rsa_priv),
+  rsapss_siginit, rsapss_sigdoit, rsapss_sigcheck, rsapss_sigdestroy
+};
+
+typedef struct rsapss_vrfctx {
+  sig s;
+  rsa_pubctx rp;
+  pss p;
+} rsapss_vrfctx;
+
+static sig *rsapss_vrfinit(key *k, void *kd, const gchash *hc)
+{
+  rsapss_vrfctx *rv = CREATE(rsapss_vrfctx);
+  rsa_pubcreate(&rv->rp, kd);
+  rv->p.r = &rand_global;
+  rv->p.cc = getmgf(k, hc);
+  rv->p.ch = hc;
+  rv->p.ssz = hc->hashsz;
+  return (&rv->s);
+}
+
+static int rsapss_vrfdoit(sig *s, dstr *d)
+{
+  rsapss_vrfctx *rv = (rsapss_vrfctx *)s;
+  mp *m = mp_loadb(MP_NEW, d->buf, d->len);
+  int rc = rsa_verify(&rv->rp, m,
+                     GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,
+                     0, pss_decode, &rv->p);
+  mp_drop(m);
+  return (rc);
+}
+
+static const char *rsapss_vrfcheck(sig *s)
+{
+  rsapss_vrfctx *rv = (rsapss_vrfctx *)s;
+  const char *e;
+  if ((e = rsa_lengthcheck(rv->rp.rp->n)) != 0) return (e);
+  return (0);
+}
+
+static void rsapss_vrfdestroy(sig *s)
+{
+  rsapss_vrfctx *rv = (rsapss_vrfctx *)s;
+  rsa_pubdestroy(&rv->rp);
+  DESTROY(rv);
+}
+
+static const sigops rsapss_vrf = {
+  rsa_pubfetch, sizeof(rsa_pub),
+  rsapss_vrfinit, rsapss_vrfdoit, rsapss_vrfcheck, rsapss_vrfdestroy
+};
+
+/* --- DSA and ECDSA --- */
+
+typedef struct dsa_sigctx {
+  sig s;
+  gdsa g;
+} dsa_sigctx;
+
+static void dsa_initcommon(dsa_sigctx *ds, const gchash *hc,
+                          const char *ktag)
+{
+  ds->g.r = &rand_global;
+  ds->g.h = hc;
+  ds->g.u = MP_NEW;
+  ds->s.h = 0;
+}
+
+static dsa_sigctx *dsa_doinit(key *k, const gprime_param *gp,
+                             mp *y, const gchash *hc)
+{
+  dsa_sigctx *ds = CREATE(dsa_sigctx);
+  dstr t = DSTR_INIT;
+
+  key_fulltag(k, &t);
+  if ((ds->g.g = group_prime(gp)) == 0)
+    die(EXIT_FAILURE, "bad prime group in key `%s'", t.buf);
+  ds->g.p = G_CREATE(ds->g.g);
+  if (G_FROMINT(ds->g.g, ds->g.p, y))
+    die(EXIT_FAILURE, "bad public key in key `%s'", t.buf);
+  dsa_initcommon(ds, hc, t.buf);
+  dstr_destroy(&t);
+  return (ds);
+}
+
+static dsa_sigctx *ecdsa_doinit(key *k, const char *cstr,
+                               ec *y, const gchash *hc)
+{
+  dsa_sigctx *ds = CREATE(dsa_sigctx);
+  ec_info ei;
+  const char *e;
+  dstr t = DSTR_INIT;
+
+  key_fulltag(k, &t);
+  if ((e = ec_getinfo(&ei, cstr)) != 0)
+    die(EXIT_FAILURE, "bad curve in key `%s': %s", t.buf, e);
+  ds->g.g = group_ec(&ei);
+  ds->g.p = G_CREATE(ds->g.g);
+  if (G_FROMEC(ds->g.g, ds->g.p, y))
+    die(EXIT_FAILURE, "bad public key in key `%s'", t.buf);
+  dsa_initcommon(ds, hc, t.buf);
+  dstr_destroy(&t);
+  return (ds);
+}
+
+static sig *dsa_siginit(key *k, void *kd, const gchash *hc)
+{
+  dh_priv *dp = kd;
+  dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
+  ds->g.u = MP_COPY(dp->x);
+  return (&ds->s);
+}
+
+static sig *ecdsa_siginit(key *k, void *kd, const gchash *hc)
+{
+  ec_priv *ep = kd;
+  dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
+  ds->g.u = MP_COPY(ep->x);
+  return (&ds->s);
+}
+
+static int dsa_sigdoit(sig *s, dstr *d)
+{
+  dsa_sigctx *ds = (dsa_sigctx *)s;
+  gdsa_sig ss = GDSA_SIG_INIT;
+  size_t n = mp_octets(ds->g.g->r);
+
+  gdsa_sign(&ds->g, &ss, GH_DONE(ds->s.h, 0), 0);
+  dstr_ensure(d, 2 * n);
+  mp_storeb(ss.r, d->buf, n);
+  mp_storeb(ss.s, d->buf + n, n);
+  d->len += 2 * n;
+  mp_drop(ss.r); mp_drop(ss.s);
+  return (0);
+}
+
+static const char *dsa_sigcheck(sig *s)
+{
+  dsa_sigctx *ds = (dsa_sigctx *)s;
+  const char *e;
+  if ((e = G_CHECK(ds->g.g, &rand_global)) != 0)
+    return (0);
+  if (group_check(ds->g.g, ds->g.p))
+    return ("public key not in subgroup");
+  return (0);
+}
+
+static void dsa_sigdestroy(sig *s)
+{
+  dsa_sigctx *ds = (dsa_sigctx *)s;
+  G_DESTROY(ds->g.g, ds->g.p);
+  mp_drop(ds->g.u);
+  G_DESTROYGROUP(ds->g.g);
+}
+
+static const sigops dsa_sig = {
+  dh_privfetch, sizeof(dh_priv),
+  dsa_siginit, dsa_sigdoit, dsa_sigcheck, dsa_sigdestroy
+};
+
+static const sigops ecdsa_sig = {
+  ec_privfetch, sizeof(ec_priv),
+  ecdsa_siginit, dsa_sigdoit, dsa_sigcheck, dsa_sigdestroy
+};
+
+static sig *dsa_vrfinit(key *k, void *kd, const gchash *hc)
+{
+  dh_pub *dp = kd;
+  dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
+  return (&ds->s);
+}
+
+static sig *ecdsa_vrfinit(key *k, void *kd, const gchash *hc)
+{
+  ec_pub *ep = kd;
+  dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
+  return (&ds->s);
+}
+
+static int dsa_vrfdoit(sig *s, dstr *d)
+{
+  dsa_sigctx *ds = (dsa_sigctx *)s;
+  gdsa_sig ss;
+  size_t n = d->len/2;
+  int rc;
+
+  ss.r = mp_loadb(MP_NEW, d->buf, n);
+  ss.s = mp_loadb(MP_NEW, d->buf + n, d->len - n);
+  rc = gdsa_verify(&ds->g, &ss, GH_DONE(ds->s.h, 0));
+  mp_drop(ss.r); mp_drop(ss.s);
+  return (rc);
+}
+
+static const sigops dsa_vrf = {
+  dh_pubfetch, sizeof(dh_pub),
+  dsa_vrfinit, dsa_vrfdoit, dsa_sigcheck, dsa_sigdestroy
+};
+
+static const sigops ecdsa_vrf = {
+  ec_pubfetch, sizeof(ec_pub),
+  ecdsa_vrfinit, dsa_vrfdoit, dsa_sigcheck, dsa_sigdestroy
+};
+
+/* --- KCDSA and ECKCDSA --- */
+
+static void kcdsa_privkey(dsa_sigctx *ds, mp *x)
+  { ds->g.u = mp_modinv(MP_NEW, x, ds->g.g->r); }
+
+static void kcdsa_sethash(dsa_sigctx *ds, const gchash *hc)
+  { ds->s.h = gkcdsa_beginhash(&ds->g); }
+
+static sig *kcdsa_siginit(key *k, void *kd, const gchash *hc)
+{
+  dh_priv *dp = kd;
+  dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
+  kcdsa_privkey(ds, dp->x);
+  kcdsa_sethash(ds, hc);
+  return (&ds->s);
+}
+
+static sig *eckcdsa_siginit(key *k, void *kd, const gchash *hc)
+{
+  ec_priv *ep = kd;
+  dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
+  kcdsa_privkey(ds, ep->x);
+  kcdsa_sethash(ds, hc);
+  return (&ds->s);
+}
+
+static int kcdsa_sigdoit(sig *s, dstr *d)
+{
+  dsa_sigctx *ds = (dsa_sigctx *)s;
+  gkcdsa_sig ss = GKCDSA_SIG_INIT;
+  size_t hsz = ds->g.h->hashsz, n = mp_octets(ds->g.g->r);
+
+  gkcdsa_sign(&ds->g, &ss, GH_DONE(ds->s.h, 0), 0);
+  dstr_ensure(d, hsz + n);
+  memcpy(d->buf, ss.r, hsz);
+  mp_storeb(ss.s, d->buf + hsz, n);
+  d->len += hsz + n;
+  xfree(ss.r); mp_drop(ss.s);
+  return (0);
+}
+
+static const sigops kcdsa_sig = {
+  dh_privfetch, sizeof(dh_priv),
+  kcdsa_siginit, kcdsa_sigdoit, dsa_sigcheck, dsa_sigdestroy
+};
+
+static const sigops eckcdsa_sig = {
+  ec_privfetch, sizeof(ec_priv),
+  eckcdsa_siginit, kcdsa_sigdoit, dsa_sigcheck, dsa_sigdestroy
+};
+
+static sig *kcdsa_vrfinit(key *k, void *kd, const gchash *hc)
+{
+  dh_pub *dp = kd;
+  dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
+  kcdsa_sethash(ds, hc);
+  return (&ds->s);
+}
+
+static sig *eckcdsa_vrfinit(key *k, void *kd, const gchash *hc)
+{
+  ec_pub *ep = kd;
+  dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
+  kcdsa_sethash(ds, hc);
+  return (&ds->s);
+}
+
+static int kcdsa_vrfdoit(sig *s, dstr *d)
+{
+  dsa_sigctx *ds = (dsa_sigctx *)s;
+  gkcdsa_sig ss;
+  size_t hsz = ds->g.h->hashsz, n = d->len - hsz;
+  int rc;
+
+  if (d->len < hsz)
+    return (-1);
+  ss.r = (octet *)d->buf;
+  ss.s = mp_loadb(MP_NEW, d->buf + hsz, n);
+  rc = gkcdsa_verify(&ds->g, &ss, GH_DONE(ds->s.h, 0));
+  mp_drop(ss.s);
+  return (rc);
+}
+
+static const sigops kcdsa_vrf = {
+  dh_pubfetch, sizeof(dh_pub),
+  kcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigcheck, dsa_sigdestroy
+};
+
+static const sigops eckcdsa_vrf = {
+  ec_pubfetch, sizeof(ec_pub),
+  eckcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigcheck, dsa_sigdestroy
+};
+
+/* --- The switch table --- */
+
+static const struct sigtab {
+  const char *name;
+  const sigops *signops;
+  const sigops *verifyops;
+  const gchash *ch;
+} sigtab[] = {
+  { "rsapkcs1",        &rsap1_sig,     &rsap1_vrf,     &sha },
+  { "rsapss",  &rsapss_sig,    &rsapss_vrf,    &sha },
+  { "dsa",     &dsa_sig,       &dsa_vrf,       &sha },
+  { "ecdsa",   &ecdsa_sig,     &ecdsa_vrf,     &sha },
+  { "kcdsa",   &kcdsa_sig,     &kcdsa_vrf,     &has160 },
+  { "eckcdsa", &eckcdsa_sig,   &eckcdsa_vrf,   &has160 },
+  { 0,         0,              0 }
+};
+
+/* --- @getsig@ --- *
+ *
+ * Arguments:  @key *k@ = the key to load
+ *             @const char *app@ = application name
+ *             @int wantpriv@ = nonzero if we want to sign
+ *
+ * Returns:    A signature-making thing.
+ *
+ * Use:                Loads a key and starts hashing.
+ */
+
+sig *getsig(key *k, const char *app, int wantpriv)
+{
+  const char *salg, *halg = 0;
+  dstr d = DSTR_INIT;
+  dstr t = DSTR_INIT;
+  char *p = 0;
+  const char *q;
+  sig *s;
+  size_t n;
+  const struct sigtab *st;
+  const sigops *so;
+  const gchash *ch;
+  void *kd;
+  int e;
+  key_packdef *kp;
+
+  /* --- Setup stuff --- */
+
+  key_fulltag(k, &t);
+
+  /* --- Get the signature algorithm --- *
+   *
+   * Take the attribute if it's there; otherwise use the key type.
+   */
+
+  n = strlen(app);
+  if ((q = key_getattr(0, k, "sig")) != 0) {
+    dstr_puts(&d, q);
+    p = d.buf;
+  } else if (strncmp(k->type, app, n) == 0 && k->type[n] == '-') {
+    dstr_puts(&d, k->type);
+    p = d.buf + n + 1;
+  } else
+    die(EXIT_FAILURE, "no signature algorithm for key `%s'", t.buf);
+
+  /* --- Grab the hash algorithm --- *
+   *
+   * Grab it from the signature algorithm if it's there.  But override that
+   * from the attribute.
+   */
+
+  salg = p;
+  if ((p = strchr(p, '/')) != 0) {
+    *p++ = 0;
+    halg = p;
+  }
+  if ((q = key_getattr(0, k, "hash")) != 0)
+    halg = q;
+
+  /* --- Look up the algorithms in the table --- */
+
+  for (st = sigtab; st->name; st++) {
+    if (strcmp(st->name, salg) == 0)
+      goto s_found;
+  }
+  die(EXIT_FAILURE, "signature algorithm `%s' not found in key `%s'",
+      salg, t.buf);
+s_found:;
+  if (!halg)
+    ch = st->ch;
+  else {
+    if ((ch = ghash_byname(halg)) == 0) {
+      die(EXIT_FAILURE, "hash algorithm `%s' not found in key `%s'",
+         halg, t.buf);
+    }
+  }
+  so = wantpriv ? st->signops : st->verifyops;
+
+  /* --- 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));
+  s = so->init(k, kd, ch);
+  if (!s->h)
+    s->h = GH_INIT(ch);
+  s->kp = kp;
+  s->ops = so;
+  s->kd = kd;
+
+  /* --- Free stuff up --- */
+
+  dstr_destroy(&d);
+  dstr_destroy(&t);
+  return (s);
+}
+
+/* --- @freesig@ --- *
+ *
+ * Arguments:  @sig *s@ = signature-making thing
+ *
+ * Returns:    ---
+ *
+ * Use:                Frees up a signature-making thing
+ */
+
+void freesig(sig *s)
+{
+  GH_DESTROY(s->h);
+  key_fetchdone(s->kp);
+  xfree(s->kd);
+  s->ops->destroy(s);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/cc.h b/cc.h
new file mode 100644 (file)
index 0000000..7c2c092
--- /dev/null
+++ b/cc.h
@@ -0,0 +1,216 @@
+/* -*-c-*-
+ *
+ * $Id: cc.h,v 1.1 2004/04/17 09:58:37 mdw Exp $
+ *
+ * Catcrypt common stuff
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * 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,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_CC_H
+#define CATACOMB_CC_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+
+#include <mLib/dstr.h>
+
+#include "key.h"
+#include "gcipher.h"
+#include "ghash.h"
+#include "gmac.h"
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- Key encapsulation --- */
+
+typedef struct kem {
+  const struct kemops *ops;
+  key_packdef *kp;
+  void *kd;
+  const gchash *h;
+  const gccipher *c, *cx;
+  const gcmac *m;
+} kem;
+
+typedef struct kemops {
+  const key_fetchdef *kf;              /* Key fetching structure */
+  size_t kdsz;                         /* Size of the key-data structure */
+  kem *(*init)(key */*k*/, void */*kd*/);
+  int (*doit)(kem */*k*/, dstr */*d*/, ghash */*h*/);
+  const char *(*check)(kem */*k*/);
+  void (*destroy)(kem */*k*/);
+} kemops;
+
+/* --- Signing --- */
+
+typedef struct sig {
+  const struct sigops *ops;
+  key_packdef *kp;
+  void *kd;
+  ghash *h;
+} sig;
+
+typedef struct sigops {
+  const key_fetchdef *kf;              /* Key fetching structure */
+  size_t kdsz;                         /* Size of the key-data structure */
+  sig *(*init)(key */*k*/, void */*kd*/, const gchash */*hc*/);
+  int (*doit)(sig */*s*/, dstr */*d*/);
+  const char *(*check)(sig */*s*/);
+  void (*destroy)(sig */*s*/);
+} sigops;
+
+/* --- Data encoding --- */
+
+typedef struct enc {
+  const struct encops *ops;
+  FILE *fp;
+} enc;
+
+typedef struct encops {
+  const char *name;
+  const char *rmode, *wmode;
+  enc *(*initenc)(FILE */*fp*/, const char */*msg*/);
+  enc *(*initdec)(FILE */*fp*/, const char */*msg*/);
+  int (*read)(enc */*e*/, void */*p*/, size_t /*sz*/);
+  int (*write)(enc */*e*/, const void */*p*/, size_t /*sz*/);
+  int (*encdone)(enc */*e*/);
+  int (*decdone)(enc */*e*/);
+  void (*destroy)(enc */*e*/);
+} encops;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @getkem@ --- *
+ *
+ * Arguments:  @key *k@ = the key to load
+ *             @const char *app@ = application name
+ *             @int wantpriv@ = nonzero if we want to decrypt
+ *
+ * Returns:    A key-encapsulating thing.
+ *
+ * Use:                Loads a key.
+ */
+
+extern kem *getkem(key */*k*/, const char */*app*/, int /*wantpriv*/);
+
+/* --- @setupkem@ --- *
+ *
+ * Arguments:  @kem *k@ = key-encapsulation thing
+ *             @dstr *d@ = key-encapsulation data
+ *             @gcipher **cx@ = key-expansion function (for IVs)
+ *             @gcipher **c@ = where to put initialized encryption scheme
+ *             @gmac **m@ = where to put initialized MAC
+ *
+ * Returns:    Zero for success, nonzero on faliure.
+ *
+ * Use:                Initializes all the various symmetric things from a KEM.
+ */
+
+extern int setupkem(kem */*k*/, dstr */*d*/,
+                   gcipher **/*cx*/, gcipher **/*c*/, gmac **/*m*/);
+
+/* --- @freekem@ --- *
+ *
+ * Arguments:  @kem *k@ = key-encapsulation thing
+ *
+ * Returns:    ---
+ *
+ * Use:                Frees up a key-encapsulation thing.
+ */
+
+extern void freekem(kem */*k*/);
+
+/* --- @getsig@ --- *
+ *
+ * Arguments:  @key *k@ = the key to load
+ *             @const char *app@ = application name
+ *             @int wantpriv@ = nonzero if we want to sign
+ *
+ * Returns:    A signature-making thing.
+ *
+ * Use:                Loads a key and starts hashing.
+ */
+
+extern sig *getsig(key */*k*/, const char */*app*/, int /*wantpriv*/);
+
+/* --- @freesig@ --- *
+ *
+ * Arguments:  @sig *s@ = signature-making thing
+ *
+ * Returns:    ---
+ *
+ * Use:                Frees up a signature-making thing
+ */
+
+extern void freesig(sig */*s*/);
+
+/* --- @getenc@ --- *
+ *
+ * Arguments:  @const char *enc@ = name of wanted encoding
+ *
+ * Returns:    Pointer to encoder operations.
+ *
+ * Use:                Finds a named encoder or decoder.
+ */
+
+extern const encops *getenc(const char */*enc*/);
+
+/* --- @initenc@ --- *
+ *
+ * Arguments:  @const encops *eo@ = operations (from @getenc@)
+ *             @FILE *fp@ = file handle to attach
+ *             @const char *msg@ = banner message
+ *             @int wantenc@ = nonzero if we want to encode
+ *
+ * Returns:    The encoder object.
+ *
+ * Use:                Initializes an encoder.
+ */
+
+extern enc *initenc(const encops */*eo*/, FILE */*fp*/,
+                   const char */*msg*/, int /*wantenc*/);
+
+/* --- @freeenc@ --- *
+ *
+ * Arguments:  @enc *e@ = encoder object
+ *
+ * Returns:    ---
+ *
+ * Use:                Frees an encoder object.
+ */
+
+extern void freeenc(enc */*e*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index 647aa26..8de17b3 100644 (file)
--- a/cfb-def.h
+++ b/cfb-def.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: cfb-def.h,v 1.5 2004/04/08 01:36:15 mdw Exp $
+ * $Id: cfb-def.h,v 1.6 2004/04/17 09:58:37 mdw Exp $
  *
  * Definitions for ciphertext feedback mode
  *
@@ -207,7 +207,9 @@ void pre##_cfbencrypt(pre##_cfbctx *ctx,                            \
                                                                        \
   while (off < PRE##_BLKSZ) {                                          \
     register octet x = *s++;                                           \
-    *d++ = ctx->iv[off++] ^= x;                                                \
+    ctx->iv[off] ^= x;                                                 \
+    if (d) *d++ = ctx->iv[off];                                                \
+    off++;                                                             \
     sz--;                                                              \
   }                                                                    \
                                                                        \
@@ -221,10 +223,14 @@ void pre##_cfbencrypt(pre##_cfbctx *ctx,                          \
       pre##_eblk(&ctx->ctx, iv, iv);                                   \
       if (sz < PRE##_BLKSZ)                                            \
        break;                                                          \
-      BLKC_XLOAD(PRE, iv, s);                                          \
-      BLKC_STORE(PRE, d, iv);                                          \
-      s += PRE##_BLKSZ;                                                        \
-      d += PRE##_BLKSZ;                                                        \
+      if (s) {                                                         \
+       BLKC_XLOAD(PRE, iv, s);                                         \
+        s += PRE##_BLKSZ;                                              \
+      }                                                                        \
+      if (d) {                                                         \
+        BLKC_STORE(PRE, d, iv);                                                \
+        d += PRE##_BLKSZ;                                              \
+      }                                                                        \
       sz -= PRE##_BLKSZ;                                               \
     }                                                                  \
     off = 0;                                                           \
@@ -237,7 +243,9 @@ void pre##_cfbencrypt(pre##_cfbctx *ctx,                            \
   small:                                                               \
     do {                                                               \
       register octet x = *s++;                                         \
-      *d++ = ctx->iv[off++] ^= x;                                      \
+      ctx->iv[off] ^= x;                                               \
+      if (d) *d++ = ctx->iv[off];                                      \
+      off++;                                                           \
       sz--;                                                            \
     } while (sz);                                                      \
   }                                                                    \
diff --git a/dsig.c b/dsig.c
index 5a60444..2aeb9ef 100644 (file)
--- a/dsig.c
+++ b/dsig.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: dsig.c,v 1.11 2004/04/08 16:27:49 mdw Exp $
+ * $Id: dsig.c,v 1.12 2004/04/17 09:58:37 mdw Exp $
  *
  * Verify signatures on distribuitions of files
  *
 #include <mLib/sub.h>
 
 #include "getdate.h"
-#include "grand.h"
+#include "rand.h"
 #include "ghash.h"
 #include "key.h"
 #include "key-data.h"
 #include "noise.h"
-
-#include "ec.h"
-#include "ec-keys.h"
-#include "dh.h"
-#include "gdsa.h"
-#include "gkcdsa.h"
-#include "rsa.h"
-
-#include "sha.h"
-#include "has160.h"
-
-/*----- Algorithm choice --------------------------------------------------*/
-
-/* --- Relevant type operations --- */
-
-typedef struct sig {
-  const struct sigops *ops;
-  key_packdef *kp;
-  ghash *h;
-} sig;
-
-typedef struct sigops {
-  const key_fetchdef *kf;              /* Key fetching structure */
-  size_t kdsz;                         /* Size of the key-data structure */
-  sig *(*init)(key */*k*/, void */*kd*/, const gchash */*hc*/);
-  int (*doit)(sig */*s*/, dstr */*d*/);
-  void (*destroy)(sig */*s*/);
-} sigops;
-
-/* --- RSA PKCS1 --- */
-
-typedef struct rsap1_sigctx {
-  sig s;
-  rsa_privctx rp;
-  pkcs1 p1;
-} rsap1_sigctx;
-
-static sig *rsap1_siginit(key *k, void *kd, const gchash *hc)
-{
-  rsap1_sigctx *rs = CREATE(rsap1_sigctx);
-  rsa_privcreate(&rs->rp, kd, &rand_global);
-  rs->p1.r = &rand_global;
-  rs->p1.ep = hc->name;
-  rs->p1.epsz = strlen(hc->name) + 1;
-  rs->s.h = 0;
-  return (&rs->s);
-}
-
-static int rsap1_sigdoit(sig *s, dstr *d)
-{
-  rsap1_sigctx *rs = (rsap1_sigctx *)s;
-  size_t n;
-  mp *m = rsa_sign(&rs->rp, MP_NEW,
-                  GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,
-                  pkcs1_sigencode, &rs->p1);
-  if (!m) return (-1);
-  n = mp_octets(rs->rp.rp->n); dstr_ensure(d, n); mp_storeb(m, d->buf, n);
-  d->len += n; mp_drop(m);
-  return (0);
-}
-
-static void rsap1_sigdestroy(sig *s)
-{
-  rsap1_sigctx *rs = (rsap1_sigctx *)s;
-  DESTROY(rs);
-}
-
-static const sigops rsap1_sig = {
-  rsa_privfetch, sizeof(rsa_priv),
-  rsap1_siginit, rsap1_sigdoit, rsap1_sigdestroy
-};
-
-typedef struct rsap1_vrfctx {
-  sig s;
-  rsa_pubctx rp;
-  pkcs1 p1;
-} rsap1_vrfctx;
-
-static sig *rsap1_vrfinit(key *k, void *kd, const gchash *hc)
-{
-  rsap1_vrfctx *rv = CREATE(rsap1_vrfctx);
-  rsa_pubcreate(&rv->rp, kd);
-  rv->p1.r = &rand_global;
-  rv->p1.ep = hc->name;
-  rv->p1.epsz = strlen(hc->name) + 1;
-  rv->s.h = 0;
-  return (&rv->s);
-}
-
-static int rsap1_vrfdoit(sig *s, dstr *d)
-{
-  rsap1_vrfctx *rv = (rsap1_vrfctx *)s;
-  mp *m = mp_loadb(MP_NEW, d->buf, d->len);
-  int rc = rsa_verify(&rv->rp, m,
-                     GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,
-                     0, pkcs1_sigdecode, &rv->p1);
-  mp_drop(m);
-  return (rc);
-}
-
-static void rsap1_vrfdestroy(sig *s)
-{
-  rsap1_vrfctx *rv = (rsap1_vrfctx *)s;
-  DESTROY(rv);
-}
-
-static const sigops rsap1_vrf = {
-  rsa_pubfetch, sizeof(rsa_pub),
-  rsap1_vrfinit, rsap1_vrfdoit, rsap1_vrfdestroy
-};
-
-/* --- RSA PSS --- */
-
-static const gccipher *getmgf(key *k, const gchash *hc)
-{
-  dstr d = DSTR_INIT;
-  const gccipher *gc;
-  const char *mm;
-
-  if ((mm = key_getattr(0, k, "mgf-alg")) == 0) {
-    dstr_putf(&d, "%s-mgf", hc->name);
-    mm = d.buf;
-  }
-  if ((gc = gcipher_byname(mm)) == 0)
-    die(EXIT_FAILURE, "unknown encryption scheme `%s'", mm);
-  dstr_destroy(&d);
-  return (gc);
-}
-
-typedef struct rsapss_sigctx {
-  sig s;
-  rsa_privctx rp;
-  pss p;
-} rsapss_sigctx;
-
-static sig *rsapss_siginit(key *k, void *kd, const gchash *hc)
-{
-  rsapss_sigctx *rs = CREATE(rsapss_sigctx);
-  rsa_privcreate(&rs->rp, kd, &rand_global);
-  rs->p.r = &rand_global;
-  rs->p.cc = getmgf(k, hc);
-  rs->p.ch = hc;
-  rs->p.ssz = hc->hashsz;
-  return (&rs->s);
-}
-
-static int rsapss_sigdoit(sig *s, dstr *d)
-{
-  rsapss_sigctx *rs = (rsapss_sigctx *)s;
-  size_t n;
-  mp *m = rsa_sign(&rs->rp, MP_NEW,
-                  GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,
-                  pss_encode, &rs->p);
-  if (!m) return (-1);
-  n = mp_octets(rs->rp.rp->n); dstr_ensure(d, n); mp_storeb(m, d->buf, n);
-  d->len += n;  mp_drop(m);
-  return (0);
-}
-
-static void rsapss_sigdestroy(sig *s)
-{
-  rsapss_sigctx *rs = (rsapss_sigctx *)s;
-  DESTROY(rs);
-}
-
-static const sigops rsapss_sig = {
-  rsa_privfetch, sizeof(rsa_priv),
-  rsapss_siginit, rsapss_sigdoit, rsapss_sigdestroy
-};
-
-typedef struct rsapss_vrfctx {
-  sig s;
-  rsa_pubctx rp;
-  pss p;
-} rsapss_vrfctx;
-
-static sig *rsapss_vrfinit(key *k, void *kd, const gchash *hc)
-{
-  rsapss_vrfctx *rv = CREATE(rsapss_vrfctx);
-  rsa_pubcreate(&rv->rp, kd);
-  rv->p.r = &rand_global;
-  rv->p.cc = getmgf(k, hc);
-  rv->p.ch = hc;
-  rv->p.ssz = hc->hashsz;
-  return (&rv->s);
-}
-
-static int rsapss_vrfdoit(sig *s, dstr *d)
-{
-  rsapss_vrfctx *rv = (rsapss_vrfctx *)s;
-  mp *m = mp_loadb(MP_NEW, d->buf, d->len);
-  int rc = rsa_verify(&rv->rp, m,
-                     GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,
-                     0, pss_decode, &rv->p);
-  mp_drop(m);
-  return (rc);
-}
-
-static void rsapss_vrfdestroy(sig *s)
-{
-  rsapss_vrfctx *rv = (rsapss_vrfctx *)s;
-  DESTROY(rv);
-}
-
-static const sigops rsapss_vrf = {
-  rsa_pubfetch, sizeof(rsa_pub),
-  rsapss_vrfinit, rsapss_vrfdoit, rsapss_vrfdestroy
-};
-
-/* --- DSA and ECDSA --- */
-
-typedef struct dsa_sigctx {
-  sig s;
-  gdsa g;
-} dsa_sigctx;
-
-static void dsa_initcommon(dsa_sigctx *ds, const gchash *hc,
-                          const char *ktag)
-{
-  ds->g.r = &rand_global;
-  ds->g.h = hc;
-  ds->g.u = MP_NEW;
-  ds->s.h = 0;
-}
-
-static dsa_sigctx *dsa_doinit(key *k, const gprime_param *gp,
-                             mp *y, const gchash *hc)
-{
-  dsa_sigctx *ds = CREATE(dsa_sigctx);
-  dstr t = DSTR_INIT;
-
-  key_fulltag(k, &t);
-  if ((ds->g.g = group_prime(gp)) == 0)
-    die(EXIT_FAILURE, "bad prime group in key `%s'", t.buf);
-  ds->g.p = G_CREATE(ds->g.g);
-  if (G_FROMINT(ds->g.g, ds->g.p, y))
-    die(EXIT_FAILURE, "bad public key in key `%s'", t.buf);
-  dsa_initcommon(ds, hc, t.buf);
-  dstr_destroy(&t);
-  return (ds);
-}
-
-static dsa_sigctx *ecdsa_doinit(key *k, const char *cstr,
-                               ec *y, const gchash *hc)
-{
-  dsa_sigctx *ds = CREATE(dsa_sigctx);
-  ec_info ei;
-  const char *e;
-  dstr t = DSTR_INIT;
-
-  key_fulltag(k, &t);
-  if ((e = ec_getinfo(&ei, cstr)) != 0)
-    die(EXIT_FAILURE, "bad curve in key `%s': %s", t.buf, e);
-  ds->g.g = group_ec(&ei);
-  ds->g.p = G_CREATE(ds->g.g);
-  if (G_FROMEC(ds->g.g, ds->g.p, y))
-    die(EXIT_FAILURE, "bad public key in key `%s'", t.buf);
-  dsa_initcommon(ds, hc, t.buf);
-  dstr_destroy(&t);
-  return (ds);
-}
-
-static sig *dsa_siginit(key *k, void *kd, const gchash *hc)
-{
-  dh_priv *dp = kd;
-  dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
-  ds->g.u = MP_COPY(dp->x);
-  return (&ds->s);
-}
-
-static sig *ecdsa_siginit(key *k, void *kd, const gchash *hc)
-{
-  ec_priv *ep = kd;
-  dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
-  ds->g.u = MP_COPY(ep->x);
-  return (&ds->s);
-}
-
-static int dsa_sigdoit(sig *s, dstr *d)
-{
-  dsa_sigctx *ds = (dsa_sigctx *)s;
-  gdsa_sig ss = GDSA_SIG_INIT;
-  size_t n = mp_octets(ds->g.g->r);
-
-  gdsa_sign(&ds->g, &ss, GH_DONE(ds->s.h, 0), 0);
-  dstr_ensure(d, 2 * n);
-  mp_storeb(ss.r, d->buf, n);
-  mp_storeb(ss.s, d->buf + n, n);
-  d->len += 2 * n;
-  mp_drop(ss.r); mp_drop(ss.s);
-  return (0);
-}
-
-static void dsa_sigdestroy(sig *s)
-{
-  dsa_sigctx *ds = (dsa_sigctx *)s;
-  G_DESTROY(ds->g.g, ds->g.p);
-  mp_drop(ds->g.u);
-  G_DESTROYGROUP(ds->g.g);
-}
-
-static const sigops dsa_sig = {
-  dh_privfetch, sizeof(dh_priv),
-  dsa_siginit, dsa_sigdoit, dsa_sigdestroy
-};
-
-static const sigops ecdsa_sig = {
-  ec_privfetch, sizeof(ec_priv),
-  ecdsa_siginit, dsa_sigdoit, dsa_sigdestroy
-};
-
-static sig *dsa_vrfinit(key *k, void *kd, const gchash *hc)
-{
-  dh_pub *dp = kd;
-  dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
-  return (&ds->s);
-}
-
-static sig *ecdsa_vrfinit(key *k, void *kd, const gchash *hc)
-{
-  ec_pub *ep = kd;
-  dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
-  return (&ds->s);
-}
-
-static int dsa_vrfdoit(sig *s, dstr *d)
-{
-  dsa_sigctx *ds = (dsa_sigctx *)s;
-  gdsa_sig ss;
-  size_t n = d->len/2;
-  int rc;
-
-  ss.r = mp_loadb(MP_NEW, d->buf, n);
-  ss.s = mp_loadb(MP_NEW, d->buf + n, d->len - n);
-  rc = gdsa_verify(&ds->g, &ss, GH_DONE(ds->s.h, 0));
-  mp_drop(ss.r); mp_drop(ss.s);
-  return (rc);
-}
-
-static const sigops dsa_vrf = {
-  dh_pubfetch, sizeof(dh_pub),
-  dsa_vrfinit, dsa_vrfdoit, dsa_sigdestroy
-};
-
-static const sigops ecdsa_vrf = {
-  ec_pubfetch, sizeof(ec_pub),
-  ecdsa_vrfinit, dsa_vrfdoit, dsa_sigdestroy
-};
-
-/* --- KCDSA and ECKCDSA --- */
-
-static void kcdsa_privkey(dsa_sigctx *ds, mp *x)
-  { ds->g.u = mp_modinv(MP_NEW, x, ds->g.g->r); }
-
-static void kcdsa_sethash(dsa_sigctx *ds, const gchash *hc)
-  { ds->s.h = gkcdsa_beginhash(&ds->g); }
-
-static sig *kcdsa_siginit(key *k, void *kd, const gchash *hc)
-{
-  dh_priv *dp = kd;
-  dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
-  kcdsa_privkey(ds, dp->x);
-  kcdsa_sethash(ds, hc);
-  return (&ds->s);
-}
-
-static sig *eckcdsa_siginit(key *k, void *kd, const gchash *hc)
-{
-  ec_priv *ep = kd;
-  dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
-  kcdsa_privkey(ds, ep->x);
-  kcdsa_sethash(ds, hc);
-  return (&ds->s);
-}
-
-static int kcdsa_sigdoit(sig *s, dstr *d)
-{
-  dsa_sigctx *ds = (dsa_sigctx *)s;
-  gkcdsa_sig ss = GKCDSA_SIG_INIT;
-  size_t hsz = ds->g.h->hashsz, n = mp_octets(ds->g.g->r);
-
-  gkcdsa_sign(&ds->g, &ss, GH_DONE(ds->s.h, 0), 0);
-  dstr_ensure(d, hsz + n);
-  memcpy(d->buf, ss.r, hsz);
-  mp_storeb(ss.s, d->buf + hsz, n);
-  d->len += hsz + n;
-  xfree(ss.r); mp_drop(ss.s);
-  return (0);
-}
-
-static const sigops kcdsa_sig = {
-  dh_privfetch, sizeof(dh_priv),
-  kcdsa_siginit, kcdsa_sigdoit, dsa_sigdestroy
-};
-
-static const sigops eckcdsa_sig = {
-  ec_privfetch, sizeof(ec_priv),
-  eckcdsa_siginit, kcdsa_sigdoit, dsa_sigdestroy
-};
-
-static sig *kcdsa_vrfinit(key *k, void *kd, const gchash *hc)
-{
-  dh_pub *dp = kd;
-  dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
-  kcdsa_sethash(ds, hc);
-  return (&ds->s);
-}
-
-static sig *eckcdsa_vrfinit(key *k, void *kd, const gchash *hc)
-{
-  ec_pub *ep = kd;
-  dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
-  kcdsa_sethash(ds, hc);
-  return (&ds->s);
-}
-
-static int kcdsa_vrfdoit(sig *s, dstr *d)
-{
-  dsa_sigctx *ds = (dsa_sigctx *)s;
-  gkcdsa_sig ss;
-  size_t hsz = ds->g.h->hashsz, n = d->len - hsz;
-  int rc;
-
-  if (d->len < hsz)
-    return (-1);
-  ss.r = (octet *)d->buf;
-  ss.s = mp_loadb(MP_NEW, d->buf + hsz, n);
-  rc = gkcdsa_verify(&ds->g, &ss, GH_DONE(ds->s.h, 0));
-  mp_drop(ss.s);
-  return (rc);
-}
-
-static const sigops kcdsa_vrf = {
-  dh_pubfetch, sizeof(dh_pub),
-  kcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigdestroy
-};
-
-static const sigops eckcdsa_vrf = {
-  ec_pubfetch, sizeof(ec_pub),
-  eckcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigdestroy
-};
-
-/* --- The switch table --- */
-
-static const struct sigtab {
-  const char *name;
-  const sigops *signops;
-  const sigops *verifyops;
-  const gchash *ch;
-} sigtab[] = {
-  { "rsapkcs1",        &rsap1_sig,     &rsap1_vrf,     &sha },
-  { "rsapss",  &rsapss_sig,    &rsapss_vrf,    &sha },
-  { "dsa",     &dsa_sig,       &dsa_vrf,       &sha },
-  { "ecdsa",   &ecdsa_sig,     &ecdsa_vrf,     &sha },
-  { "kcdsa",   &kcdsa_sig,     &kcdsa_vrf,     &has160 },
-  { "eckcdsa", &eckcdsa_sig,   &eckcdsa_vrf,   &has160 },
-  { 0,         0,              0 }
-};
-
-/* --- @getsig@ --- *
- *
- * Arguments:  @key *k@ = the key to load
- *             @int wantpriv@ = nonzero if we want to sign
- *
- * Returns:    A signature-making thing.
- *
- * Use:                Loads a key and starts hashing.
- */
-
-static sig *getsig(key *k, int wantpriv)
-{
-  const char *salg, *halg = 0;
-  dstr d = DSTR_INIT;
-  dstr t = DSTR_INIT;
-  char *p = 0;
-  const char *q;
-  sig *s;
-  const struct sigtab *st;
-  const sigops *so;
-  const gchash *ch;
-  void *kd;
-  int e;
-  key_packdef *kp;
-
-  /* --- Setup stuff --- */
-
-  key_fulltag(k, &t);
-
-  /* --- Get the signature algorithm --- *
-   *
-   * Take the attribute if it's there; otherwise use the key type.
-   */
-
-  if ((q = key_getattr(0, k, "sig-alg")) != 0) {
-    dstr_puts(&d, q);
-    p = d.buf;
-  } else if (strncmp(k->type, "dsig-", 5) == 0 && k->type[5]) {
-    dstr_puts(&d, k->type);
-    p = d.buf + 5;
-  } else
-    die(EXIT_FAILURE, "no signature algorithm for key `%s'", t.buf);
-
-  /* --- Grab the hash algorithm --- *
-   *
-   * Grab it from the signature algorithm if it's there.  But override that
-   * from the attribute.
-   */
-
-  salg = p;
-  if ((p = strchr(p, '-')) != 0) {
-    *p++ = 0;
-    halg = p;
-  }
-  if ((q = key_getattr(0, k, "hash-alg")) != 0)
-    halg = q;
-
-  /* --- Look up the algorithms in the table --- */
-
-  for (st = sigtab; st->name; st++) {
-    if (strcmp(st->name, salg) == 0)
-      goto s_found;
-  }
-  die(EXIT_FAILURE, "signature algorithm `%s' not found in key `%s'",
-      salg, t.buf);
-s_found:;
-  if (!halg)
-    ch = st->ch;
-  else {
-    if ((ch = ghash_byname(halg)) == 0) {
-      die(EXIT_FAILURE, "hash algorithm `%s' not found in key `%s'",
-         halg, t.buf);
-    }
-  }
-  so = wantpriv ? st->signops : st->verifyops;
-
-  /* --- 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));
-  s = so->init(k, kd, ch);
-  if (!s->h)
-    s->h = GH_INIT(ch);
-  s->kp = kp;
-  s->ops = so;
-
-  /* --- Free stuff up --- */
-
-  dstr_destroy(&d);
-  dstr_destroy(&t);
-  return (s);
-}
-
-/* --- @freesig@ --- *
- *
- * Arguments:  @sig *s@ = signature-making thing
- *
- * Returns:    ---
- *
- * Use:                Frees up a signature-making thing
- */
-
-static void freesig(sig *s)
-{
-  GH_DESTROY(s->h);
-  key_fetchdone(s->kp);
-  s->ops->destroy(s);
-}
+#include "cc.h"
 
 /*----- Data formatting ---------------------------------------------------*/
 
@@ -1224,7 +656,6 @@ static void fhex(FILE *fp, const void *p, size_t sz)
     sz--;
     if (!sz)
       break;
-/*     putc(' ', fp); */
   }
 }    
 
@@ -1246,6 +677,7 @@ static int sign(int argc, char *argv[])
   const char *ifile = 0;
   const char *ofile = 0;
   const char *c = 0;
+  const char *err;
   FILE *ifp, *ofp;
   dstr d = DSTR_INIT;
   block b;
@@ -1264,7 +696,7 @@ static int sign(int argc, char *argv[])
       { "expire",      OPTF_ARGREQ,    0,      'e' },
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "+0vqb c: f:o: k:e:", opts, 0, 0, 0);
+    int i = mdwopt(argc, argv, "+0vqb" "c:" "f:o:" "k:e:", opts, 0, 0, 0);
     if (i < 0)
       break;
     switch (i) {
@@ -1318,7 +750,12 @@ static int sign(int argc, char *argv[])
     die(EXIT_FAILURE, "key `%s' expires: can't create nonexpiring signature",
        d.buf);
   }
-  s = getsig(k, 1);
+  s = getsig(k, "dsig", 1);
+
+  /* --- Check the key --- */
+
+  if ((err = s->ops->check(s)) != 0)
+    moan("key `%s' fails check: %s", d.buf, err);
 
   /* --- Open files --- */
 
@@ -1455,6 +892,7 @@ static int verify(int argc, char *argv[])
   key *k = 0;
   sig *s;
   dstr d = DSTR_INIT;
+  const char *err;
   FILE *fp;
   block b;
   int e;
@@ -1546,14 +984,16 @@ static int verify(int argc, char *argv[])
 
   /* --- Initialize the hash function and start reading hashed packets --- */
 
-  s = getsig(k, 0);
-
   if (!k) {
     if (verb)
       puts("FAIL no keyid packet found");
     exit(EXIT_FAILURE);
   }
 
+  s = getsig(k, "dsig", 0);
+  if (verb && (err = s->ops->check(s)) != 0)
+    printf("WARN public key fails check: %s", err);
+
   for (;;) {
     switch (e) {
       case T_COMMENT:
@@ -1656,12 +1096,9 @@ typedef struct cmd {
 } cmd;
 
 static cmd cmdtab[] = {
-/*   { "manifest", manifest, */
-/*     "manifest [-0] [-o output]" }, */
   { "sign", sign,
-    "sign [-options]\n\
-       [-0bqv] [-c comment] [-k tag] [-i keyid]\n\
-       [-e expire] [-f file] [-o output]", "\
+    "sign [-0bqv] [-c comment] [-k tag] [-e expire] [-f file] [-o output]",
+    "\
 Options:\n\
 \n\
 -0, --null             Read null-terminated filenames from stdin.\n\
index cf65584..4f852c2 100644 (file)
--- a/ec-info.c
+++ b/ec-info.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: ec-info.c,v 1.6 2004/04/08 16:17:32 mdw Exp $
+ * $Id: ec-info.c,v 1.7 2004/04/17 09:58:37 mdw Exp $
  *
  * Elliptic curve information management
  *
@@ -372,11 +372,6 @@ static const char *primecheck(const ec_info *ei, grand *gr)
 
   if (!pgen_primep(ei->r, gr)) return ("generator order not prime");
 
-  /* --- Check %$0 < h \le 4$% --- */
-
-  if (MP_CMP(ei->h, <, MP_ONE) || MP_CMP(ei->h, >, MP_FOUR))
-    return ("cofactor out of range");
-
   /* --- Check %$h = \lfloor (\sqrt{p} + 1)^2/r \rlfoor$% --- *
    *
    * This seems to work with the approximate-sqrt in the library, but might
@@ -421,6 +416,11 @@ static const char *primecheck(const ec_info *ei, grand *gr)
   MP_DROP(x);
   if (i) return ("curve is weak");
 
+  /* --- Check %$0 < h \le 4$% --- */
+
+  if (MP_CMP(ei->h, <, MP_ONE) || MP_CMP(ei->h, >, MP_FOUR))
+    return ("cofactor out of range");
+
   /* --- Done --- */
 
   return (0);
@@ -459,11 +459,6 @@ static const char *bincheck(const ec_info *ei, grand *gr)
 
   if (!pgen_primep(ei->r, gr)) return ("generator order not prime");
 
-  /* --- Check %$0 < h \le 4$% --- */
-
-  if (MP_CMP(ei->h, <, MP_ONE) || MP_CMP(ei->h, >, MP_FOUR))
-    return ("cofactor out of range");
-
   /* --- Check %$h = \lfloor (\sqrt{2^m} + 1)^2/r \rlfoor$% --- *
    *
    * This seems to work with the approximate-sqrt in the library, but might
@@ -505,6 +500,11 @@ static const char *bincheck(const ec_info *ei, grand *gr)
   MP_DROP(x);
   if (i) return ("curve is weak");
 
+  /* --- Check %$0 < h \le 4$% --- */
+
+  if (MP_CMP(ei->h, <, MP_ONE) || MP_CMP(ei->h, >, MP_FOUR))
+    return ("cofactor out of range");
+
   /* --- Done --- */
 
   return (0);
index 49a232b..7333310 100644 (file)
--- a/ecb-def.h
+++ b/ecb-def.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: ecb-def.h,v 1.3 2004/04/08 01:36:15 mdw Exp $
+ * $Id: ecb-def.h,v 1.4 2004/04/17 09:58:37 mdw Exp $
  *
  * Definitions electronic code book mode
  *
@@ -148,11 +148,17 @@ void pre##_ecbencrypt(pre##_ecbctx *ctx,                          \
                                                                        \
   while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) {                 \
     uint32 x[PRE##_BLKSZ / 4];                                         \
-    BLKC_LOAD(PRE, x, s);                                              \
+    if (!s)                                                            \
+      BLKC_ZERO(PRE, x);                                               \
+    else {                                                             \
+      BLKC_LOAD(PRE, x, s);                                            \
+      s += PRE##_BLKSZ;                                                        \
+    }                                                                  \
     pre##_eblk(&ctx->ctx, x, x);                                       \
-    BLKC_STORE(PRE, d, x);                                             \
-    s += PRE##_BLKSZ;                                                  \
-    d += PRE##_BLKSZ;                                                  \
+    if (d) {                                                           \
+      BLKC_STORE(PRE, d, x);                                           \
+      d += PRE##_BLKSZ;                                                        \
+    }                                                                  \
     sz -= PRE##_BLKSZ;                                                 \
   }                                                                    \
                                                                        \
@@ -177,7 +183,12 @@ void pre##_ecbencrypt(pre##_ecbctx *ctx,                           \
      * out yet, because I've not read the partial plaintext block.     \
      */                                                                        \
                                                                        \
-    BLKC_LOAD(PRE, x, s);                                              \
+    if (!s)                                                            \
+      BLKC_ZERO(PRE, x);                                               \
+    else {                                                             \
+      BLKC_LOAD(PRE, x, s);                                            \
+      s += PRE##_BLKSZ;                                                        \
+    }                                                                  \
     pre##_eblk(&ctx->ctx, x, x);                                       \
     BLKC_STORE(PRE, b, x);                                             \
                                                                        \
@@ -188,16 +199,15 @@ void pre##_ecbencrypt(pre##_ecbctx *ctx,                          \
      * ciphertext block.                                               \
      */                                                                        \
                                                                        \
-    s += PRE##_BLKSZ;                                                  \
-    d += PRE##_BLKSZ;                                                  \
+    if (d) d += PRE##_BLKSZ;                                           \
     for (i = 0; i < sz; i++) {                                         \
       register octet y = b[i];                                         \
       b[i] = s[i];                                                     \
-      d[i] = y;                                                                \
+      if (d) d[i] = y;                                                 \
     }                                                                  \
     BLKC_LOAD(PRE, x, b);                                              \
     pre##_eblk(&ctx->ctx, x, x);                                       \
-    BLKC_STORE(PRE, d - PRE##_BLKSZ, x);                               \
+    if (d) BLKC_STORE(PRE, d - PRE##_BLKSZ, x);                                \
   }                                                                    \
                                                                        \
   /* --- Done --- */                                                   \
diff --git a/g-ec.c b/g-ec.c
index 1809e6c..32220ff 100644 (file)
--- a/g-ec.c
+++ b/g-ec.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: g-ec.c,v 1.4 2004/04/08 01:36:15 mdw Exp $
+ * $Id: g-ec.c,v 1.5 2004/04/17 09:58:37 mdw Exp $
  *
  * Abstraction for elliptic curve groups
  *
@@ -150,7 +150,7 @@ static int gfromint(group *gg, ec *d, mp *x) {
 static int gtoec(group *gg, ec *d, ec *x)
   { gctx *g = (gctx *)gg; EC_OUT(g->ei.c, d, x); return (0); }
 
-static int gfromec(group *gg, ec *d, ec *x) {
+static int gfromec(group *gg, ec *d, const ec *x) {
   gctx *g = (gctx *)gg; ec t = EC_INIT; int rc; EC_IN(g->ei.c, &t, x);
   rc = EC_CHECK(g->ei.c, &t); if (!rc) EC_COPY(d, &t); EC_DESTROY(&t);
   return (rc);
index faa34f2..ec30b4d 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: group-stdops.c,v 1.2 2004/04/08 01:36:15 mdw Exp $
+ * $Id: group-stdops.c,v 1.3 2004/04/17 09:58:37 mdw Exp $
  *
  * Standard group operations
  *
@@ -42,7 +42,7 @@
  * Returns:    Zero on success, nonzero for failure.
  *
  * Use:                Checks that @x@ is a valid group element.  This may take a
- *             while, since it checks that %$x^h \ne 1$% and %$x^r = 1$%.
+ *             while, since it checks that %$x \ne 1$% and %$x^r = 1$%.
  */
 
 int group_check(group *g, ge *x)
@@ -50,8 +50,8 @@ int group_check(group *g, ge *x)
   ge *d = G_CREATE(g);
   int rc;
 
-  G_EXP(g, d, x, g->h); rc = !G_IDENTP(g, d);
-  if (rc) { G_EXP(g, d, x, g->r); rc = G_IDENTP(g, d); }
+  G_EXP(g, d, x, g->r);
+  rc = (G_IDENTP(g, d) && !G_IDENTP(g, x));
   G_DESTROY(g, d);
   if (!rc) return (-1);
   return (0);
@@ -137,7 +137,7 @@ int group_stdtoec(group *g, ec *d, ge *x) { return (-1); }
  *
  * Arguments:  @group *g@ = abstract group
  *             @ge *d@ = destination pointer
- *             @ec *p@ = elliptic curve point
+ *             @const ec *p@ = elliptic curve point
  *
  * Returns:    Zero for success, @-1@ on failure.
  *
@@ -145,7 +145,7 @@ int group_stdtoec(group *g, ec *d, ge *x) { return (-1); }
  *             coordinate.
  */
 
-int group_stdfromec(group *g, ge *d, ec *p)
+int group_stdfromec(group *g, ge *d, const ec *p)
   { if (EC_ATINF(p)) return (-1); return (G_FROMINT(g, d, p->x)); }
 
 /* --- @group_stdcheck@ --- *
diff --git a/group.h b/group.h
index 9211a58..9578f33 100644 (file)
--- a/group.h
+++ b/group.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: group.h,v 1.4 2004/04/08 01:36:15 mdw Exp $
+ * $Id: group.h,v 1.5 2004/04/17 09:58:37 mdw Exp $
  *
  * General cyclic group abstraction
  *
@@ -122,7 +122,7 @@ typedef struct group_ops {
   mp *(*toint)(group */*g*/, mp */*d*/, ge */*x*/);
   int (*fromint)(group */*g*/, ge */*d*/, mp */*x*/);
   int (*toec)(group */*g*/, ec */*d*/, ge */*x*/);
-  int (*fromec)(group */*g*/, ge */*d*/, ec */*p*/);
+  int (*fromec)(group */*g*/, ge */*d*/, const ec */*p*/);
   int (*tobuf)(group */*h*/, buf */*b*/, ge */*x*/);
   int (*frombuf)(group */*h*/, buf */*b*/, ge */*d*/);
   int (*toraw)(group */*h*/, buf */*b*/, ge */*x*/);
@@ -305,7 +305,7 @@ extern int group_stdtoec(group */*g*/, ec */*d*/, ge */*x*/);
  *
  * Arguments:  @group *g@ = abstract group
  *             @ge *d@ = destination pointer
- *             @ec *p@ = elliptic curve point
+ *             @const ec *p@ = elliptic curve point
  *
  * Returns:    Zero for success, @-1@ on failure.
  *
@@ -313,7 +313,7 @@ extern int group_stdtoec(group */*g*/, ec */*d*/, ge */*x*/);
  *             coordinate.
  */
 
-extern int group_stdfromec(group */*g*/, ge */*d*/, ec */*p*/);
+extern int group_stdfromec(group */*g*/, ge */*d*/, const ec */*p*/);
 
 /*----- Prime field subgroups ---------------------------------------------*/