+/*
+ * xdh.c: x-coordinate-only Montgomery-ladder elliptic-curve Diffie--Hellman
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2017 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+#include <limits.h>
+
+#include "secnet.h"
+#include "magic.h"
+#include "util.h"
+
+#include "x25519.h"
+#include "x448.h"
+
+#define XDH_MAXSZ 64
+
+typedef void xdh_fn(uint8_t *z, const uint8_t *k, const uint8_t *x);
+
+struct xdh {
+ closure_t cl;
+ struct dh_if ops;
+ xdh_fn *fn;
+ const uint8_t *base;
+};
+
+static int32_t xdh_makepublic(void *sst, void *pub, int32_t publen,
+ uint8_t *k, int32_t klen)
+{
+ struct xdh *st = sst;
+
+ assert(klen == st->ops.secret_len);
+ assert(publen >= st->ops.public_len);
+ st->fn(pub, k, st->base);
+ return st->ops.public_len;
+}
+
+static bool_t xdh_makeshared(void *sst,
+ uint8_t *k, int32_t klen,
+ const void *pub, int32_t publen,
+ uint8_t *z, int32_t zlen)
+{
+ struct xdh *st = sst;
+
+ assert(klen == st->ops.secret_len);
+ assert(zlen >= st->ops.shared_len);
+ if (publen != st->ops.public_len) {
+ Message(M_ERR,
+ "xdh_makeshared: incoming public point has wrong length");
+ return False;
+ }
+ st->fn(z, k, pub);
+ return (True);
+}
+
+static void make_xdh_closure(dict_t *dict, const char *name, xdh_fn *fn,
+ const uint8_t *base, size_t sz, int cap)
+{
+ struct xdh *st;
+
+ NEW(st);
+ st->cl.description = name;
+ st->cl.type = CL_DH;
+ st->cl.apply = 0;
+ st->cl.interface = &st->ops;
+ st->ops.st = st;
+ st->ops.makepublic = xdh_makepublic;
+ st->ops.makeshared = xdh_makeshared;
+ st->ops.secret_len = st->ops.public_len = st->ops.shared_len = sz;
+ st->ops.capab_bit = cap;
+ st->fn = fn;
+ st->base = base;
+ dict_add(dict, name, new_closure(&st->cl));
+}
+
+void xdh_module(dict_t *dict)
+{
+ make_xdh_closure(dict, "x25519", x25519, x25519_base,
+ X25519_PUBSZ, CAPAB_BIT_X25519);
+ make_xdh_closure(dict, "x448", x448, x448_base,
+ X448_PUBSZ, CAPAB_BIT_X448);
+}