Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl-sp-math/wolfcrypt/src/curve25519.c
Line
Count
Source
1
/* curve25519.c
2
 *
3
 * Copyright (C) 2006-2026 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
22
23
 /* Based On Daniel J Bernstein's curve25519 Public Domain ref10 work. */
24
25
/*
26
 * X25519 configuration macros:
27
 *
28
 * WC_X25519_NONBLOCK: Enable non-blocking support for key gen and shared
29
 *                     secret. Requires CURVE25519_SMALL. Default: off.
30
 */
31
32
#define _WC_BUILDING_CURVE25519_C
33
34
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
35
36
#ifdef NO_CURVED25519_X64
37
    #undef USE_INTEL_SPEEDUP
38
#endif
39
40
#ifdef HAVE_CURVE25519
41
42
#include <wolfssl/wolfcrypt/curve25519.h>
43
#include <wolfssl/wolfcrypt/ge_operations.h>
44
#include <wolfssl/wolfcrypt/error-crypt.h>
45
#include <wolfssl/wolfcrypt/logging.h>
46
#ifdef NO_INLINE
47
    #include <wolfssl/wolfcrypt/misc.h>
48
#else
49
    #define WOLFSSL_MISC_INCLUDED
50
    #include <wolfcrypt/src/misc.c>
51
#endif
52
53
#if defined(FREESCALE_LTC_ECC)
54
    #include <wolfssl/wolfcrypt/port/nxp/ksdk_port.h>
55
#endif
56
#ifdef WOLFSSL_SE050
57
    #include <wolfssl/wolfcrypt/port/nxp/se050_port.h>
58
#endif
59
60
#ifdef WOLF_CRYPTO_CB
61
    #include <wolfssl/wolfcrypt/cryptocb.h>
62
#endif
63
64
#if defined(WOLFSSL_CURVE25519_BLINDING)
65
    #if defined(CURVE25519_SMALL)
66
        #error "Blinding not needed nor available for small implementation"
67
    #elif defined(USE_INTEL_SPEEDUP) || defined(WOLFSSL_ARMASM)
68
        #error "Blinding not needed nor available for assembly implementation"
69
    #elif defined(WOLFSSL_CURVE25519_USE_ED25519)
70
        #error "Ed25519 base scalar mult cannot be used with blinding "
71
    #endif
72
#endif
73
74
#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && !defined(USE_INTEL_SPEEDUP)
75
    /* force off unneeded vector register save/restore. */
76
    #undef SAVE_VECTOR_REGISTERS
77
    #define SAVE_VECTOR_REGISTERS(fail_clause) SAVE_NO_VECTOR_REGISTERS(fail_clause)
78
    #undef RESTORE_VECTOR_REGISTERS
79
    #define RESTORE_VECTOR_REGISTERS() RESTORE_NO_VECTOR_REGISTERS()
80
#endif
81
82
const curve25519_set_type curve25519_sets[] = {
83
    {
84
        CURVE25519_KEYSIZE,
85
        "CURVE25519",
86
    }
87
};
88
89
/* base point is only referenced by the software scalar-mult paths, which are
90
 * compiled out under WOLF_CRYPTO_CB_ONLY_CURVE25519 */
91
#if !defined(WOLF_CRYPTO_CB_ONLY_CURVE25519) && \
92
    ((!defined(WOLFSSL_CURVE25519_USE_ED25519) && \
93
     !(defined(CURVED25519_X64) || (defined(WOLFSSL_ARMASM) && \
94
     defined(__aarch64__)))) || defined(WOLFSSL_CURVE25519_BLINDING) || \
95
     defined(WC_X25519_NONBLOCK))
96
static const word32 kCurve25519BasePoint[CURVE25519_KEYSIZE/sizeof(word32)] = {
97
#ifdef BIG_ENDIAN_ORDER
98
    0x09000000
99
#else
100
    9
101
#endif
102
};
103
#endif /* !WOLFSSL_CURVE25519_USE_ED25519 || WOLFSSL_CURVE25519_BLINDING */
104
105
/* Curve25519 private key must be less than order */
106
/* These functions clamp private k and check it */
107
static WC_INLINE int curve25519_priv_clamp(byte* priv)
108
5.77k
{
109
5.77k
    priv[0]  &= 248;
110
5.77k
    priv[CURVE25519_KEYSIZE-1] &= 127;
111
5.77k
    priv[CURVE25519_KEYSIZE-1] |= 64;
112
5.77k
    return 0;
113
5.77k
}
114
static WC_INLINE int curve25519_priv_clamp_check(const byte* priv)
115
7.09k
{
116
    /* check that private part of key has been clamped per RFC 7748 section 5:
117
     *   bits 0-2 of byte 0 must be clear  (priv[0] &= 248)
118
     *   bit 7 of byte 31 must be clear    (priv[31] &= 127)
119
     *   bit 6 of byte 31 must be set      (priv[31] |= 64)  */
120
7.09k
    int ret = 0;
121
7.09k
    if ((priv[0] & ~248) ||
122
7.09k
        (priv[CURVE25519_KEYSIZE-1] & 128) ||
123
7.09k
        !(priv[CURVE25519_KEYSIZE-1] & 64)) {
124
0
        ret = ECC_BAD_ARG_E;
125
0
    }
126
7.09k
    return ret;
127
7.09k
}
128
129
static WC_INLINE void curve25519_copy_point(byte* out, const byte* point,
130
    int endian)
131
6.07k
{
132
6.07k
    if (endian == EC25519_BIG_ENDIAN) {
133
3
        int i;
134
        /* put shared secret key in Big Endian format */
135
99
        for (i = 0; i < CURVE25519_KEYSIZE; i++) {
136
96
            out[i] = point[CURVE25519_KEYSIZE - i -1];
137
96
        }
138
3
    }
139
6.06k
    else { /* put shared secret key in Little Endian format */
140
6.06k
        XMEMCPY(out, point, CURVE25519_KEYSIZE);
141
6.06k
    }
142
6.07k
}
143
144
#if defined(WOLFSSL_CURVE25519_BLINDING) && !defined(FREESCALE_LTC_ECC) && \
145
    !defined(WOLF_CRYPTO_CB_ONLY_CURVE25519)
146
static int curve25519_make_pub_blind_sw(int public_size, byte* pub,
147
    const byte* priv, WC_RNG* rng);
148
#endif
149
150
/* Compute pub = priv * basepoint(9).
151
 *
152
 * devId  [in]  Device to offer the private scalar to, or INVALID_DEVID to keep
153
 *              it in software.  A key passes its own devId, so an unbound key
154
 *              is never offloaded to whichever device happens to be registered
155
 *              first; a caller holding no key passes the build default.
156
 */
157
static int curve25519_make_pub_ex(int public_size, byte* pub, int private_size,
158
                                  const byte* priv, int devId)
