103 lines
2.7 KiB
C
103 lines
2.7 KiB
C
/* 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;
|
|
}
|