summaryrefslogtreecommitdiffstats
path: root/wsutil/curve25519.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--wsutil/curve25519.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/wsutil/curve25519.c b/wsutil/curve25519.c
new file mode 100644
index 0000000..d40c0cf
--- /dev/null
+++ b/wsutil/curve25519.c
@@ -0,0 +1,102 @@
+/* curve25519.c
+ * NaCl/Sodium-compatible API for Curve25519 cryptography.
+ *
+ * Copyright (c) 2018, Peter Wu <peter@lekensteyn.nl>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "curve25519.h"
+#include <gcrypt.h>
+
+static inline void
+copy_and_reverse(unsigned char *dest, const unsigned char *src, size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ dest[n - 1 - i] = src[i];
+ }
+}
+
+static int
+x25519_mpi(unsigned char *q, const unsigned char *n, gcry_mpi_t mpi_p)
+{
+ unsigned char priv_be[32];
+ unsigned char result_be[32];
+ size_t result_len = 0;
+ gcry_mpi_t mpi = NULL;
+ gcry_ctx_t ctx = NULL;
+ gcry_mpi_point_t P = NULL;
+ gcry_mpi_point_t Q = NULL;
+ int r = -1;
+
+ /* Default to infinity (all zeroes). */
+ memset(q, 0, 32);
+
+ /* Keys are in little-endian, but gcry_mpi_scan expects big endian. Convert
+ * keys and ensure that the result is a valid Curve25519 secret scalar. */
+ copy_and_reverse(priv_be, n, 32);
+ priv_be[0] &= 127;
+ priv_be[0] |= 64;
+ priv_be[31] &= 248;
+ gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, priv_be, 32, NULL);
+
+ if (gcry_mpi_ec_new(&ctx, NULL, "Curve25519")) {
+ /* Should not happen, possibly out-of-memory. */
+ goto leave;
+ }
+
+ /* Compute Q = nP */
+ Q = gcry_mpi_point_new(0);
+ P = gcry_mpi_point_set(NULL, mpi_p, NULL, GCRYMPI_CONST_ONE);
+ gcry_mpi_ec_mul(Q, mpi, P, ctx);
+
+ /* Note: mpi is reused to store the result. */
+ if (gcry_mpi_ec_get_affine(mpi, NULL, Q, ctx)) {
+ /* Infinity. */
+ goto leave;
+ }
+
+ if (gcry_mpi_print(GCRYMPI_FMT_USG, result_be, 32, &result_len, mpi)) {
+ /* Should not happen, possibly out-of-memory. */
+ goto leave;
+ }
+ copy_and_reverse(q, result_be, result_len);
+ r = 0;
+
+leave:
+ gcry_mpi_point_release(P);
+ gcry_mpi_point_release(Q);
+ gcry_ctx_release(ctx);
+ gcry_mpi_release(mpi);
+ /* XXX erase priv_be and result_be */
+ return r;
+}
+
+int
+crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n,
+ const unsigned char *p)
+{
+ unsigned char p_be[32];
+ gcry_mpi_t mpi_p = NULL;
+
+ copy_and_reverse(p_be, p, 32);
+ /* Clear unused bit. */
+ p_be[0] &= 0x7f;
+ gcry_mpi_scan(&mpi_p, GCRYMPI_FMT_USG, p_be, 32, NULL);
+ int r = x25519_mpi(q, n, mpi_p);
+ gcry_mpi_release(mpi_p);
+ return r;
+}
+
+int
+crypto_scalarmult_curve25519_base(unsigned char *q, const unsigned char *n)
+{
+ gcry_mpi_t mpi_basepoint_x = gcry_mpi_set_ui(NULL, 9);
+ int r = x25519_mpi(q, n, mpi_basepoint_x);
+ gcry_mpi_release(mpi_basepoint_x);
+ return r;
+}