159
1.31k
{
160
1.31k
    int ret;
161
#if defined(FREESCALE_LTC_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_CURVE25519)
162
    const ECPoint* basepoint = nxp_ltc_curve25519_GetBasePoint();
163
    ECPoint wc_pub;
164
#endif
165
166
1.31k
    if ((public_size != CURVE25519_KEYSIZE) ||
167
1.31k
        (private_size != CURVE25519_KEYSIZE)) {
168
0
        return ECC_BAD_ARG_E;
169
0
    }
170
1.31k
    if ((pub == NULL) || (priv == NULL)) {
171
0
        return ECC_BAD_ARG_E;
172
0
    }
173
174
    /* check clamping */
175
1.31k
    ret = curve25519_priv_clamp_check(priv);
176
1.31k
    if (ret != 0)
177
0
        return ret;
178
179
1.31k
#ifdef WOLF_CRYPTO_CB
180
1.31k
    #ifndef WOLF_CRYPTO_CB_FIND
181
1.31k
    if (devId != INVALID_DEVID)
182
1.31k
    #endif
183
1.31k
    {
184
1.31k
        ret = wc_CryptoCb_Curve25519MakePub(devId, public_size, pub,
185
1.31k
            private_size, priv);
186
1.31k
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
187
0
            return ret;
188
        /* fall-through when unavailable */
189
1.31k
    }
190
#else
191
    (void)devId;
192
#endif
193
194
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519
195
    return NO_VALID_DEVID;
196
#else
197
#ifdef FREESCALE_LTC_ECC
198
    /* input basepoint on Weierstrass curve */
199
    ret = nxp_ltc_curve25519(&wc_pub, priv, basepoint, kLTC_Weierstrass);
200
    if (ret == 0) {
201
        XMEMCPY(pub, wc_pub.point, CURVE25519_KEYSIZE);
202
    }
203
#else
204
#ifndef WOLFSSL_CURVE25519_BLINDING
205
    fe_init();
206
207
    SAVE_VECTOR_REGISTERS(return _svr_ret;);
208
209
#if defined(WOLFSSL_CURVE25519_USE_ED25519)
210
    {
211
        ge_p3 A;
212
213
        ge_scalarmult_base(&A, priv);
214
    #ifndef CURVE25519_SMALL
215
        fe_add(A.X, A.Z, A.Y);
216
        fe_sub(A.T, A.Z, A.Y);
217
        fe_invert(A.T, A.T);
218
        fe_mul(A.T, A.X, A.T);
219
        fe_tobytes(pub, A.T);
220
    #else
221
        lm_add(A.X, A.Z, A.Y);
222
        lm_sub(A.T, A.Z, A.Y);
223
        lm_invert(A.T, A.T);
224
        lm_mul(pub, A.X, A.T);
225
    #endif
226
        ret = 0;
227
    }
228
#elif defined(CURVED25519_X64) || (defined(WOLFSSL_ARMASM) && \
229
    defined(__aarch64__))
230
    ret = curve25519_base(pub, priv);
231
#else
232
    ret = curve25519(pub, priv, (byte*)kCurve25519BasePoint);
233
#endif
234
235
    RESTORE_VECTOR_REGISTERS();
236
#else
237
1.31k
    {
238
1.31k
        WC_RNG rng;
239
240
1.31k
        ret = wc_InitRng(&rng);
241
1.31k
        if (ret == 0) {
242
866
            ret = curve25519_make_pub_blind_sw(public_size, pub, priv, &rng);
243
244
866
            wc_FreeRng(&rng);
245
866
        }
246
1.31k
    }
247
1.31k
#endif /* !WOLFSSL_CURVE25519_BLINDING */
248
1.31k
#endif /* FREESCALE_LTC_ECC */
249
250
/* If WOLFSSL_CURVE25519_BLINDING is defined, this check is run in
251
 * curve25519_make_pub_blind_sw since it could be reached directly. */
252
#if !defined(WOLFSSL_CURVE25519_BLINDING) || defined(FREESCALE_LTC_ECC)
253
    if (ret == 0) {
254
        ret = wc_curve25519_check_public(pub, (word32)public_size,
255
                                    EC25519_LITTLE_ENDIAN);
256
    }
257
#endif
258
259
1.31k
    return ret;
260
1.31k
#endif /* WOLF_CRYPTO_CB_ONLY_CURVE25519 */
261
1.31k
}
262
263
/* compute the public key from an existing private key, using bare vectors.
264
 *
265
 * return value is propagated from curve25519() (0 on success), or
266
 * ECC_BAD_ARG_E, and the byte vectors are little endian.
267
 */
268
int wc_curve25519_make_pub(int public_size, byte* pub, int private_size,
269
                           const byte* priv)
270
1.31k
{
271
1.31k
#ifdef WOLF_CRYPTO_CB
272
    /* no key names a device, so offer the scalar to the build default one */
273
1.31k
    const int devId = wc_CryptoCb_DefaultDevID();
274
#else
275
    const int devId = INVALID_DEVID;
276
#endif
277
278
1.31k
    return curve25519_make_pub_ex(public_size, pub, private_size, priv, devId);
279
1.31k
}
280
281
#ifdef WOLFSSL_CURVE25519_BLINDING
282
#ifndef FREESCALE_LTC_ECC
283
#ifndef WOLFSSL_CURVE25519_BLINDING_RAND_CNT
284
13.9k
    #define WOLFSSL_CURVE25519_BLINDING_RAND_CNT    10
285
#endif
286
#ifndef WOLF_CRYPTO_CB_ONLY_CURVE25519
287
static int curve25519_smul_blind(byte* rp, const byte* n, const byte* p,
288
    WC_RNG* rng)
289
6.93k
{
290
6.93k
    int ret;
291
6.93k
    byte a[CURVE25519_KEYSIZE];
292
6.93k
    byte n_a[CURVE25519_KEYSIZE];
293
6.93k
    byte rz[CURVE25519_KEYSIZE];
294
6.93k
    int i;
295
6.93k
    int cnt;
296
297
6.93k
    SAVE_VECTOR_REGISTERS(return _svr_ret;);
298
299
#ifdef WOLFSSL_CHECK_MEM_ZERO
300
    /* Register the blinding scalar/value buffers up front (but below the
301
     * SAVE_VECTOR_REGISTERS early return) so every path to the cleanup
302
     * ForceZero is checked. XMEMSET makes them defined before first use. */
303
    XMEMSET(a, 0, sizeof(a));
304
    XMEMSET(n_a, 0, sizeof(n_a));
305
    XMEMSET(rz, 0, sizeof(rz));
306
    wc_MemZero_Add("curve25519_smul_blind a", a, sizeof(a));
307
    wc_MemZero_Add("curve25519_smul_blind n_a", n_a, sizeof(n_a));
308
    wc_MemZero_Add("curve25519_smul_blind rz", rz, sizeof(rz));
309
#endif
310
311
    /* Generate random z. */
312
7.06k
    for (cnt = 0; cnt < WOLFSSL_CURVE25519_BLINDING_RAND_CNT; cnt++) {
313
7.06k
        ret = wc_RNG_GenerateBlock(rng, rz, sizeof(rz));
314
7.06k
        if (ret < 0) {
315
71
            goto cleanup;
316
71
        }
317
11.5k
        for (i = CURVE25519_KEYSIZE - 1; i >= 0; i--) {
318
11.4k
            if (rz[i] != 0xff)
319
6.86k
                break;
320
11.4k
        }
321
6.99k
        if ((i >= 0) || (rz[0] <= 0xec)) {
322
6.86k
            break;
323
6.86k
        }
324
6.99k
    }
325
6.86k
    if (cnt == WOLFSSL_CURVE25519_BLINDING_RAND_CNT) {
326
1
        ret = RNG_FAILURE_E;
327
1
        goto cleanup;
328
1
    }
329
330
    /* Generate 253 random bits. */
331
6.86k
    ret = wc_RNG_GenerateBlock(rng, a, sizeof(a));
332
6.86k
    if (ret != 0)
333
88
        goto cleanup;
334
6.77k
    a[CURVE25519_KEYSIZE-1] &= 0x7f;
335
    /* k' = k ^ 2k ^ a */
336
6.77k
    n_a[0] = n[0] ^ (byte)(n[0] << 1) ^ a[0];
337
216k
    for (i = 1; i < CURVE25519_KEYSIZE; i++) {
338
210k
        byte b1, b2, b3;
339
210k
        b1 = n[i] ^ a[i];
340
210k
        b2 = (byte)(n[i] << 1) ^ a[i];
341
210k
        b3 = (n[i-1] >> 7) ^ a[i];
342
210k
        n_a[i] = b1 ^ b2 ^ b3;
343
210k
    }
344
    /* Scalar multiple blinded scalar with blinding value. */
345
6.77k
    ret = curve25519_blind(rp, n_a, a, p, rz);
346
347
6.93k
cleanup:
348
6.93k
    ForceZero(a, sizeof(a));
349
6.93k
    ForceZero(n_a, sizeof(n_a));
350
6.93k
    ForceZero(rz, sizeof(rz));
351
#ifdef WOLFSSL_CHECK_MEM_ZERO
352
    wc_MemZero_Check(rz, sizeof(rz));
353
    wc_MemZero_Check(n_a, sizeof(n_a));
354
    wc_MemZero_Check(a, sizeof(a));
355
#endif
356
357
6.93k
    RESTORE_VECTOR_REGISTERS();
358
359
6.93k
    return ret;
360
6.77k
}
361
362
/* Software half of curve25519_make_pub_blind_ex, so a caller that has already
363
 * offered the scalar to a device does not offer it a second time. */
