wsutil: Add Curve25519 ECDH (X25519) using Gcrypt
The WireGuard dissector will need X25519 to enable decryption, add a Gcrypt implementation that implements the NaCl/Sodium interface. While inspired by the MPI example in t-cv25519.c, note subtle but important correctness/interoperability fixes: add a check for infinity (gcry_mpi_ec_get_affine) and handle short values from gcry_mpi_print. The last issue is ugly, perhaps the high level API (gcry_pk_decrypt) should be used instead (which < 2% slower than this MPI implementation). (Both issues were found through fuzzing.) As for alternative options, Sodium is superior but would be a new dependency. For some older performance and usability notes (comparing crypto_scalarmult_curve25519_base (note "_base") against others), see https://lists.gnupg.org/pipermail/gcrypt-devel/2018-July/004532.html Performance comparison on Ubuntu 18.04 (i7-3770) between Sodium 1.0.16 against Gcrypt 1.8.3 and Gcrypt 86e5e06a (git master, future 1.9.x) by computing 65536 times X25519(1, 8) via crypto_scalarmult_curve25519: Sodium (sandy2x): 1.4x faster than ref10 Sodium (ref10): 1 (baseline) Gcrypt (git): 5x slower than ref10, 7x slower than sandy2x Gcrypt (1.8.3): 17x ref10, 24x sandy2x (took 65 seconds) Change-Id: Ia54e73cc3cc469a6697554729aff4edd19f55630 Ping-Bug: 15011 Reviewed-on: https://code.wireshark.org/review/28987 Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
e50ae0ad11
commit
d7187e0b1b
|
@ -44,6 +44,8 @@ libwsutil.so.0 libwsutil0 #MINVER#
|
|||
create_tempfile@Base 1.12.0~rc1
|
||||
create_timestamp@Base 2.5.0
|
||||
crypt_des_ecb@Base 2.3.0
|
||||
crypto_scalarmult_curve25519@Base 2.9.0
|
||||
crypto_scalarmult_curve25519_base@Base 2.9.0
|
||||
data_file_url@Base 2.3.0
|
||||
decrypt_xtea_ecb@Base 2.5.0
|
||||
decrypt_xtea_le_ecb@Base 2.5.0
|
||||
|
|
|
@ -35,6 +35,7 @@ set(WSUTIL_PUBLIC_HEADERS
|
|||
crc16.h
|
||||
crc16-plain.h
|
||||
crc32.h
|
||||
curve25519.h
|
||||
eax.h
|
||||
filesystem.h
|
||||
frequency-utils.h
|
||||
|
@ -92,6 +93,7 @@ set(WSUTIL_COMMON_FILES
|
|||
crc7.c
|
||||
crc8.c
|
||||
crc11.c
|
||||
curve25519.c
|
||||
dot11decrypt_wep.c
|
||||
eax.c
|
||||
filesystem.c
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/* 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"
|
||||
|
||||
#ifdef HAVE_X25519
|
||||
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;
|
||||
}
|
||||
#endif /* HAVE_X25519 */
|
|
@ -0,0 +1,41 @@
|
|||
/* curve25519.h
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __CURVE25519_H__
|
||||
#define __CURVE25519_H__
|
||||
|
||||
#include "ws_symbol_export.h"
|
||||
#include "wsgcrypt.h"
|
||||
|
||||
#if GCRYPT_VERSION_NUMBER >= 0x010700 /* 1.7.0 */
|
||||
#define HAVE_X25519
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_X25519
|
||||
/*
|
||||
* Computes Q = X25519(n, P). In other words, given the secret key n, the public
|
||||
* key P, compute the shared secret Q. Each key is 32 bytes long.
|
||||
* Returns 0 on success or -1 on failure.
|
||||
*/
|
||||
WS_DLL_PUBLIC
|
||||
int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n,
|
||||
const unsigned char *p);
|
||||
|
||||
/*
|
||||
* Computes the Curve25519 32-byte public key Q from the 32-byte secret key n.
|
||||
* Returns 0 on success or -1 on failure.
|
||||
*/
|
||||
WS_DLL_PUBLIC
|
||||
int crypto_scalarmult_curve25519_base(unsigned char *q, const unsigned char *n);
|
||||
#endif /* HAVE_X25519 */
|
||||
|
||||
#endif /* __CURVE25519_H__ */
|
Loading…
Reference in New Issue