+/* --- @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);
+ }) })
+}
+