364
static int curve25519_make_pub_blind_sw(int public_size, byte* pub,
365
    const byte* priv, WC_RNG* rng)
366
6.64k
{
367
6.64k
    int ret;
368
369
6.64k
    fe_init();
370
371
6.64k
    ret = curve25519_smul_blind(pub, priv, (const byte*)kCurve25519BasePoint,
372
6.64k
                                rng);
373
6.64k
    if (ret == 0) {
374
6.48k
        ret = wc_curve25519_check_public(pub, (word32)public_size,
375
6.48k
                                    EC25519_LITTLE_ENDIAN);
376
6.48k
    }
377
378
6.64k
    return ret;
379
6.64k
}
380
381
/* Software half of wc_curve25519_generic_blind; same reason. */
382
static int curve25519_generic_blind_sw(byte* pub, const byte* priv,
383
    const byte* basepoint, WC_RNG* rng)
384
0
{
385
0
    fe_init();
386
387
0
    return curve25519_smul_blind(pub, priv, basepoint, rng);
388
0
}
389
#endif /* !WOLF_CRYPTO_CB_ONLY_CURVE25519 */
390
#endif
391
392
/* Blinded form of curve25519_make_pub_ex; devId means the same. */
393
static int curve25519_make_pub_blind_ex(int public_size, byte* pub,
394
    int private_size, const byte* priv, WC_RNG* rng, int devId)
395
5.77k
{
396
5.77k
    int ret;
397
#if defined(FREESCALE_LTC_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_CURVE25519)
398
    const ECPoint* basepoint = nxp_ltc_curve25519_GetBasePoint();
399
    ECPoint wc_pub;
400
#endif
401
402
5.77k
    if ( (public_size != CURVE25519_KEYSIZE) ||
403
5.77k
        (private_size != CURVE25519_KEYSIZE)) {
404
0
        return ECC_BAD_ARG_E;
405
0
    }
406
5.77k
    if ((pub == NULL) || (priv == NULL)) {
407
0
        return ECC_BAD_ARG_E;
408
0
    }
409
5.77k
#ifndef FREESCALE_LTC_ECC
410
5.77k
    if (rng == NULL) {
411
0
        return ECC_BAD_ARG_E;
412
0
    }
413
5.77k
#endif
414
415
    /* check clamping */
416
5.77k
    ret = curve25519_priv_clamp_check(priv);
417
5.77k
    if (ret != 0)
418
0
        return ret;
419
420
5.77k
#ifdef WOLF_CRYPTO_CB
421
5.77k
    #ifndef WOLF_CRYPTO_CB_FIND
422
5.77k
    if (devId != INVALID_DEVID)
423
0
    #endif
424
0
    {
425
0
        ret = wc_CryptoCb_Curve25519MakePub(devId, public_size, pub,
426
0
            private_size, priv);
427
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
428
0
            return ret;
429
        /* fall-through when unavailable */
430
0
    }
431
#else
432
    (void)devId;
433
#endif
434
435
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519
436
    /* the LTC path checks the rng, the callback path has no use for it */
437
    (void)rng;
438
    return NO_VALID_DEVID;
439
#else
440
#ifdef FREESCALE_LTC_ECC
441
    /* input basepoint on Weierstrass curve */
442
    ret = nxp_ltc_curve25519(&wc_pub, priv, basepoint, kLTC_Weierstrass);
443
    if (ret == 0) {
444
        XMEMCPY(pub, wc_pub.point, CURVE25519_KEYSIZE);
445
    }
446
447
    if (ret == 0) {
448
        ret = wc_curve25519_check_public(pub, (word32)public_size,
449
                                    EC25519_LITTLE_ENDIAN);
450
    }
451
#else
452
5.77k
    ret = curve25519_make_pub_blind_sw(public_size, pub, priv, rng);
453
5.77k
#endif
454
455
5.77k
    return ret;
456
5.77k
#endif /* WOLF_CRYPTO_CB_ONLY_CURVE25519 */
457
5.77k
}
458
459
int wc_curve25519_make_pub_blind(int public_size, byte* pub, int private_size,
460
                                 const byte* priv, WC_RNG* rng)
461
0
{
462
0
#ifdef WOLF_CRYPTO_CB
463
    /* no key names a device, so offer the scalar to the build default one */
464
0
    const int devId = wc_CryptoCb_DefaultDevID();
465
#else
466
    const int devId = INVALID_DEVID;
467
#endif
468
469
0
    return curve25519_make_pub_blind_ex(public_size, pub, private_size, priv,
470
0
        rng, devId);
471
0
}
472
#endif
473
474
/* Derive a key's public point from its own private scalar.
475
 *
476
 * Only wc_curve25519_make_key() and the public key export use this, so the
477
 * guard below is the union of their two call-site conditions: the software
478
 * key generation must be compiled in and not replaced by the SE050 key
479
 * creation, or the public key export must be enabled.
480
 */
481
#if (!defined(WOLF_CRYPTO_CB_ONLY_CURVE25519) && \
482
     (!defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_ONLY_KEY_ID))) || \
483
    defined(HAVE_CURVE25519_KEY_EXPORT)
484
static int curve25519_key_make_pub(curve25519_key* key, WC_RNG* rng)
485
5.77k
{
486
5.77k
#ifdef WOLF_CRYPTO_CB
487
5.77k
    const int devId = key->devId;
488
#else
489
    const int devId = INVALID_DEVID;
490
#endif
491
492
5.77k
#ifdef WOLFSSL_CURVE25519_BLINDING
493
5.77k
    return curve25519_make_pub_blind_ex((int)sizeof(key->p.point), key->p.point,
494
5.77k
        (int)sizeof(key->k), key->k, rng, devId);
495
#else
496
    (void)rng;
497
    return curve25519_make_pub_ex((int)sizeof(key->p.point), key->p.point,
498
        (int)sizeof(key->k), key->k, devId);
499
#endif
500
5.77k
}
501
#endif /* (!WOLF_CRYPTO_CB_ONLY_CURVE25519 &&
502
        *  (!WOLFSSL_SE050 || WOLFSSL_SE050_ONLY_KEY_ID)) ||
503
        * HAVE_CURVE25519_KEY_EXPORT */
504
505
/* compute the public key from an existing private key, with supplied basepoint,
506
 * using bare vectors.
507
 *
508
 * return value is propagated from curve25519() (0 on success),
509
 * and the byte vectors are little endian.
510
 */
511
int wc_curve25519_generic(int public_size, byte* pub,
512
                          int private_size, const byte* priv,
513
                          int basepoint_size, const byte* basepoint)
