progs/catcrypt.c: Support the use of AEAD schemes.
authorMark Wooding <mdw@distorted.org.uk>
Fri, 9 Nov 2018 18:45:51 +0000 (18:45 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 5 Sep 2019 00:36:04 +0000 (01:36 +0100)
progs/catcrypt.1
progs/catcrypt.c
progs/cc-kem.c

index d55b7bf..97367a5 100644 (file)
@@ -256,6 +256,15 @@ is
 .BR blowfish-cbc .
 This is the default transform.
 .TP
+.B aead
+Use an `authenticated encryption with additional data' (AEAD) scheme.
+The specific scheme is named by the
+.B cipher
+attribute.  Run
+.B catcrypt show aead
+for a list of supported AEAD schemes; the default is
+.BR chacha20-poly1305 .
+.TP
 .B naclbox
 Use Salsa20 or ChaCha and Poly1305 to secure the bulk data.
 This is nearly the same as the NaCl
index 72c7780..c31a3d9 100644 (file)
@@ -51,6 +51,7 @@
 #include "key.h"
 #include "cc.h"
 
+#include "gaead.h"
 #include "ectab.h"
 #include "ptab.h"
 
@@ -572,6 +573,8 @@ static int decrypt(int argc, char *argv[])
      enctab[i].name, enctab[i].name)                                   \
   LI("Symmetric encryption algorithms", cipher,                                \
      gciphertab[i], gciphertab[i]->name)                               \
+  LI("Authenticated encryption schemes", aead,                         \
+     gaeadtab[i], gaeadtab[i]->name)                                   \
   LI("Hash functions", hash,                                           \
      ghashtab[i], ghashtab[i]->name)                                   \
   LI("Message authentication codes", mac,                              \
index 1e99e05..0974f4f 100644 (file)
@@ -36,6 +36,7 @@
 #include <mLib/report.h>
 #include <mLib/sub.h>
 
+#include "gaead.h"
 #include "mprand.h"
 #include "rand.h"
 
@@ -48,6 +49,7 @@
 
 #include "rmd160.h"
 #include "blowfish-cbc.h"
+#include "chacha20-poly1305.h"
 #include "poly1305.h"
 #include "salsa20.h"
 #include "chacha.h"
@@ -165,6 +167,139 @@ static const bulkops naclbox_encops = {
   naclbox_decdoit, naclbox_destroy
 };
 
+/* --- Authenticated encryption schemes --- */
+
+typedef struct aead_encctx {
+  bulk b;
+  const gcaead *aec;
+  gaead_key *key;
+  union { gaead_enc *enc; gaead_dec *dec; } ed;
+  octet *t;
+  size_t nsz, tsz;
+} aead_encctx;
+
+static bulk *aead_init(key *k, const char *calg, const char *halg)
+{
+  aead_encctx *ctx = CREATE(aead_encctx);
+  const char *q;
+  dstr t = DSTR_INIT;
+
+  key_fulltag(k, &t);
+
+  if ((q = key_getattr(0, k, "cipher")) != 0) calg = q;
+  if (!calg) ctx->aec = &chacha20_poly1305;
+  else if ((ctx->aec = gaead_byname(calg)) == 0)
+    die(EXIT_FAILURE, "AEAD scheme `%s' not found in key `%s'",
+       calg, t.buf);
+
+  ctx->key = 0;
+  if ((ctx->nsz = keysz_pad(4, ctx->aec->noncesz)) == 0)
+    die(EXIT_FAILURE, "no suitable nonce size for `%s'", calg);
+  ctx->tsz = keysz(0, ctx->aec->tagsz);
+
+  dstr_destroy(&t);
+  return (&ctx->b);
+}
+
+static int aead_commonsetup(aead_encctx *ctx, gcipher *cx)
+{
+  size_t ksz, n;
+
+  n = ksz = keysz(0, ctx->aec->keysz);
+  if (n < ctx->nsz) n = ctx->nsz;
+  if (n < ctx->tsz) n = ctx->tsz;
+  ctx->t = xmalloc(n);
+
+  GC_ENCRYPT(cx, 0, ctx->t, ksz);
+  ctx->key = GAEAD_KEY(ctx->aec, ctx->t, ksz);
+  return (0);
+}
+
+static size_t aead_overhead(bulk *b)
+  { aead_encctx *ctx = (aead_encctx *)b; return (ctx->aec->ohd + ctx->tsz); }
+
+static void aead_commondestroy(aead_encctx *ctx)
+{
+  if (ctx->key) GAEAD_DESTROY(ctx->key);
+  xfree(ctx->t);
+  DESTROY(ctx);
+}
+
+static int aead_encsetup(bulk *b, gcipher *cx)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
+  ctx->ed.enc = 0; return (aead_commonsetup(ctx, cx));
+}
+
+static const char *aead_encdoit(bulk *b, uint32 seq, buf *bb,
+                               const void *p, size_t sz)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
+  octet *t;
+  int rc;
+
+  memset(ctx->t + 4, 0, ctx->nsz - 4); STORE32_B(ctx->t, seq);
+  if (!ctx->ed.enc)
+    ctx->ed.enc = GAEAD_ENC(ctx->key, ctx->t, ctx->nsz, 0, sz, ctx->tsz);
+  else
+    GAEAD_REINIT(ctx->ed.enc, ctx->t, ctx->nsz, 0, sz, ctx->tsz);
+  t = buf_get(bb, ctx->tsz); assert(t);
+  rc = GAEAD_ENCRYPT(ctx->ed.enc, p, sz, bb); assert(rc >= 0);
+  rc = GAEAD_DONE(ctx->ed.enc, 0, bb, t, ctx->tsz); assert(rc >= 0);
+  return (0);
+}
+
+static void aead_encdestroy(bulk *b)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
+  if (ctx->ed.enc) GAEAD_DESTROY(ctx->ed.enc);
+  aead_commondestroy(ctx);
+}
+
+static int aead_decsetup(bulk *b, gcipher *cx)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
+  ctx->ed.dec = 0; return (aead_commonsetup(ctx, cx));
+}
+
+static const char *aead_decdoit(bulk *b, uint32 seq, buf *bb,
+                               const void *p, size_t sz)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
+  buf bin;
+  const octet *t;
+  int rc;
+
+  memset(ctx->t + 4, 0, ctx->nsz - 4); STORE32_B(ctx->t, seq);
+  if (!ctx->ed.dec)
+    ctx->ed.dec = GAEAD_DEC(ctx->key, ctx->t, ctx->nsz, 0, sz, ctx->tsz);
+  else
+    GAEAD_REINIT(ctx->ed.enc, ctx->t, ctx->nsz, 0, sz, ctx->tsz);
+
+  buf_init(&bin, (/*unconst*/ void *)p, sz);
+  t = buf_get(&bin, ctx->tsz); if (!t) return ("no tag");
+  rc = GAEAD_DECRYPT(ctx->ed.dec, BCUR(&bin), BLEFT(&bin), bb);
+  assert(rc >= 0);
+  rc = GAEAD_DONE(ctx->ed.dec, 0, bb, t, ctx->tsz); assert(rc >= 0);
+  if (!rc) return ("authentication failure");
+  return (0);
+}
+
+static void aead_decdestroy(bulk *b)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
+  if (ctx->ed.dec) GAEAD_DESTROY(ctx->ed.dec);
+  aead_commondestroy(ctx);
+}
+
+static const struct bulkops aead_encops = {
+  aead_init, aead_encsetup, aead_overhead,
+  aead_encdoit, aead_encdestroy
+}, aead_decops = {
+  aead_init, aead_decsetup, aead_overhead,
+  aead_decdoit, aead_decdestroy
+};
+
 /* --- Generic composition --- */
 
 typedef struct gencomp_encctx {
@@ -300,6 +435,7 @@ static const bulkops gencomp_encops = {
 const struct bulktab bulktab[] = {
   { "gencomp", &gencomp_encops,        &gencomp_decops },
   { "naclbox", &naclbox_encops,        &naclbox_decops },
+  { "aead",    &aead_encops,           &aead_decops },
   { 0,         0,                      0 }
 };