## -*-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
##
## --- 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
/* -*-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)
--- /dev/null
+/* -*-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 -------------------------------------------------*/
/* -*-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
*
\
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); \
*/ \
\
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; \
} \
\
* 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); \
\
* 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 --- */ \
--- /dev/null
+/* -*-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 -------------------------------------------------*/
--- /dev/null
+/* -*-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 -------------------------------------------------*/
--- /dev/null
+/* -*-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 -------------------------------------------------*/
--- /dev/null
+/* -*-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
/* -*-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
*
\
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--; \
} \
\
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; \
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); \
} \
/* -*-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 ---------------------------------------------------*/
sz--;
if (!sz)
break;
-/* putc(' ', fp); */
}
}
const char *ifile = 0;
const char *ofile = 0;
const char *c = 0;
+ const char *err;
FILE *ifp, *ofp;
dstr d = DSTR_INIT;
block b;
{ "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) {
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 --- */
key *k = 0;
sig *s;
dstr d = DSTR_INIT;
+ const char *err;
FILE *fp;
block b;
int e;
/* --- 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:
} 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\
/* -*-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
*
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
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);
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
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);
/* -*-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
*
\
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; \
} \
\
* 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); \
\
* 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 --- */ \
/* -*-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
*
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);
/* -*-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
*
* 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)
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);
*
* 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.
*
* 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@ --- *
/* -*-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
*
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*/);
*
* 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.
*
* 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 ---------------------------------------------*/