wmem: allow wmem_destroy_list to ignore a NULL list.
[metze/wireshark/wip.git] / wsutil / curve25519.c
1 /* curve25519.c
2  * NaCl/Sodium-compatible API for Curve25519 cryptography.
3  *
4  * Copyright (c) 2018, Peter Wu <peter@lekensteyn.nl>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  */
12
13 #include "curve25519.h"
14
15 #ifdef HAVE_X25519
16 static inline void
17 copy_and_reverse(unsigned char *dest, const unsigned char *src, size_t n)
18 {
19     for (size_t i = 0; i < n; i++) {
20         dest[n - 1 - i] = src[i];
21     }
22 }
23
24 static int
25 x25519_mpi(unsigned char *q, const unsigned char *n, gcry_mpi_t mpi_p)
26 {
27     unsigned char priv_be[32];
28     unsigned char result_be[32];
29     size_t result_len = 0;
30     gcry_mpi_t mpi = NULL;
31     gcry_ctx_t ctx = NULL;
32     gcry_mpi_point_t P = NULL;
33     gcry_mpi_point_t Q = NULL;
34     int r = -1;
35
36     /* Default to infinity (all zeroes). */
37     memset(q, 0, 32);
38
39     /* Keys are in little-endian, but gcry_mpi_scan expects big endian. Convert
40      * keys and ensure that the result is a valid Curve25519 secret scalar. */
41     copy_and_reverse(priv_be, n, 32);
42     priv_be[0] &= 127;
43     priv_be[0] |= 64;
44     priv_be[31] &= 248;
45     gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, priv_be, 32, NULL);
46
47     if (gcry_mpi_ec_new(&ctx, NULL, "Curve25519")) {
48         /* Should not happen, possibly out-of-memory. */
49         goto leave;
50     }
51
52     /* Compute Q = nP */
53     Q = gcry_mpi_point_new(0);
54     P = gcry_mpi_point_set(NULL, mpi_p, NULL, GCRYMPI_CONST_ONE);
55     gcry_mpi_ec_mul(Q, mpi, P, ctx);
56
57     /* Note: mpi is reused to store the result. */
58     if (gcry_mpi_ec_get_affine(mpi, NULL, Q, ctx)) {
59         /* Infinity. */
60         goto leave;
61     }
62
63     if (gcry_mpi_print(GCRYMPI_FMT_USG, result_be, 32, &result_len, mpi)) {
64         /* Should not happen, possibly out-of-memory. */
65         goto leave;
66     }
67     copy_and_reverse(q, result_be, result_len);
68     r = 0;
69
70 leave:
71     gcry_mpi_point_release(P);
72     gcry_mpi_point_release(Q);
73     gcry_ctx_release(ctx);
74     gcry_mpi_release(mpi);
75     /* XXX erase priv_be and result_be */
76     return r;
77 }
78
79 int
80 crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n,
81                              const unsigned char *p)
82 {
83     unsigned char p_be[32];
84     gcry_mpi_t mpi_p = NULL;
85
86     copy_and_reverse(p_be, p, 32);
87     /* Clear unused bit. */
88     p_be[0] &= 0x7f;
89     gcry_mpi_scan(&mpi_p, GCRYMPI_FMT_USG, p_be, 32, NULL);
90     int r = x25519_mpi(q, n, mpi_p);
91     gcry_mpi_release(mpi_p);
92     return r;
93 }
94
95 int
96 crypto_scalarmult_curve25519_base(unsigned char *q, const unsigned char *n)
97 {
98     gcry_mpi_t mpi_basepoint_x = gcry_mpi_set_ui(NULL, 9);
99     int r = x25519_mpi(q, n, mpi_basepoint_x);
100     gcry_mpi_release(mpi_basepoint_x);
101     return r;
102 }
103 #endif /* HAVE_X25519 */