514
0
{
515
#ifdef FREESCALE_LTC_ECC
516
    /* unsupported with NXP LTC, only supports single basepoint with
517
     * nxp_ltc_curve25519_GetBasePoint() */
518
    return WC_HW_E;
519
#else
520
0
    int ret;
521
522
0
    if ((public_size != CURVE25519_KEYSIZE) ||
523
0
        (private_size != CURVE25519_KEYSIZE) ||
524
0
        (basepoint_size != CURVE25519_KEYSIZE)) {
525
0
        return ECC_BAD_ARG_E;
526
0
    }
527
0
    if ((pub == NULL) || (priv == NULL) || (basepoint == NULL))
528
0
        return ECC_BAD_ARG_E;
529
530
    /* check clamping */
531
0
    ret = curve25519_priv_clamp_check(priv);
532
0
    if (ret != 0)
533
0
        return ret;
534
535
0
#ifdef WOLF_CRYPTO_CB
536
    /* no key names a device, so offer the scalar to the build default one */
537
0
    ret = wc_CryptoCb_Curve25519Generic(wc_CryptoCb_DefaultDevID(), public_size,
538
0
        pub, private_size, priv, basepoint_size, basepoint);
539
0
    if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
540
0
        return ret;
541
    /* fall-through when unavailable */
542
0
#endif
543
544
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519
545
    return NO_VALID_DEVID;
546
#elif !defined(WOLFSSL_CURVE25519_BLINDING)
547
    fe_init();
548
549
    SAVE_VECTOR_REGISTERS(return _svr_ret;);
550
551
    ret = curve25519(pub, priv, basepoint);
552
553
    RESTORE_VECTOR_REGISTERS();
554
555
    return ret;
556
#else
557
0
    {
558
0
        WC_RNG rng;
559
560
0
        ret = wc_InitRng(&rng);
561
0
        if (ret == 0) {
562
0
            ret = curve25519_generic_blind_sw(pub, priv, basepoint, &rng);
563
564
0
            wc_FreeRng(&rng);
565
0
        }
566
0
    }
567
568
0
    return ret;
569
0
#endif
570
0
#endif /* FREESCALE_LTC_ECC */
571
0
}
572
573
#ifdef WOLFSSL_CURVE25519_BLINDING
574
/* compute the public key from an existing private key, with supplied basepoint,
575
 * using bare vectors.
576
 *
577
 * return value is propagated from curve25519() (0 on success),
578
 * and the byte vectors are little endian.
579
 */
580
int wc_curve25519_generic_blind(int public_size, byte* pub,
581
                                int private_size, const byte* priv,
582
                                int basepoint_size, const byte* basepoint,
583
                                WC_RNG* rng)
584
0
{
585
#ifdef FREESCALE_LTC_ECC
586
    /* unsupported with NXP LTC, only supports single basepoint with
587
     * nxp_ltc_curve25519_GetBasePoint() */
588
    return WC_HW_E;
589
#else
590
0
    int ret;
591
592
0
    if ((public_size != CURVE25519_KEYSIZE) ||
593
0
        (private_size != CURVE25519_KEYSIZE) ||
594
0
        (basepoint_size != CURVE25519_KEYSIZE)) {
595
0
        return ECC_BAD_ARG_E;
596
0
    }
597
0
    if ((pub == NULL) || (priv == NULL) || (basepoint == NULL))
598
0
        return ECC_BAD_ARG_E;
599
0
    if (rng == NULL) {
600
0
        return ECC_BAD_ARG_E;
601
0
    }
602
603
    /* check clamping */
604
0
    ret = curve25519_priv_clamp_check(priv);
605
0
    if (ret != 0)
606
0
        return ret;
607
608
0
#ifdef WOLF_CRYPTO_CB
609
    /* no key names a device, so offer the scalar to the build default one */
610
0
    ret = wc_CryptoCb_Curve25519Generic(wc_CryptoCb_DefaultDevID(), public_size,
611
0
        pub, private_size, priv, basepoint_size, basepoint);
612
0
    if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
613
0
        return ret;
614
    /* fall-through when unavailable */
615
0
#endif
616
617
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519
618
    return NO_VALID_DEVID;
619
#else
620
0
    return curve25519_generic_blind_sw(pub, priv, basepoint, rng);
621
0
#endif /* WOLF_CRYPTO_CB_ONLY_CURVE25519 */
622
0
#endif /* FREESCALE_LTC_ECC */
623
0
}
624
#endif
625
626
/* generate a new private key, as a bare vector.
627
 *
628
 * return value is propagated from wc_RNG_GenerateBlock(() (0 on success),
629
 * or BAD_FUNC_ARG/ECC_BAD_ARG_E, and the byte vector is little endian.
630
 */
631
int wc_curve25519_make_priv(WC_RNG* rng, int keysize, byte* key)
632
6.00k
{
633
6.00k
    int ret;
634
635
6.00k
    if (key == NULL || rng == NULL)
636
0
        return BAD_FUNC_ARG;
637
638
    /* currently only a key size of 32 bytes is used */
639
6.00k
    if (keysize != CURVE25519_KEYSIZE)
640
0
        return ECC_BAD_ARG_E;
641
642
    /* random number for private key */
643
6.00k
    ret = wc_RNG_GenerateBlock(rng, key, (word32)keysize);
644
6.00k
    if (ret == 0) {
645
        /* Clamp the private key */
646
5.77k
        ret = curve25519_priv_clamp(key);
647
5.77k
    }
648
649
6.00k
    return ret;
650
6.00k
}
651
652
#ifdef WC_X25519_NONBLOCK
653
654
static int wc_curve25519_make_pub_nb(curve25519_key* key)
655
{
656
    int ret = 0;
657
658
    if (key == NULL) {
659
        ret = BAD_FUNC_ARG;
660
    }
661
    else if (key->nb_ctx == NULL) {
662
        WOLFSSL_MSG("wc_curve25519_make_pub_nb called with NULL non-blocking "
663
            "context.");
664
        ret = BAD_FUNC_ARG;
665
    }
666
667
    if (ret == 0 && key->nb_ctx->state == 0) {
668
        /* check clamping */
669
        ret = curve25519_priv_clamp_check(key->k);
670
        if (ret == 0) {
671
            fe_init();
672
        }
673
    }
674
    if (ret == 0) {
675
        ret = curve25519_nb(key->p.point, key->k, (byte*)kCurve25519BasePoint,
676
                  key->nb_ctx);
677
    }
678
679
    return ret;
680
}
681
682
static int wc_curve25519_make_key_nb(WC_RNG* rng, int keysize,
683
    curve25519_key* key)
684
{
685
    int ret = 0;
686
687
    if (key == NULL || rng == NULL) {
688
        ret = BAD_FUNC_ARG;
689
    }
690
    else if (key->nb_ctx == NULL) {
691
        WOLFSSL_MSG("wc_curve25519_make_key_nb called with NULL non-blocking "
692
            "context.");
693
        ret = BAD_FUNC_ARG;
694
    }
695
696
    if (ret == 0 && key->nb_ctx->state == 0) {
697
        ret = wc_curve25519_make_priv(rng, keysize, key->k);
698
        if (ret == 0) {
699
            key->privSet = 1;
700
        }
701
    }
702
    if (ret == 0) {
703
        ret = wc_curve25519_make_pub_nb(key);
704
        if (ret == 0)  {
705
            key->pubSet = 1;
706
        }
707
    }
708
709
    return ret;
710
}
711
712
int wc_curve25519_set_nonblock(curve25519_key* key, x25519_nb_ctx_t* ctx)
713
{
714
    if (key == NULL) {
715
        return BAD_FUNC_ARG;
716
    }
717
    /* If a different context is already set, clear it before replacing.
718
     * The caller is responsible for freeing any heap-allocated context. */
719
    if (key->nb_ctx != NULL && key->nb_ctx != ctx) {
720
        XMEMSET(key->nb_ctx, 0, sizeof(x25519_nb_ctx_t));
721
    }
722
    if (ctx != NULL) {
723
        XMEMSET(ctx, 0, sizeof(x25519_nb_ctx_t));
724
    }
725
    key->nb_ctx = ctx;
726
    return 0;
727
}
728
729
#endif /* WC_X25519_NONBLOCK */
730
731
/* generate a new keypair.
732
 *
733
 * return value is propagated from wc_curve25519_make_private() or
734
 * wc_curve25519_make_pub() (0 on success).
735
 */
