chiark / gitweb /
server/: Expose and enhance the bulk-key-derivation protocol.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 24 Aug 2017 21:24:07 +0000 (22:24 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 16 Jun 2018 18:13:41 +0000 (19:13 +0100)
  * Rename `struct rawkey' to `deriveargs', and document it;

  * make `ks_derivekey' private in `bulkcrypto.c', and rename it
    `derivekey';

  * make the various contributions to the derived keys be optional and
    handle them not existing sensibly; and

  * cope with the idea that a caller might only want incoming or
    outgoing keys, but not both.

This lays the groundwork for a separately usable public-key encryption
scheme based on the existing machinery, but this will come a bit later.

server/bulkcrypto.c
server/keyexch.c
server/keyset.c
server/tripe.h

index 7d754cd7accb7d283bf335b66a1faf3ab088b9ca..fff2c8251eb70cdc92b559a27b78f15cb6c0dbc0 100644 (file)
   trace_block(T_CRYPTO, "crypto: expected MAC", (pmac), (tagsz));      \
 }) } while (0)
 
+/* --- @derivekey@ --- *
+ *
+ * Arguments:  @octet *k@ = pointer to an output buffer of at least
+ *                     @MAXHASHSZ@ bytes
+ *             @size_t ksz@ = actual size wanted (for tracing)
+ *             @const deriveargs@ = derivation parameters, as passed into
+ *                     @genkeys@
+ *             @int dir@ = direction for the key (@DIR_IN@ or @DIR_OUT@)
+ *             @const char *what@ = label for the key (input to derivation)
+ *
+ * Returns:    ---
+ *
+ * Use:                Derives a session key, for use on incoming or outgoing data.
+ */
+
+static void derivekey(octet *k, size_t ksz, const deriveargs *a,
+                     int dir, const char *what)
+{
+  const gchash *hc = a->hc;
+  ghash *h;
+
+  assert(ksz <= hc->hashsz);
+  assert(hc->hashsz <= MAXHASHSZ);
+  h = GH_INIT(hc);
+  GH_HASH(h, a->what, strlen(a->what)); GH_HASH(h, what, strlen(what) + 1);
+  switch (dir) {
+    case DIR_IN:
+      if (a->x) GH_HASH(h, a->k, a->x);
+      if (a->y != a->x) GH_HASH(h, a->k + a->x, a->y - a->x);
+      break;
+    case DIR_OUT:
+      if (a->y != a->x) GH_HASH(h, a->k + a->x, a->y - a->x);
+      if (a->x) GH_HASH(h, a->k, a->x);
+      break;
+    default:
+      abort();
+  }
+  GH_HASH(h, a->k + a->y, a->z - a->y);
+  GH_DONE(h, k);
+  GH_DESTROY(h);
+  IF_TRACING(T_KEYSET, { IF_TRACING(T_CRYPTO, {
+    char _buf[32];
+    sprintf(_buf, "crypto: %s key %s", dir ? "outgoing" : "incoming", what);
+    trace_block(T_CRYPTO, _buf, k, ksz);
+  }) })
+}
+
 /*----- Common functionality for generic-composition transforms -----------*/
 
 #define CHECK_MAC(h, pmac, tagsz) do {                                 \
@@ -309,7 +356,7 @@ static size_t v0_overhead(const bulkalgs *aa)
 static size_t v0_expsz(const bulkalgs *aa)
   { const v0_algs *a = (const v0_algs *)aa; return (gencomp_expsz(&a->ga)); }
 
-static bulkctx *v0_genkeys(const bulkalgs *aa, const struct rawkey *rk)
+static bulkctx *v0_genkeys(const bulkalgs *aa, const deriveargs *da)
 {
   const v0_algs *a = (const v0_algs *)aa;
   v0_ctx *bc = CREATE(v0_ctx);
@@ -318,9 +365,10 @@ static bulkctx *v0_genkeys(const bulkalgs *aa, const struct rawkey *rk)
 
   bc->tagsz = a->ga.tagsz;
   for (i = 0; i < NDIR; i++) {
-    ks_derivekey(k, a->ga.cksz, rk, i, "encryption");
+    if (!(da->f&(1 << i))) { bc->d[i].c = 0; bc->d[i].m = 0; continue; }
+    derivekey(k, a->ga.cksz, da, i, "encryption");
     bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz);
-    ks_derivekey(k, a->ga.mksz, rk, i, "integrity");
+    derivekey(k, a->ga.mksz, da, i, "integrity");
     bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz);
   }
   return (&bc->_b);
@@ -344,8 +392,8 @@ static void v0_freectx(bulkctx *bbc)
   int i;
 
   for (i = 0; i < NDIR; i++) {
-    GC_DESTROY(bc->d[i].c);
-    GM_DESTROY(bc->d[i].m);
+    if (bc->d[i].c) GC_DESTROY(bc->d[i].c);
+    if (bc->d[i].m) GM_DESTROY(bc->d[i].m);
   }
   DESTROY(bc);
 }
@@ -359,10 +407,13 @@ static int v0_encrypt(bulkctx *bbc, unsigned ty,
   const octet *p = BCUR(b);
   size_t sz = BLEFT(b);
   octet *qmac, *qseq, *qiv, *qpk;
-  size_t ivsz = GC_CLASS(c)->blksz;
+  size_t ivsz;
   size_t tagsz = bc->tagsz;
   octet t[4];
 
+  assert(c);
+  ivsz = GC_CLASS(c)->blksz;
+
   /* --- Determine the ciphertext layout --- */
 
   if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0);
@@ -419,10 +470,13 @@ static int v0_decrypt(bulkctx *bbc, unsigned ty,
   octet *q = BCUR(bb);
   ghash *h;
   gcipher *c = bc->d[DIR_IN].c;
-  size_t ivsz = GC_CLASS(c)->blksz;
+  size_t ivsz;
   size_t tagsz = bc->tagsz;
   octet t[4];
 
+  assert(c);
+  ivsz = GC_CLASS(c)->blksz;
+
   /* --- Break up the packet into its components --- */
 
   if (psz < ivsz + SEQSZ + tagsz) {
@@ -587,7 +641,7 @@ static size_t iiv_expsz(const bulkalgs *aa)
   return (gencomp_expsz(&a->ga));
 }
 
-static bulkctx *iiv_genkeys(const bulkalgs *aa, const struct rawkey *rk)
+static bulkctx *iiv_genkeys(const bulkalgs *aa, const deriveargs *da)
 {
   const iiv_algs *a = (const iiv_algs *)aa;
   iiv_ctx *bc = CREATE(iiv_ctx);
@@ -596,11 +650,13 @@ static bulkctx *iiv_genkeys(const bulkalgs *aa, const struct rawkey *rk)
 
   bc->tagsz = a->ga.tagsz;
   for (i = 0; i < NDIR; i++) {
-    ks_derivekey(k, a->ga.cksz, rk, i, "encryption");
+    if (!(da->f&(1 << i)))
+      { bc->d[i].c = 0; bc->d[i].b = 0; bc->d[i].m = 0; continue; }
+    derivekey(k, a->ga.cksz, da, i, "encryption");
     bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz);
-    ks_derivekey(k, a->bksz, rk, i, "blkc");
+    derivekey(k, a->bksz, da, i, "blkc");
     bc->d[i].b = GC_INIT(a->b, k, a->bksz);
-    ks_derivekey(k, a->ga.mksz, rk, i, "integrity");
+    derivekey(k, a->ga.mksz, da, i, "integrity");
     bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz);
   }
   return (&bc->_b);
@@ -624,9 +680,9 @@ static void iiv_freectx(bulkctx *bbc)
   int i;
 
   for (i = 0; i < NDIR; i++) {
-    GC_DESTROY(bc->d[i].c);
-    GC_DESTROY(bc->d[i].b);
-    GM_DESTROY(bc->d[i].m);
+    if (bc->d[i].c) GC_DESTROY(bc->d[i].c);
+    if (bc->d[i].b) GC_DESTROY(bc->d[i].b);
+    if (bc->d[i].m) GM_DESTROY(bc->d[i].m);
   }
   DESTROY(bc);
 }
@@ -644,10 +700,14 @@ static int iiv_encrypt(bulkctx *bbc, unsigned ty,
   const octet *p = BCUR(b);
   size_t sz = BLEFT(b);
   octet *qmac, *qseq, *qpk;
-  size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
+  size_t ivsz, blkcsz;
   size_t tagsz = bc->tagsz;
   octet t[4];
 
+  assert(c); assert(blkc);
+  ivsz = GC_CLASS(c)->blksz;
+  blkcsz = GC_CLASS(blkc)->blksz;
+
   /* --- Determine the ciphertext layout --- */
 
   if (buf_ensure(bb, tagsz + SEQSZ + sz)) return (0);
@@ -707,10 +767,14 @@ static int iiv_decrypt(bulkctx *bbc, unsigned ty,
   octet *q = BCUR(bb);
   ghash *h;
   gcipher *c = bc->d[DIR_IN].c, *blkc = bc->d[DIR_IN].b;
-  size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
+  size_t ivsz, blkcsz;
   size_t tagsz = bc->tagsz;
   octet t[4];
 
+  assert(c); assert(blkc);
+  ivsz = GC_CLASS(c)->blksz;
+  blkcsz = GC_CLASS(blkc)->blksz;
+
   /* --- Break up the packet into its components --- */
 
   if (psz < SEQSZ + tagsz) {
@@ -893,7 +957,7 @@ static size_t naclbox_overhead(const bulkalgs *aa)
 static size_t naclbox_expsz(const bulkalgs *aa)
   { return (MEG(2048)); }
 
-static bulkctx *naclbox_genkeys(const bulkalgs *aa, const struct rawkey *rk)
+static bulkctx *naclbox_genkeys(const bulkalgs *aa, const deriveargs *da)
 {
   const naclbox_algs *a = (const naclbox_algs *)aa;
   naclbox_ctx *bc = CREATE(naclbox_ctx);
@@ -901,7 +965,8 @@ static bulkctx *naclbox_genkeys(const bulkalgs *aa, const struct rawkey *rk)
   int i;
 
   for (i = 0; i < NDIR; i++) {
-    ks_derivekey(k, a->cksz, rk, i, "encryption");
+    if (!(da->f&(1 << i))) { bc->d[i].c = 0; continue; }
+    derivekey(k, a->cksz, da, i, "encryption");
     bc->d[i].c = GC_INIT(a->c, k, a->cksz);
   }
   return (&bc->_b);
@@ -960,7 +1025,7 @@ static void naclbox_freectx(bulkctx *bbc)
   naclbox_ctx *bc = (naclbox_ctx *)bbc;
   int i;
 
-  for (i = 0; i < NDIR; i++) GC_DESTROY(bc->d[i].c);
+  for (i = 0; i < NDIR; i++) { if (bc->d[i].c) GC_DESTROY(bc->d[i].c); }
   DESTROY(bc);
 }
 
@@ -975,6 +1040,8 @@ static int naclbox_encrypt(bulkctx *bbc, unsigned ty,
   size_t sz = BLEFT(b);
   octet *qmac, *qseq, *qpk;
 
+  assert(c);
+
   /* --- Determine the ciphertext layout --- */
 
   if (buf_ensure(bb, POLY1305_TAGSZ + SEQSZ + sz)) return (0);
@@ -1022,6 +1089,8 @@ static int naclbox_decrypt(bulkctx *bbc, unsigned ty,
   size_t sz;
   octet *q = BCUR(bb);
 
+  assert(c);
+
   /* --- Break up the packet into its components --- */
 
   if (psz < SEQSZ + POLY1305_TAGSZ) {
index 9d08bec6442e34347bc2a8a8293fed8ab5c04423..be5bc88085bfbc3f11ceb252f7d3b11366806d81 100644 (file)
@@ -637,8 +637,8 @@ static kxchal *respond(keyexch *kx, unsigned msg, buf *b)
   dhge *C = 0;
   dhge *R = 0;
   dhge *CC = 0;
+  deriveargs a;
   const octet *hc, *ck;
-  size_t x, y, z;
   dhsc *c = 0;
   kxchal *kxc;
   ghash *h = 0;
@@ -752,13 +752,13 @@ static kxchal *respond(keyexch *kx, unsigned msg, buf *b)
 
     /* --- Create a new symmetric keyset --- */
 
-    buf_init(&bb, buf_o, sizeof(buf_o));
-    g->ops->stge(g, &bb, kx->C, DHFMT_HASH); x = BLEN(&bb);
-    g->ops->stge(g, &bb, kxc->C, DHFMT_HASH); y = BLEN(&bb);
-    g->ops->stge(g, &bb, R, DHFMT_HASH); z = BLEN(&bb);
+    buf_init(&bb, buf_o, sizeof(buf_o)); a.k = BBASE(&bb);
+    g->ops->stge(g, &bb, kx->C, DHFMT_HASH); a.x = BLEN(&bb);
+    g->ops->stge(g, &bb, kxc->C, DHFMT_HASH); a.y = BLEN(&bb);
+    g->ops->stge(g, &bb, R, DHFMT_HASH); a.z = BLEN(&bb);
     assert(BOK(&bb));
 
-    kxc->ks = ks_gen(BBASE(&bb), x, y, z, kx->p);
+    kxc->ks = ks_gen(&a, kx->p);
   }
 
   if (C) g->ops->freege(g, C);
index 9429fa4ab01d3c37b7c3c8078aa4b5bec5d1c3a3..a0c4577d0e32fc92c55a46c5d345d3d434bbd9b7 100644 (file)
@@ -169,95 +169,33 @@ void ks_drop(keyset *ks)
   DESTROY(ks);
 }
 
-/* --- @ks_derivekey@ --- *
- *
- * Arguments:  @octet *k@ = pointer to an output buffer of at least
- *                     @MAXHASHSZ@ bytes
- *             @size_t ksz@ = actual size wanted (for tracing)
- *             @const struct rawkey *rk@ = a raw key, as passed into
- *                     @genkeys@
- *             @int dir@ = direction for the key (@DIR_IN@ or @DIR_OUT@)
- *             @const char *what@ = label for the key (input to derivation)
- *
- * Returns:    ---
- *
- * Use:                Derives a session key, for use on incoming or outgoing data.
- *             This function is part of a private protocol between @ks_gen@
- *             and the bulk crypto transform @genkeys@ operation.
- */
-
-struct rawkey {
-  const gchash *hc;
-  const octet *k;
-  size_t x, y, z;
-};
-
-void ks_derivekey(octet *k, size_t ksz, const struct rawkey *rk,
-                 int dir, const char *what)
-{
-  const gchash *hc = rk->hc;
-  ghash *h;
-
-  assert(ksz <= hc->hashsz);
-  assert(hc->hashsz <= MAXHASHSZ);
-  h = GH_INIT(hc);
-  GH_HASH(h, "tripe-", 6); GH_HASH(h, what, strlen(what) + 1);
-  switch (dir) {
-    case DIR_IN:
-      GH_HASH(h, rk->k, rk->x);
-      GH_HASH(h, rk->k + rk->x, rk->y - rk->x);
-      break;
-    case DIR_OUT:
-      GH_HASH(h, rk->k + rk->x, rk->y - rk->x);
-      GH_HASH(h, rk->k, rk->x);
-      break;
-    default:
-      abort();
-  }
-  GH_HASH(h, rk->k + rk->y, rk->z - rk->y);
-  GH_DONE(h, k);
-  GH_DESTROY(h);
-  IF_TRACING(T_KEYSET, { IF_TRACING(T_CRYPTO, {
-    char _buf[32];
-    sprintf(_buf, "crypto: %s key %s", dir ? "outgoing" : "incoming", what);
-    trace_block(T_CRYPTO, _buf, k, ksz);
-  }) })
-}
-
 /* --- @ks_gen@ --- *
  *
- * Arguments:  @const void *k@ = pointer to key material
- *             @size_t x, y, z@ = offsets into key material (see below)
+ * Arguments:  @deriveargs *a@ = key derivation parameters (modified)
  *             @peer *p@ = pointer to peer information
  *
  * Returns:    A pointer to the new keyset.
  *
- * Use:                Derives a new keyset from the given key material.  The
- *             offsets @x@, @y@ and @z@ separate the key material into three
- *             parts.  Between the @k@ and @k + x@ is `my' contribution to
- *             the key material; between @k + x@ and @k + y@ is `your'
- *             contribution; and between @k + y@ and @k + z@ is a shared
- *             value we made together.  These are used to construct two
- *             collections of symmetric keys: one for outgoing messages, the
- *             other for incoming messages.
+ * Use:                Derives a new keyset from the given key material.  This will
+ *             set the @what@, @f@, and @hc@ members in @*a@; other members
+ *             must be filled in by the caller.
  *
  *             The new key is marked so that it won't be selected for output
  *             by @ksl_encrypt@.  You can still encrypt data with it by
  *             calling @ks_encrypt@ directly.
  */
 
-keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p)
+keyset *ks_gen(deriveargs *a, peer *p)
 {
   keyset *ks = CREATE(keyset);
   time_t now = time(0);
   const algswitch *algs = &p->kx.kpriv->algs;
-  struct rawkey rk;
   T( static unsigned seq = 0; )
 
   T( trace(T_KEYSET, "keyset: adding new keyset %u", seq); )
 
-  rk.hc = algs->h; rk.k = k; rk.x = x; rk.y = y; rk.z = z;
-  ks->bulk = algs->bulk->ops->genkeys(algs->bulk, &rk);
+  a->what = "tripe-"; a->f = DF_IN | DF_OUT; a->hc = algs->h;
+  ks->bulk = algs->bulk->ops->genkeys(algs->bulk, a);
   ks->bulk->ops = algs->bulk->ops;
 
   T( ks->seq = seq++; )
index 4b6c7101434260dc007298800d5e007aa72a830c..75ad2f1f5d1e357bfdca8d4e2f9728cfb8336ea4 100644 (file)
@@ -181,6 +181,16 @@ enum {
   DHFMT_VAR                   /* Variable-width-format, mostly a bad idea */
 };
 
+typedef struct deriveargs {
+  const char *what;                    /* Operation name (hashed) */
+  unsigned f;                          /* Flags */
+#define DF_IN 1u                       /*   Make incoming key */
+#define DF_OUT 2u                      /*   Make outgoing key */
+  const gchash *hc;                    /* Hash class */
+  const octet *k;                      /* Pointer to contributions */
+  size_t x, y, z;                      /* Markers in contributions */
+} deriveargs;
+
 typedef struct bulkalgs {
   const struct bulkops *ops;
 } bulkalgs;
@@ -194,8 +204,6 @@ typedef struct bulkchal {
   size_t tagsz;
 } bulkchal;
 
-struct rawkey;
-
 typedef struct dhops {
   const char *name;
 
@@ -325,9 +333,17 @@ typedef struct bulkops {
         * after which the keys must no longer be used.
         */
 
-  bulkctx *(*genkeys)(const bulkalgs */*a*/, const struct rawkey */*rk*/);
+  bulkctx *(*genkeys)(const bulkalgs */*a*/, const deriveargs */*a*/);
        /* Generate session keys and construct and return an appropriate
-        * context for using them, by calling @ks_derive@.
+        * context for using them.  The offsets @a->x@, @a->y@ and @a->z@
+        * separate the key material into three parts.  Between @a->k@ and
+        * @a->k + a->x@ is `my' contribution to the key material; between
+        * @a->k + a->x@ and @a->k + a->y@ is `your' contribution; and
+        * between @a->k + a->y@ and @a->k + a->z@ is a shared value we made
+        * together.  These are used to construct (up to) two collections of
+        * symmetric keys: one for outgoing messages, the other for incoming
+        * messages.  If @a->x == 0@ (or @a->y == a->x@) then my (or your)
+        * contribution is omitted.
         */
 
   bulkchal *(*genchal)(const bulkalgs */*a*/);
@@ -939,52 +955,23 @@ extern int kx_init(keyexch */*kx*/, peer */*p*/,
 
 extern void ks_drop(keyset */*ks*/);
 
-/* --- @ks_derivekey@ --- *
- *
- * Arguments:  @octet *k@ = pointer to an output buffer of at least
- *                     @MAXHASHSZ@ bytes
- *             @size_t ksz@ = actual size wanted (for tracing)
- *             @const struct rawkey *rk@ = a raw key, as passed into
- *                     @genkeys@
- *             @int dir@ = direction for the key (@DIR_IN@ or @DIR_OUT@)
- *             @const char *what@ = label for the key (input to derivation)
- *
- * Returns:    ---
- *
- * Use:                Derives a session key, for use on incoming or outgoing data.
- *             This function is part of a private protocol between @ks_gen@
- *             and the bulk crypto transform @genkeys@ operation.
- */
-
-extern void ks_derivekey(octet */*k*/, size_t /*ksz*/,
-                        const struct rawkey */*rk*/,
-                        int /*dir*/, const char */*what*/);
-
 /* --- @ks_gen@ --- *
  *
- * Arguments:  @const void *k@ = pointer to key material
- *             @size_t x, y, z@ = offsets into key material (see below)
+ * Arguments:  @deriveargs *a@ = key derivation parameters (modified)
  *             @peer *p@ = pointer to peer information
  *
  * Returns:    A pointer to the new keyset.
  *
- * Use:                Derives a new keyset from the given key material.  The
- *             offsets @x@, @y@ and @z@ separate the key material into three
- *             parts.  Between the @k@ and @k + x@ is `my' contribution to
- *             the key material; between @k + x@ and @k + y@ is `your'
- *             contribution; and between @k + y@ and @k + z@ is a shared
- *             value we made together.  These are used to construct two
- *             collections of symmetric keys: one for outgoing messages, the
- *             other for incoming messages.
+ * Use:                Derives a new keyset from the given key material.  This will
+ *             set the @what@, @f@, and @hc@ members in @*a@; other members
+ *             must be filled in by the caller.
  *
  *             The new key is marked so that it won't be selected for output
  *             by @ksl_encrypt@.  You can still encrypt data with it by
  *             calling @ks_encrypt@ directly.
  */
 
-extern keyset *ks_gen(const void */*k*/,
-                     size_t /*x*/, size_t /*y*/, size_t /*z*/,
-                     peer */*p*/);
+extern keyset *ks_gen(deriveargs */*a*/, peer */*p*/);
 
 /* --- @ks_activate@ --- *
  *