Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_ecc.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
26
27#include "nilorea/n_ecc.h"
28
29#include "nilorea/n_log.h"
30
31#ifdef HAVE_OPENSSL
32
33#include <openssl/evp.h>
34#include <openssl/err.h>
35
36#if N_ECC_AVAILABLE
37
38/* Generate a raw keypair for the given EVP_PKEY type (X25519 or Ed25519). */
39static int n_ecc_keypair(int type, unsigned char* priv, unsigned char* pub, const char* name) {
40 if (!priv || !pub) {
41 n_log(LOG_ERR, "%s: NULL output", name);
42 return -1;
43 }
44 int rc = -1;
45 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(type, NULL);
46 EVP_PKEY* pkey = NULL;
47 size_t plen;
48 if (!ctx) {
49 n_log(LOG_ERR, "%s: EVP_PKEY_CTX_new_id failed", name);
50 goto done;
51 }
52 if (EVP_PKEY_keygen_init(ctx) != 1 || EVP_PKEY_keygen(ctx, &pkey) != 1) {
53 n_log(LOG_ERR, "%s: keygen failed", name);
54 goto done;
55 }
56 plen = N_ECC_KEY_LEN;
57 if (EVP_PKEY_get_raw_private_key(pkey, priv, &plen) != 1 || plen != N_ECC_KEY_LEN) {
58 n_log(LOG_ERR, "%s: get_raw_private_key failed", name);
59 goto done;
60 }
61 plen = N_ECC_KEY_LEN;
62 if (EVP_PKEY_get_raw_public_key(pkey, pub, &plen) != 1 || plen != N_ECC_KEY_LEN) {
63 n_log(LOG_ERR, "%s: get_raw_public_key failed", name);
64 goto done;
65 }
66 rc = 0;
67done:
68 if (rc != 0)
69 ERR_clear_error(); /* never leave the thread error queue dirty */
70 EVP_PKEY_free(pkey);
71 EVP_PKEY_CTX_free(ctx);
72 return rc;
73}
74
75int n_x25519_keypair(unsigned char* priv, unsigned char* pub) {
76 return n_ecc_keypair(EVP_PKEY_X25519, priv, pub, "n_x25519_keypair");
77}
78
79int n_ed25519_keypair(unsigned char* priv, unsigned char* pub) {
80 return n_ecc_keypair(EVP_PKEY_ED25519, priv, pub, "n_ed25519_keypair");
81}
82
83int n_x25519_derive(const unsigned char* priv, const unsigned char* peer_pub, unsigned char* shared) {
84 if (!priv || !peer_pub || !shared) {
85 n_log(LOG_ERR, "n_x25519_derive: NULL argument");
86 return -1;
87 }
88 int rc = -1;
89 EVP_PKEY* pk = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, priv, N_ECC_KEY_LEN);
90 EVP_PKEY* peer = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, peer_pub, N_ECC_KEY_LEN);
91 EVP_PKEY_CTX* dctx = NULL;
92 size_t slen = N_ECC_KEY_LEN;
93 if (!pk || !peer) {
94 n_log(LOG_ERR, "n_x25519_derive: key import failed");
95 goto done;
96 }
97 dctx = EVP_PKEY_CTX_new(pk, NULL);
98 if (!dctx || EVP_PKEY_derive_init(dctx) != 1 || EVP_PKEY_derive_set_peer(dctx, peer) != 1) {
99 n_log(LOG_ERR, "n_x25519_derive: derive init failed");
100 goto done;
101 }
102 if (EVP_PKEY_derive(dctx, shared, &slen) != 1 || slen != N_ECC_KEY_LEN) {
103 n_log(LOG_ERR, "n_x25519_derive: derive failed");
104 goto done;
105 }
106 rc = 0;
107done:
108 if (rc != 0)
109 ERR_clear_error(); /* never leave the thread error queue dirty */
110 EVP_PKEY_CTX_free(dctx);
111 EVP_PKEY_free(peer);
112 EVP_PKEY_free(pk);
113 return rc;
114}
115
116int n_ed25519_sign(const unsigned char* priv, const unsigned char* msg, size_t len, unsigned char* sig) {
117 if (!priv || !sig || (!msg && len > 0)) {
118 n_log(LOG_ERR, "n_ed25519_sign: invalid arguments");
119 return -1;
120 }
121 int rc = -1;
122 EVP_PKEY* pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, priv, N_ECC_KEY_LEN);
123 EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
124 size_t siglen = N_ECC_SIG_LEN;
125 if (!pkey || !mdctx) {
126 n_log(LOG_ERR, "n_ed25519_sign: setup failed");
127 goto done;
128 }
129 if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
130 n_log(LOG_ERR, "n_ed25519_sign: init failed");
131 goto done;
132 }
133 if (EVP_DigestSign(mdctx, sig, &siglen, msg, len) != 1 || siglen != N_ECC_SIG_LEN) {
134 n_log(LOG_ERR, "n_ed25519_sign: sign failed");
135 goto done;
136 }
137 rc = 0;
138done:
139 if (rc != 0)
140 ERR_clear_error(); /* never leave the thread error queue dirty */
141 EVP_MD_CTX_free(mdctx);
142 EVP_PKEY_free(pkey);
143 return rc;
144}
145
146int n_ed25519_verify(const unsigned char* pub, const unsigned char* msg, size_t len, const unsigned char* sig) {
147 if (!pub || !sig || (!msg && len > 0)) {
148 n_log(LOG_ERR, "n_ed25519_verify: invalid arguments");
149 return -1;
150 }
151 int rc = -1;
152 EVP_PKEY* pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, pub, N_ECC_KEY_LEN);
153 EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
154 if (!pkey || !mdctx) {
155 n_log(LOG_ERR, "n_ed25519_verify: setup failed");
156 goto done;
157 }
158 if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
159 n_log(LOG_ERR, "n_ed25519_verify: init failed");
160 goto done;
161 }
162 /* EVP_DigestVerify returns 1 for a valid signature, 0 for an invalid one,
163 negative on error; only a valid signature is a success here. */
164 if (EVP_DigestVerify(mdctx, sig, N_ECC_SIG_LEN, msg, len) == 1)
165 rc = 0;
166done:
167 /* A signature mismatch is a NORMAL outcome (e.g. probing which of several
168 candidate keys signed a message), yet EVP_DigestVerify pushes an entry
169 onto the OpenSSL per-thread error queue on any non-match. Left there,
170 that stale entry misleads a later, unrelated OpenSSL call on the same
171 thread -- the classic trap where SSL_get_error() then returns
172 SSL_ERROR_SSL and a healthy connection is torn down. Drain the queue on
173 every non-success path so it reflects only genuine, unhandled failures. */
174 if (rc != 0)
175 ERR_clear_error();
176 EVP_MD_CTX_free(mdctx);
177 EVP_PKEY_free(pkey);
178 return rc;
179}
180
181#else /* !N_ECC_AVAILABLE */
182
183/* OpenSSL grew Curve25519 over two releases: EVP_PKEY_X25519 in 1.1.0 and
184 Ed25519 plus the raw-key import/export helpers in 1.1.1. The 1.0.2 this
185 library still targets has none of it, and there is no reasonable in-tree
186 substitute for the curve arithmetic, so the module keeps its symbols and
187 reports the primitive as unavailable instead. Callers test N_ECC_AVAILABLE
188 to skip the call rather than treat the -1 as a failure. */
189
190int n_x25519_keypair(unsigned char* priv, unsigned char* pub) {
191 (void)priv;
192 (void)pub;
193 n_log(LOG_ERR, "n_x25519_keypair: requires OpenSSL 1.1.1+ (raw EVP_PKEY X25519 keys)");
194 return -1;
195}
196
197int n_ed25519_keypair(unsigned char* priv, unsigned char* pub) {
198 (void)priv;
199 (void)pub;
200 n_log(LOG_ERR, "n_ed25519_keypair: requires OpenSSL 1.1.1+ (raw EVP_PKEY Ed25519 keys)");
201 return -1;
202}
203
204int n_x25519_derive(const unsigned char* priv, const unsigned char* peer_pub, unsigned char* shared) {
205 (void)priv;
206 (void)peer_pub;
207 (void)shared;
208 n_log(LOG_ERR, "n_x25519_derive: requires OpenSSL 1.1.1+ (raw EVP_PKEY X25519 keys)");
209 return -1;
210}
211
212int n_ed25519_sign(const unsigned char* priv, const unsigned char* msg, size_t len, unsigned char* sig) {
213 (void)priv;
214 (void)msg;
215 (void)len;
216 (void)sig;
217 n_log(LOG_ERR, "n_ed25519_sign: requires OpenSSL 1.1.1+ (raw EVP_PKEY Ed25519 keys)");
218 return -1;
219}
220
221int n_ed25519_verify(const unsigned char* pub, const unsigned char* msg, size_t len, const unsigned char* sig) {
222 (void)pub;
223 (void)msg;
224 (void)len;
225 (void)sig;
226 n_log(LOG_ERR, "n_ed25519_verify: requires OpenSSL 1.1.1+ (raw EVP_PKEY Ed25519 keys)");
227 return -1;
228}
229
230#endif /* N_ECC_AVAILABLE */
231
232#endif /* HAVE_OPENSSL */
static void type(N_GUI_CTX *gui, const char *s)
Type a whole string into whatever has focus.
volatile sig_atomic_t done
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_ERR
error conditions
Definition n_log.h:100
int n_ed25519_keypair(unsigned char *priv, unsigned char *pub)
generate an Ed25519 keypair as N_ECC_KEY_LEN-byte raw private and public keys.
Definition n_ecc.c:197
int n_ed25519_verify(const unsigned char *pub, const unsigned char *msg, size_t len, const unsigned char *sig)
Ed25519 verify the N_ECC_SIG_LEN-byte sig over len bytes of msg under the N_ECC_KEY_LEN-byte raw publ...
Definition n_ecc.c:221
int n_x25519_keypair(unsigned char *priv, unsigned char *pub)
generate an X25519 keypair as N_ECC_KEY_LEN-byte raw private and public keys.
Definition n_ecc.c:190
#define N_ECC_SIG_LEN
Ed25519 signature length in bytes.
Definition n_ecc.h:48
#define N_ECC_KEY_LEN
raw X25519/Ed25519 key length in bytes
Definition n_ecc.h:46
int n_ed25519_sign(const unsigned char *priv, const unsigned char *msg, size_t len, unsigned char *sig)
Ed25519 sign len bytes of msg with the N_ECC_KEY_LEN-byte raw private key into sig (N_ECC_SIG_LEN byt...
Definition n_ecc.c:212
int n_x25519_derive(const unsigned char *priv, const unsigned char *peer_pub, unsigned char *shared)
X25519 ECDH: derive the N_ECC_KEY_LEN-byte shared secret from our raw private key and the peer's raw ...
Definition n_ecc.c:204
Curve25519 primitives: X25519 key agreement and Ed25519 signatures.
Generic log system.