/* curve25519.c * NaCl/Sodium-compatible API for Curve25519 cryptography. * * Copyright (c) 2018, Peter Wu * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "curve25519.h" #include "ws_attributes.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; }