736
int wc_curve25519_make_key(WC_RNG* rng, int keysize, curve25519_key* key)
737
6.00k
{
738
6.00k
    int ret;
739
740
6.00k
    if (key == NULL || rng == NULL)
741
0
        return BAD_FUNC_ARG;
742
743
6.00k
#ifdef WOLF_CRYPTO_CB
744
6.00k
    #ifndef WOLF_CRYPTO_CB_FIND
745
6.00k
    if (key->devId != INVALID_DEVID)
746
0
    #endif
747
0
    {
748
0
        ret = wc_CryptoCb_Curve25519Gen(rng, keysize, key);
749
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
750
0
            return ret;
751
        /* fall-through when unavailable */
752
0
    }
753
6.00k
#endif
754
755
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519
756
    /* software path stripped; callback is the only provider */
757
    return NO_VALID_DEVID;
758
#else
759
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_X25519) && \
760
    defined(WOLFSSL_ASYNC_CRYPT_SW)
761
    if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_X25519) {
762
        if (wc_AsyncSwInit(&key->asyncDev, ASYNC_SW_X25519_MAKE)) {
763
            WC_ASYNC_SW* sw = &key->asyncDev.sw;
764
            sw->x25519Make.rng = rng;
765
            sw->x25519Make.size = keysize;
766
            sw->x25519Make.key = key;
767
            return WC_PENDING_E;
768
        }
769
    }
770
#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_X25519 &&
771
        * WOLFSSL_ASYNC_CRYPT_SW */
772
773
#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID)
774
    ret = se050_curve25519_create_key(key, keysize);
775
#elif defined(WC_X25519_NONBLOCK)
776
    if (key->nb_ctx != NULL) {
777
        ret = wc_curve25519_make_key_nb(rng, keysize, key);
778
    }
779
    else
780
#endif
781
    /* Under WOLFSSL_SE050_ONLY_KEY_ID, generate a software key (keyIdSet == 0);
782
     * its shared-secret computation routes through software (privSet == 1). */
783
6.00k
#if !defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_ONLY_KEY_ID)
784
6.00k
    {
785
6.00k
        ret = wc_curve25519_make_priv(rng, keysize, key->k);
786
6.00k
        if (ret == 0) {
787
5.77k
            key->privSet = 1;
788
5.77k
            ret = curve25519_key_make_pub(key, rng);
789
5.77k
#ifdef WOLFSSL_CURVE25519_BLINDING
790
5.77k
            if (ret == 0) {
791
5.60k
                ret = wc_curve25519_set_rng(key, rng);
792
5.60k
            }
793
5.77k
#endif
794
5.77k
            key->pubSet = (ret == 0);
795
5.77k
        }
796
6.00k
    }
797
6.00k
#endif /* !WOLFSSL_SE050 */
798
799
6.00k
    return ret;
800
6.00k
#endif /* WOLF_CRYPTO_CB_ONLY_CURVE25519 */
801
6.00k
}
802
803
#ifdef HAVE_CURVE25519_SHARED_SECRET
804
805
int wc_curve25519_shared_secret(curve25519_key* private_key,
806
                                curve25519_key* public_key,
807
                                byte* out, word32* outlen)
808
0
{
809
0
    return wc_curve25519_shared_secret_ex(private_key, public_key,
810
0
                                          out, outlen, EC25519_BIG_ENDIAN);
811
0
}
812
813
#ifdef WC_X25519_NONBLOCK
814
815
static int wc_curve25519_shared_secret_nb(curve25519_key* privKey,
816
    curve25519_key* pubKey, byte* out, word32* outlen, int endian)
817
{
818
    int ret = FP_WOULDBLOCK;
819
820
    switch (privKey->nb_ctx->ssState) {
821
        case 0:
822
            privKey->nb_ctx->ssState = 1;
823
            break;
824
        case 1:
825
            /* Write the result directly into the caller's 'out' buffer.
826
             * curve25519_nb() zeroes the non-blocking context on completion,
827
             * so any output buffer that lives inside nb_ctx (e.g.
828
             * nb_ctx->o.point) would be clobbered to zero before we could
829
             * read it. The output is little-endian; case 2 handles the
830
             * optional byte-reversal for EC25519_BIG_ENDIAN. */
831
            ret = curve25519_nb(out, privKey->k, pubKey->p.point,
832
                      privKey->nb_ctx);
833
            if (ret == 0) {
834
                ret = FP_WOULDBLOCK;
835
                privKey->nb_ctx->ssState = 2;
836
            }
837
            break;
838
        case 2:
839
        #ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK
840
            {
841
                int i;
842
                byte t = 0;
843
844
                for (i = 0; i < CURVE25519_KEYSIZE; i++) {
845
                    t |= out[i];
846
                }
847
                if (t == 0) {
848
                    ForceZero(out, CURVE25519_KEYSIZE);
849
                    ret = ECC_OUT_OF_RANGE_E;
850
                    break;
851
                }
852
            }
853
        #endif /* !WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK */
854
            if (endian == EC25519_BIG_ENDIAN) {
855
                /* Reverse the little-endian result in place. */
856
                int i;
857
                byte tmp;
858
                for (i = 0; i < CURVE25519_KEYSIZE / 2; i++) {
859
                    tmp = out[i];
860
                    out[i] = out[CURVE25519_KEYSIZE - 1 - i];
861
                    out[CURVE25519_KEYSIZE - 1 - i] = tmp;
862
                }
863
            }
864
            *outlen = CURVE25519_KEYSIZE;
865
            ret = 0;
866
            break;
867
    }
868
869
    if (ret != FP_WOULDBLOCK) {
870
        XMEMSET(privKey->nb_ctx, 0, sizeof(x25519_nb_ctx_t));
871
    }
872
873
    return ret;
874
}
875
876
#endif /* WC_X25519_NONBLOCK */
877
878
int wc_curve25519_shared_secret_ex(curve25519_key* private_key,
879
                                   curve25519_key* public_key,
880
                                   byte* out, word32* outlen, int endian)
881
292
{
882
292
    int ret = 0;
883
884
    /* sanity check */
885
292
    if (private_key == NULL || public_key == NULL ||
886
292
        out == NULL || outlen == NULL || *outlen < CURVE25519_KEYSIZE) {
887
0
        return BAD_FUNC_ARG;
888
0
    }
889
890
    /* make sure we have a populated private and public key */
891
292
    if (!public_key->pubSet
892
292
    #ifndef WOLFSSL_SE050
893
292
        || !private_key->privSet
894
292
    #endif
895
292
    ) {
896
0
        return ECC_BAD_ARG_E;
897
0
    }
898
899
#ifdef WOLFSSL_X25519_NO_MASK_PEER
900
    /* avoid implementation fingerprinting - make sure signed bit is not set */
901
    if (public_key->p.point[CURVE25519_KEYSIZE-1] & 0x80) {
902
        return ECC_BAD_ARG_E;
903
    }
904
#endif
905
906
292
#ifdef WOLF_CRYPTO_CB
907
292
    #ifndef WOLF_CRYPTO_CB_FIND
908
292
    if (private_key->devId != INVALID_DEVID)
909
0
    #endif
910
0
    {
911
0
        ret = wc_CryptoCb_Curve25519(private_key, public_key, out, outlen,
912
0
            endian);
913
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
914
0
            return ret;
915
        /* fall-through when unavailable */
916
0
    }
917
292
#endif
918
919
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519
920
    /* software path stripped; callback is the only provider */
921
    return NO_VALID_DEVID;
922
#else
923
#ifdef WC_X25519_NONBLOCK
924
925
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_X25519) && \
926
    defined(WOLFSSL_ASYNC_CRYPT_SW)
927
    if (private_key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_X25519) {
928
        if (wc_AsyncSwInit(&private_key->asyncDev,
929
                ASYNC_SW_X25519_SHARED_SEC)) {
930
            WC_ASYNC_SW* sw = &private_key->asyncDev.sw;
931
            sw->x25519SharedSec.priv = private_key;
932
            sw->x25519SharedSec.pub = public_key;
933
            sw->x25519SharedSec.out = out;
934
            sw->x25519SharedSec.outLen = outlen;
935
            sw->x25519SharedSec.endian = endian;
936
            return WC_PENDING_E;
937
        }
938
    }
939
#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_X25519 &&
940
        * WOLFSSL_ASYNC_CRYPT_SW */
941
942
    if (private_key->nb_ctx != NULL) {
943
        ret = wc_curve25519_shared_secret_nb(private_key, public_key, out,
944
                  outlen, endian);
945
    }
946
    else
947
#endif /* WC_X25519_NONBLOCK */
948
292
    {
949
292
        ECPoint o;
950
951
292
        XMEMSET(&o, 0, sizeof(o));
952
953
#ifdef FREESCALE_LTC_ECC
954
        /* input point P on Curve25519 */
955
        ret = nxp_ltc_curve25519(&o, private_key->k, &public_key->p,
956
            kLTC_Curve25519);
957
#else
958
    #ifdef WOLFSSL_SE050
959
        if (!private_key->privSet) {
960
            /* use NXP SE050: "privSet" is not set */
961
            ret = se050_curve25519_shared_secret(private_key, public_key, &o);
962
        }
963
        else
964
    #endif /* WOLFSSL_SE050 */
965
292
        {
966
        #ifdef WOLFSSL_X25519_NO_MASK_PEER
967
            byte* pubVal = public_key->p.point;
968
        #else
969
292
            byte pubVal[CURVE25519_KEYSIZE];
970
971
292
            XMEMCPY(pubVal, public_key->p.point, CURVE25519_KEYSIZE);
972
292
            pubVal[CURVE25519_KEYSIZE-1] &= 0x7f;
973
292
        #endif
974
975
#ifndef WOLFSSL_CURVE25519_BLINDING
976
            SAVE_VECTOR_REGISTERS(return _svr_ret;);
977
978
            ret = curve25519(o.point, private_key->k, pubVal);
979
980
            RESTORE_VECTOR_REGISTERS();
981
#else
982
292
            ret = curve25519_smul_blind(o.point, private_key->k, pubVal,
983
292
                      private_key->rng);
984
292
#endif
985
292
        }
986
292
#endif /* FREESCALE_LTC_ECC */
987
#ifdef WOLFSSL_CHECK_MEM_ZERO
988
        /* Past the SAVE_VECTOR_REGISTERS early-return: o now holds the shared
989
         * secret and every remaining path reaches the ForceZero below. */
990
        wc_MemZero_Add("wc_curve25519_shared_secret_ex o", &o, sizeof(o));
991
#endif
992
292
#ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK
993
292
        if (ret == 0) {
994
292
            int i;
995
292
            byte t = 0;
996
9.63k
            for (i = 0; i < CURVE25519_KEYSIZE; i++) {
997
9.34k
                t |= o.point[i];
998
9.34k
            }
999
292
            if (t == 0) {
1000
0
                ret = ECC_OUT_OF_RANGE_E;
1001
0
            }
1002
292
        }
1003
292
#endif /* !WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK */
1004
292
        if (ret == 0) {
1005
292
            curve25519_copy_point(out, o.point, endian);
1006
292
            *outlen = CURVE25519_KEYSIZE;
1007
292
        }
1008
1009
292
        ForceZero(&o, sizeof(o));
1010
#ifdef WOLFSSL_CHECK_MEM_ZERO
1011
        wc_MemZero_Check(&o, sizeof(o));
1012
#endif
1013
292
    }
1014
1015
292
    return ret;
1016
292
#endif /* WOLF_CRYPTO_CB_ONLY_CURVE25519 */
1017
292
}
1018
1019
#endif /* HAVE_CURVE25519_SHARED_SECRET */
1020
1021
#ifdef HAVE_CURVE25519_KEY_EXPORT
1022
1023
/* export curve25519 public key (Big endian)
1024
 * return 0 on success */
1025
int wc_curve25519_export_public(curve25519_key* key, byte* out, word32* outLen)
1026
1
{
1027
1
    return wc_curve25519_export_public_ex(key, out, outLen, EC25519_BIG_ENDIAN);
1028
1
}
1029
1030
/* export curve25519 public key (Big or Little endian)
1031
 * return 0 on success */
1032
int wc_curve25519_export_public_ex(curve25519_key* key, byte* out,
1033
                                   word32* outLen, int endian)
1034
5.20k
{
1035
5.20k
    int ret = 0;
1036
1037
5.20k
    if (key == NULL || out == NULL || outLen == NULL) {
1038
67
        return BAD_FUNC_ARG;
1039
67
    }
1040
1041
    /* check and set outgoing key size */
1042
5.13k
    if (*outLen < CURVE25519_KEYSIZE) {
1043
13
        *outLen = CURVE25519_KEYSIZE;
1044
13
        return ECC_BAD_ARG_E;
1045
13
    }
1046
1047
    /* calculate public if missing */
1048
5.12k
    if (!key->pubSet) {
1049
0
#ifdef WOLFSSL_CURVE25519_BLINDING
1050
0
        ret = curve25519_key_make_pub(key, key->rng);
1051
#else
1052
        ret = curve25519_key_make_pub(key, NULL);
1053
#endif
1054
0
        key->pubSet = (ret == 0);
1055
0
    }
1056
    /* export public point with endianness */
1057
5.12k
    curve25519_copy_point(out, key->p.point, endian);
1058
5.12k
    *outLen = CURVE25519_KEYSIZE;
1059
1060
5.12k
    return ret;
1061
5.13k
}
1062
1063
#endif /* HAVE_CURVE25519_KEY_EXPORT */
1064
1065
#ifdef HAVE_CURVE25519_KEY_IMPORT
1066
1067
/* import curve25519 public key (Big endian)
1068
 *  return 0 on success */
1069
int wc_curve25519_import_public(const byte* in, word32 inLen,
1070
                                curve25519_key* key)
1071
22
{
1072
22
    return wc_curve25519_import_public_ex(in, inLen, key, EC25519_BIG_ENDIAN);
1073
22
}
1074
1075
/* import curve25519 public key (Big or Little endian)
1076
 * return 0 on success */
1077
int wc_curve25519_import_public_ex(const byte* in, word32 inLen,
1078
                                curve25519_key* key, int endian)
1079
331
{
1080
#ifdef FREESCALE_LTC_ECC
1081
    ltc_pkha_ecc_point_t ltcPoint;
1082
#endif
1083
1084
    /* sanity check */
1085
331
    if (key == NULL || in == NULL) {
1086
1
        return BAD_FUNC_ARG;
1087
1
    }
1088
1089
    /* check size of incoming keys */
1090
330
    if (inLen != CURVE25519_KEYSIZE) {
1091
21
       return ECC_BAD_ARG_E;
1092
21
    }
1093
1094
    /* import public point with endianness */
1095
309
    curve25519_copy_point(key->p.point, in, endian);
1096
309
    key->pubSet = 1;
1097
1098
309
    key->dp = &curve25519_sets[0];
1099
1100
    /* LTC needs also Y coordinate - let's compute it */
1101
#ifdef FREESCALE_LTC_ECC
1102
    ltcPoint.X = &key->p.point[0];
1103
    ltcPoint.Y = &key->p.pointY[0];
1104
    LTC_PKHA_Curve25519ComputeY(&ltcPoint);
1105
#endif
1106
1107
309
    return 0;
1108
330
}
1109
1110
/* Check the public key value (big or little endian)
1111
 *
1112
 * pub     Public key bytes.
1113
 * pubSz   Size of public key in bytes.
1114
 * endian  Public key bytes passed in as big-endian or little-endian.
1115
 * returns BAD_FUNC_ARGS when pub is NULL,
1116
 *         BUFFER_E when size of public key is zero;
1117
 *         ECC_OUT_OF_RANGE_E if the high bit is set;
1118
 *         ECC_BAD_ARG_E if key length is not 32 bytes, or the public key
1119
 *         value is a cheaply detectable low-order point: 0, 1, p-1 (u = -1)
1120
 *         or the non-canonical encodings p and p+1 (p = 2^255-19); and
1121
 *         0 otherwise.
1122
 *
1123
 * RFC 7748 Section 5 requires the non-canonical range [p, 2^255-1] to be
1124
 * accepted and processed as if reduced modulo p, so p+2 .. p+18 are valid
1125
 * inputs (the field arithmetic performs the reduction) and are not rejected
1126
 * here.
1127
 */
1128
int wc_curve25519_check_public(const byte* pub, word32 pubSz, int endian)
1129
7.68k
{
1130
7.68k
    word32 i;
1131
1132
7.68k
    if (pub == NULL)
1133
0
        return BAD_FUNC_ARG;
1134
1135
    /* Check for empty key data */
1136
7.68k
    if (pubSz == 0)
1137
6
        return BUFFER_E;
1138
1139
    /* Check key length */
1140
7.68k
    if (pubSz != CURVE25519_KEYSIZE)
1141
77
        return ECC_BAD_ARG_E;
1142
1143
1144
7.60k
    if (endian == EC25519_LITTLE_ENDIAN) {
1145
        /* Check for value of zero or one */
1146
9.18k
        for (i = CURVE25519_KEYSIZE - 1; i > 0; i--) {
1147
9.13k
            if (pub[i] != 0)
1148
7.48k
                break;
1149
9.13k
        }
1150
7.52k
        if (i == 0 && (pub[0] == 0 || pub[0] == 1))
1151
31
            return ECC_BAD_ARG_E;
1152
1153
        /* Check high bit set */
1154
7.49k
        if (pub[CURVE25519_KEYSIZE - 1] & 0x80)
1155
20
            return ECC_OUT_OF_RANGE_E;
1156
1157
        /* Check for p-1, p or p+1: 0x7fff..ffec, 0x7fff..ffed, 0x7fff..ffee.
1158
         * p-1 is the low-order point u = -1; p and p+1 reduce to 0 and 1.
1159
         * Larger values (p+2 .. p+18) are non-canonical encodings of 2 .. 18
1160
         * and must be accepted (RFC 7748 Section 5). */
1161
7.47k
        if (pub[CURVE25519_KEYSIZE - 1] == 0x7f) {
1162
1.17k
            for (i = CURVE25519_KEYSIZE - 2; i > 0; i--) {
1163
1.15k
                if (pub[i] != 0xff)
1164
241
                    break;
1165
1.15k
            }
1166
263
            if (i == 0 && (pub[0] >= 0xec) && (pub[0] <= 0xee))
1167
3
                return ECC_BAD_ARG_E;
1168
263
        }
1169
7.47k
    }
1170
79
    else {
1171
        /* Check for value of zero or one */
1172
477
        for (i = 0; i < CURVE25519_KEYSIZE - 1; i++) {
1173
467
            if (pub[i] != 0)
1174
69
                break;
1175
467
        }
1176
79
        if (i == CURVE25519_KEYSIZE - 1 && (pub[i] == 0 || pub[i] == 1))
1177
2
            return ECC_BAD_ARG_E;
1178
1179
        /* Check high bit set */
1180
77
        if (pub[0] & 0x80)
1181
18
            return ECC_OUT_OF_RANGE_E;
1182
1183
        /* Check for p-1, p or p+1 (see little-endian case above). */
1184
59
        if (pub[0] == 0x7f) {
1185
551
            for (i = 1; i < CURVE25519_KEYSIZE - 1; i++) {
1186
538
                if (pub[i] != 0xff)
1187
14
                    break;
1188
538
            }
1189
27
            if (i == CURVE25519_KEYSIZE - 1 && (pub[i] >= 0xec) &&
1190
3
                    (pub[i] <= 0xee))
1191
1
                return ECC_BAD_ARG_E;
1192
27
        }
1193
59
    }
1194
1195
7.53k
    return 0;
1196
7.60k
}
1197
1198
#endif /* HAVE_CURVE25519_KEY_IMPORT */
1199
1200
1201
#ifdef HAVE_CURVE25519_KEY_EXPORT
1202
1203
/* export curve25519 private key only raw (Big endian)
1204
 * outLen is in/out size
1205
 * return 0 on success */
1206
int wc_curve25519_export_private_raw(curve25519_key* key, byte* out,
1207
                                     word32* outLen)
1208
0
{
1209
0
    return wc_curve25519_export_private_raw_ex(key, out, outLen,
1210
0
                                               EC25519_BIG_ENDIAN);
1211
0
}
1212
1213
/* export curve25519 private key only raw (Big or Little endian)
1214
 * outLen is in/out size
1215
 * return 0 on success */
1216
int wc_curve25519_export_private_raw_ex(curve25519_key* key, byte* out,
1217
                                        word32* outLen, int endian)
1218
648
{
1219
    /* sanity check */
1220
648
    if (key == NULL || out == NULL || outLen == NULL)
1221
270
        return BAD_FUNC_ARG;
1222
1223
378
    if (!key->privSet)
1224
0
        return ECC_BAD_ARG_E;
1225
1226
    /* check size of outgoing buffer */
1227
378
    if (*outLen < CURVE25519_KEYSIZE) {
1228
31
        *outLen = CURVE25519_KEYSIZE;
1229
31
        return ECC_BAD_ARG_E;
1230
31
    }
1231
1232
    /* export private scalar with endianness */
1233
347
    curve25519_copy_point(out, key->k, endian);
1234
347
    *outLen = CURVE25519_KEYSIZE;
1235
1236
347
    return 0;
1237
378
}
1238
1239
/* curve25519 key pair export (Big or Little endian)
1240
 * return 0 on success */
1241
int wc_curve25519_export_key_raw(curve25519_key* key,
1242
                                 byte* priv, word32 *privSz,
1243
                                 byte* pub, word32 *pubSz)
1244
0
{
1245
0
    return wc_curve25519_export_key_raw_ex(key, priv, privSz,
1246
0
                                           pub, pubSz, EC25519_BIG_ENDIAN);
1247
0
}
1248
1249
/* curve25519 key pair export (Big or Little endian)
1250
 * return 0 on success */
1251
int wc_curve25519_export_key_raw_ex(curve25519_key* key,
1252
                                    byte* priv, word32 *privSz,
1253
                                    byte* pub, word32 *pubSz,
1254
                                    int endian)
1255
0
{
1256
0
    int ret;
1257
1258
    /* export private part */
1259
0
    ret = wc_curve25519_export_private_raw_ex(key, priv, privSz, endian);
1260
0
    if (ret != 0)
1261
0
        return ret;
1262
1263
    /* export public part */
1264
0
    return wc_curve25519_export_public_ex(key, pub, pubSz, endian);
1265
0
}
1266
1267
#endif /* HAVE_CURVE25519_KEY_EXPORT */
1268
1269
#ifdef HAVE_CURVE25519_KEY_IMPORT
1270
1271
/* curve25519 private key import (Big endian)
1272
 * Public key to match private key needs to be imported too
1273
 * return 0 on success */
1274
int wc_curve25519_import_private_raw(const byte* priv, word32 privSz,
1275
                                     const byte* pub, word32 pubSz,
1276
                                     curve25519_key* key)
1277
12
{
1278
12
    return wc_curve25519_import_private_raw_ex(priv, privSz, pub, pubSz,
1279
12
                                               key, EC25519_BIG_ENDIAN);
1280
12
}
1281
1282
/* curve25519 private key import (Big or Little endian)
1283
 * Public key to match private key needs to be imported too
1284
 * return 0 on success */
1285
int wc_curve25519_import_private_raw_ex(const byte* priv, word32 privSz,
1286
                                        const byte* pub, word32 pubSz,
1287
                                        curve25519_key* key, int endian)
1288
12
{
1289
12
    int ret;
1290
1291
    /* import private part */
1292
12
    ret = wc_curve25519_import_private_ex(priv, privSz, key, endian);
1293
12
    if (ret != 0)
1294
11
        return ret;
1295
1296
    /* import public part */
1297
1
    return wc_curve25519_import_public_ex(pub, pubSz, key, endian);
1298
12
}
1299
1300
/* curve25519 private key import only. (Big endian)
1301
 * return 0 on success */
1302
int wc_curve25519_import_private(const byte* priv, word32 privSz,
1303
                                 curve25519_key* key)
1304
0
{
1305
0
    return wc_curve25519_import_private_ex(priv, privSz,
1306
0
                                           key, EC25519_BIG_ENDIAN);
1307
0
}
1308
1309
/* curve25519 private key import only. (Big or Little endian)
1310
 * return 0 on success */
1311
int wc_curve25519_import_private_ex(const byte* priv, word32 privSz,
1312
                                    curve25519_key* key, int endian)
1313
12
{
1314
    /* sanity check */
1315
12
    if (key == NULL || priv == NULL) {
1316
0
        return BAD_FUNC_ARG;
1317
0
    }
1318
1319
    /* check size of incoming keys */
1320
12
    if ((int)privSz != CURVE25519_KEYSIZE) {
1321
11
        return ECC_BAD_ARG_E;
1322
11
    }
1323
1324
#ifdef WOLFSSL_SE050
1325
#ifdef WOLFSSL_SE050_AUTO_ERASE
1326
    wc_se050_erase_object(key->keyId);
1327
#endif
1328
    /* release NXP resources if set */
1329
    se050_curve25519_free_key(key);
1330
#endif
1331
1332
    /* import private scalar with endianness */
1333
1
    curve25519_copy_point(key->k, priv, endian);
1334
1
    key->privSet = 1;
1335
1336
1
    key->dp = &curve25519_sets[0];
1337
1338
    /* Clamp the key */
1339
1
    return curve25519_priv_clamp(key->k);
1340
12
}
1341
1342
#endif /* HAVE_CURVE25519_KEY_IMPORT */
1343
1344
#ifndef WC_NO_CONSTRUCTORS
1345
curve25519_key* wc_curve25519_new(void* heap, int devId, int *result_code)
1346
0
{
1347
0
    int ret;
1348
0
    curve25519_key* key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), heap,
1349
0
                           DYNAMIC_TYPE_CURVE25519);
1350
0
    if (key == NULL) {
1351
0
        ret = MEMORY_E;
1352
0
    }
1353
0
    else {
1354
0
        ret = wc_curve25519_init_ex(key, heap, devId);
1355
0
        if (ret != 0) {
1356
0
            XFREE(key, heap, DYNAMIC_TYPE_CURVE25519);
1357
0
            key = NULL;
1358
0
        }
1359
0
    }
1360
1361
0
    if (result_code != NULL)
1362
0
        *result_code = ret;
1363
1364
0
    return key;
1365
0
}
1366
1367
0
int wc_curve25519_delete(curve25519_key* key, curve25519_key** key_p) {
1368
0
    void* heap;
1369
0
    if (key == NULL)
1370
0
        return BAD_FUNC_ARG;
1371
0
    heap = key->heap;
1372
0
    wc_curve25519_free(key);
1373
0
    XFREE(key, heap, DYNAMIC_TYPE_CURVE25519);
1374
0
    if (key_p != NULL)
1375
0
        *key_p = NULL;
1376
0
    return 0;
1377
0
}
1378
#endif /* !WC_NO_CONSTRUCTORS */
1379
1380
int wc_curve25519_init_ex(curve25519_key* key, void* heap, int devId)
1381
6.37k
{
1382
6.37k
    int ret = 0;
1383
1384
6.37k
    if (key == NULL) {
1385
0
       ret = BAD_FUNC_ARG;
1386
0
    }
1387
6.37k
#ifdef WC_CTX_IS_ALIGNED
1388
6.37k
    else if (!WC_CTX_IS_ALIGNED(key, curve25519_key)) {
1389
0
        ret = BAD_ALIGN_E;
1390
0
    }
1391
6.37k
#endif
1392
6.37k
    else {
1393
6.37k
        XMEMSET(key, 0, sizeof(*key));
1394
1395
        /* currently the format for curve25519 */
1396
6.37k
        key->dp = &curve25519_sets[0];
1397
1398
6.37k
    #ifdef WOLF_CRYPTO_CB
1399
6.37k
        key->devId = devId;
1400
    #else
1401
        (void)devId;
1402
    #endif
1403
6.37k
        (void)heap; /* if needed for XMALLOC/XFREE in future */
1404
1405
    /* field math is implemented in the callback in crypto cb only */
1406
6.37k
    #if !defined(FREESCALE_LTC_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_CURVE25519)
1407
6.37k
        fe_init();
1408
6.37k
    #endif
1409
1410
    #ifdef WOLFSSL_CHECK_MEM_ZERO
1411
        wc_MemZero_Add("wc_curve25519_init_ex key->k", key->k,
1412
            CURVE25519_KEYSIZE);
1413
    #endif
1414
1415
    #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_X25519)
1416
        ret = wolfAsync_DevCtxInit(&key->asyncDev, WOLFSSL_ASYNC_MARKER_X25519,
1417
                  heap, devId);
1418
    #endif
1419
6.37k
    }
1420
1421
6.37k
    return ret;
1422
6.37k
}
1423
1424
int wc_curve25519_init(curve25519_key* key)
1425
1.15k
{
1426
1.15k
    return wc_curve25519_init_ex(key, NULL, INVALID_DEVID);
1427
1.15k
}
1428
1429
/* Clean the memory of a key */
1430
void wc_curve25519_free(curve25519_key* key)
1431
11.9k
{
1432
11.9k
    if (key == NULL)
1433
5.54k
       return;
1434
6.37k
#ifdef WC_CTX_IS_ALIGNED
1435
6.37k
    if (!WC_CTX_IS_ALIGNED(key, curve25519_key)) {
1436
0
        ForceZero(key, sizeof(*key));
1437
0
        return;
1438
0
    }
1439
6.37k
#endif
1440
1441
#ifdef WOLFSSL_SE050
1442
    se050_curve25519_free_key(key);
1443
#endif
1444
1445
6.37k
    ForceZero(key, sizeof(*key));
1446
1447
#ifdef WOLFSSL_CHECK_MEM_ZERO
1448
    wc_MemZero_Check(key, sizeof(curve25519_key));
1449
#endif
1450
6.37k
}
1451
1452
#ifdef WOLFSSL_CURVE25519_BLINDING
1453
int wc_curve25519_set_rng(curve25519_key* key, WC_RNG* rng)
1454
5.89k
{
1455
5.89k
    if (key == NULL)
1456
0
        return BAD_FUNC_ARG;
1457
5.89k
    key->rng = rng;
1458
5.89k
    return 0;
1459
5.89k
}
1460
1461
/* Companion to wc_curve25519_set_rng(): detach the key's RNG association.
1462
 * Subsequent blinded operations then fail in the RNG service (BAD_FUNC_ARG
1463
 * on the NULL WC_RNG) until a new one is set. */
1464
int wc_curve25519_clear_rng(curve25519_key* key)
1465
0
{
1466
0
    if (key == NULL)
1467
0
        return BAD_FUNC_ARG;
1468
0
    key->rng = NULL;
1469
0
    return 0;
1470
0
}
1471
#endif
1472
1473
/* get key size */
1474
int wc_curve25519_size(curve25519_key* key)
1475
0
{
1476
0
    if (key == NULL)
1477
0
        return 0;
1478
1479
0
    return key->dp->size;
1480
0
}
1481
1482
#endif /*HAVE_CURVE25519*/