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/curve448.c
Line
Count
Source
1
/* curve448.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
/* Implemented to: RFC 7748 */
23
24
/* Based On Daniel J Bernstein's curve25519 Public Domain ref10 work.
25
 * Reworked for curve448 by Sean Parkinson.
26
 */
27
28
/*
29
 * Curve448 Build Options:
30
 *
31
 * HAVE_CURVE448:            Enable Curve448 support                default: off
32
 * HAVE_CURVE448_SHARED_SECRET: Enable Curve448 shared secret      default: on
33
 *                            (when HAVE_CURVE448 is enabled)
34
 * HAVE_CURVE448_KEY_EXPORT: Enable Curve448 key export            default: on
35
 * HAVE_CURVE448_KEY_IMPORT: Enable Curve448 key import            default: on
36
 * WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK: Skip ECDH shared secret != 0 check
37
 *                                                                  default: off
38
 */
39
40
#define _WC_BUILDING_CURVE448_C
41
42
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
43
44
#ifdef HAVE_CURVE448
45
46
#include <wolfssl/wolfcrypt/curve448.h>
47
#ifdef WOLF_CRYPTO_CB
48
    #include <wolfssl/wolfcrypt/cryptocb.h>
49
#endif
50
#ifdef NO_INLINE
51
    #include <wolfssl/wolfcrypt/misc.h>
52
#else
53
    #define WOLFSSL_MISC_INCLUDED
54
    #include <wolfcrypt/src/misc.c>
55
#endif
56
57
/* Check the private scalar is clamped per RFC 7748 section 5:
58
 * low two bits of byte 0 clear and top bit of byte 55 set. */
59
static WC_INLINE int curve448_priv_clamp_check(const byte* priv)
60
772
{
61
772
    int ret = 0;
62
772
    if ((priv[0] & 0x03) || !(priv[CURVE448_KEY_SIZE-1] & 0x80)) {
63
0
        ret = ECC_BAD_ARG_E;
64
0
    }
65
772
    return ret;
66
772
}
67
68
/* Compute pub = priv * basepoint(5).
69
 *
70
 * devId  [in]  Device to offload to, INVALID_DEVID for the caller's choice.
71
 * cbOk   [in]  Whether the private scalar may be offered to a crypto
72
 *              callback at all.  The keyless public API sets this, since it
73
 *              has no key to take a devId from; a key-owned scalar only sets
74
 *              it when the key is actually bound to a device, so an unbound
75
 *              key is never offloaded to whichever device happens to be
76
 *              registered first.
77
 */
78
static int curve448_make_pub_ex(int public_size, byte* pub, int private_size,
79
    const byte* priv, int devId, int cbOk)
80
772
{
81
772
    int ret;
82
772
#ifndef WOLF_CRYPTO_CB_ONLY_CURVE448
83
772
    unsigned char basepoint[CURVE448_KEY_SIZE] = {5};
84
772
#endif
85
86
772
    if ((pub == NULL) || (priv == NULL)) {
87
0
        return ECC_BAD_ARG_E;
88
0
    }
89
772
    if ((public_size  != CURVE448_PUB_KEY_SIZE) ||
90
772
        (private_size != CURVE448_KEY_SIZE)) {
91
0
        return ECC_BAD_ARG_E;
92
0
    }
93
94
    /* check clamping */
95
772
    ret = curve448_priv_clamp_check(priv);
96
772
    if (ret != 0)
97
0
        return ret;
98
99
772
#ifdef WOLF_CRYPTO_CB
100
772
    if (cbOk) {
101
0
        ret = wc_CryptoCb_Curve448MakePub(devId, public_size, pub,
102
0
            private_size, priv);
103
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
104
0
            return ret;
105
        /* fall-through when unavailable */
106
0
    }
107
#else
108
    (void)devId;
109
    (void)cbOk;
110
#endif
111
112
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE448
113
    ret = NO_VALID_DEVID;
114
#else
115
772
    fe448_init();
116
117
    /* compute public key */
118
772
    ret = curve448(pub, priv, basepoint);
119
772
#endif /* WOLF_CRYPTO_CB_ONLY_CURVE448 */
120
121
772
    return ret;
122
772
}
123
124
/* Derive a key's public point from its own private scalar.
125
 *
126
 * Only wc_curve448_make_key() and the public key export use this, so it is
127
 * unreferenced when the software key generation is stripped out and export is
128
 * disabled.
129
 */
130
#if !defined(WOLF_CRYPTO_CB_ONLY_CURVE448) || \
131
    defined(HAVE_CURVE448_KEY_EXPORT)
132
static int curve448_key_make_pub(curve448_key* key)
133
772
{
134
772
#ifdef WOLF_CRYPTO_CB
135
    #ifdef WOLF_CRYPTO_CB_FIND
136
    /* the find callback gets to route unbound keys */
137
    const int cbOk = 1;
138
    #else
139
772
    const int cbOk = (key->devId != INVALID_DEVID);
140
772
    #endif
141
142
772
    return curve448_make_pub_ex((int)sizeof(key->p), key->p,
143
772
        (int)sizeof(key->k), key->k, key->devId, cbOk);
144
#else
145
    return curve448_make_pub_ex((int)sizeof(key->p), key->p,
146
        (int)sizeof(key->k), key->k, INVALID_DEVID, 0);
147
#endif
148
772
}
149
#endif /* !WOLF_CRYPTO_CB_ONLY_CURVE448 || HAVE_CURVE448_KEY_EXPORT */
150
151
int wc_curve448_make_pub(int public_size, byte* pub, int private_size,
152
    const byte* priv)
153
0
{
154
    /* no key, so no device was selected: any registered one may serve it */
155
0
    return curve448_make_pub_ex(public_size, pub, private_size, priv,
156
0
        INVALID_DEVID, 1);
157
0
}
158
159
/* Is every byte of the curve448 result zero? Only reached when the caller's
160
 * basepoint is of small order, which leaks the result to anyone watching. */
161
#ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK
162
static WC_INLINE int curve448_result_is_zero(const byte* out)
163
0
{
164
0
    int i;
165
0
    byte t = 0;
166
0
    for (i = 0; i < CURVE448_PUB_KEY_SIZE; i++) {
167
0
        t |= out[i];
168
0
    }
169
0
    return (t == 0);
170
0
}
171
#endif
172
173
/* Multiply a scalar (private key) against any basepoint over curve448.
174
 *
175
 * An all-zero result is rejected with ECC_OUT_OF_RANGE_E, matching
176
 * wc_curve448_shared_secret_ex; define WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK to
177
 * get the raw scalar multiplication result instead.
178
 */
179
int wc_curve448_generic(int public_size, byte* pub,
180
                        int private_size, const byte* priv,
181
                        int basepoint_size, const byte* basepoint)
182
0
{
183
0
    int ret;
184
185
0
    if ((pub == NULL) || (priv == NULL) || (basepoint == NULL)) {
186
0
        return ECC_BAD_ARG_E;
187
0
    }
188
0
    if ((public_size    != CURVE448_PUB_KEY_SIZE) ||
189
0
        (private_size   != CURVE448_KEY_SIZE) ||
190
0
        (basepoint_size != CURVE448_KEY_SIZE)) {
191
0
        return ECC_BAD_ARG_E;
192
0
    }
193
194
    /* check clamping */
195
0
    ret = curve448_priv_clamp_check(priv);
196
0
    if (ret != 0)
197
0
        return ret;
198
199
0
#ifdef WOLF_CRYPTO_CB
200
    /* no key, so no device was selected: any registered one may serve it */
201
0
    ret = wc_CryptoCb_Curve448Generic(INVALID_DEVID, public_size, pub,
202
0
        private_size, priv, basepoint_size, basepoint);
203
0
    if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
204
0
    #ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK
205
        /* RFC 7748: reject an all-zero result from the callback too */
206
0
        if ((ret == 0) && curve448_result_is_zero(pub)) {
207
0
            ret = ECC_OUT_OF_RANGE_E;
208
0
        }
209
0
    #endif
210
0
        return ret;
211
0
    }
212
    /* fall-through when unavailable */
213
0
#endif
214
215
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE448
216
    ret = NO_VALID_DEVID;
217
#else
218
0
    fe448_init();
219
220
0
    ret = curve448(pub, priv, basepoint);
221
0
#ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK
222
0
    if ((ret == 0) && curve448_result_is_zero(pub)) {
223
0
        ret = ECC_OUT_OF_RANGE_E;
224
0
    }
225
0
#endif
226
0
#endif /* WOLF_CRYPTO_CB_ONLY_CURVE448 */
227
228
0
    return ret;
229
0
}
230
231
232
/* Make a new curve448 private/public key.
233
 *
234
 * rng      [in]  Random number generator.
235
 * keysize  [in]  Size of the key to generate.
236
 * key      [in]  Curve448 key object.
237
 * returns BAD_FUNC_ARG when rng or key are NULL,
238
 *         ECC_BAD_ARG_E when keysize is not CURVE448_KEY_SIZE,
239
 *         0 otherwise.
240
 */
241
int wc_curve448_make_key(WC_RNG* rng, int keysize, curve448_key* key)
242
920
{
243
920
    int  ret = 0;
244
245
920
    if ((key == NULL) || (rng == NULL)) {
246
0
        ret = BAD_FUNC_ARG;
247
0
    }
248
249
    /* currently only a key size of 56 bytes is used */
250
920
    if ((ret == 0) && (keysize != CURVE448_KEY_SIZE)) {
251
0
        ret = ECC_BAD_ARG_E;
252
0
    }
253
254
920
#ifdef WOLF_CRYPTO_CB
255
920
    if (ret == 0) {
256
920
    #ifndef WOLF_CRYPTO_CB_FIND
257
920
        if (key->devId != INVALID_DEVID)
258
0
    #endif
259
0
        {
260
0
            ret = wc_CryptoCb_Curve448Gen(rng, keysize, key);
261
0
            if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
262
0
                return ret;
263
            /* fall-through when unavailable */
264
0
            ret = 0;
265
0
        }
266
920
    }
267
920
#endif
268
269
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE448
270
    /* software path stripped; callback is the only provider */
271
    if (ret == 0) {
272
        ret = NO_VALID_DEVID;
273
    }
274
#else
275
920
    if (ret == 0) {
276
        /* random number for private key */
277
920
        ret = wc_RNG_GenerateBlock(rng, key->k, (word32)keysize);
278
920
    }
279
920
    if (ret == 0) {
280
772
        key->privSet = 1;
281
282
        /* clamp private */
283
772
        key->k[0] &= 0xfc;
284
772
        key->k[CURVE448_KEY_SIZE-1] |= 0x80;
285
286
        /* compute public */
287
772
        ret = curve448_key_make_pub(key);
288
772
        if (ret == 0) {
289
772
            key->pubSet = 1;
290
772
        }
291
0
        else {
292
0
            ForceZero(key->k, sizeof(key->k));
293
0
            XMEMSET(key->p, 0, sizeof(key->p));
294
0
        }
295
772
    }
296
920
#endif /* WOLF_CRYPTO_CB_ONLY_CURVE448 */
297
298
920
    return ret;
299
920
}
300
301
#ifdef HAVE_CURVE448_SHARED_SECRET
302
303
/* Calculate the shared secret from the private key and peer's public key.
304
 * Calculation over curve448.
305
 * Secret encoded big-endian.
306
 *
307
 * private_key  [in]      Curve448 private key.
308
 * public_key   [in]      Curve448 public key.
309
 * out          [in]      Array to hold shared secret.
310
 * outLen       [in/out]  On in, the number of bytes in array.
311
 *                        On out, the number bytes put into array.
312
 * returns BAD_FUNC_ARG when a parameter is NULL or outLen is less than
313
 *         CURVE448_KEY_SIZE,
314
 *         0 otherwise.
315
 */
316
int wc_curve448_shared_secret(curve448_key* private_key,
317
                              curve448_key* public_key,
318
                              byte* out, word32* outLen)
319
0
{
320
0
    return wc_curve448_shared_secret_ex(private_key, public_key, out, outLen,
321
0
                                        EC448_BIG_ENDIAN);
322
0
}
323
324
/* Calculate the shared secret from the private key and peer's public key.
325
 * Calculation over curve448.
326
 *
327
 * private_key  [in]      Curve448 private key.
328
 * public_key   [in]      Curve448 public key.
329
 * out          [in]      Array to hold shared secret.
330
 * outLen       [in/out]  On in, the number of bytes in array.
331
 *                        On out, the number bytes put into array.
332
 * endian       [in]      Endianness to use when encoding number in array.
333
 * returns BAD_FUNC_ARG when a parameter is NULL or outLen is less than
334
 *         CURVE448_PUB_KEY_SIZE,
335
 *         0 otherwise.
336
 */
337
int wc_curve448_shared_secret_ex(curve448_key* private_key,
338
                                 curve448_key* public_key,
339
                                 byte* out, word32* outLen, int endian)
340
42
{
341
42
#ifndef WOLF_CRYPTO_CB_ONLY_CURVE448
342
42
    unsigned char o[CURVE448_PUB_KEY_SIZE];
343
42
    int i;
344
42
#endif
345
42
    int ret = 0;
346
347
    /* sanity check */
348
42
    if ((private_key == NULL) || (public_key == NULL) || (out == NULL) ||
349
42
                        (outLen == NULL) || (*outLen < CURVE448_PUB_KEY_SIZE)) {
350
0
        return BAD_FUNC_ARG;
351
0
    }
352
    /* make sure we have a populated private and public key */
353
42
    if (!private_key->privSet || !public_key->pubSet) {
354
0
        return ECC_BAD_ARG_E;
355
0
    }
356
357
42
#ifdef WOLF_CRYPTO_CB
358
42
    #ifndef WOLF_CRYPTO_CB_FIND
359
42
    if (private_key->devId != INVALID_DEVID)
360
0
    #endif
361
0
    {
362
0
        ret = wc_CryptoCb_Curve448(private_key, public_key, out, outLen,
363
0
            endian);
364
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
365
0
#ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK
366
            /* RFC 7748: reject an all-zero secret from the callback too */
367
0
            if (ret == 0) {
368
0
                int j;
369
0
                byte t = 0;
370
0
                for (j = 0; j < CURVE448_PUB_KEY_SIZE; j++) {
371
0
                    t |= out[j];
372
0
                }
373
0
                if (t == 0) {
374
0
                    ret = ECC_OUT_OF_RANGE_E;
375
0
                }
376
0
            }
377
0
#endif
378
0
            return ret;
379
0
        }
380
        /* fall-through when unavailable */
381
0
        ret = 0;
382
0
    }
383
42
#endif
384
385
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE448
386
    /* software path stripped; callback is the only provider */
387
    if (ret == 0) {
388
        ret = NO_VALID_DEVID;
389
    }
390
#else
391
#ifdef WOLFSSL_CHECK_MEM_ZERO
392
    /* Register the buffer after the early returns so every later path
393
     * reaches the cleanup ForceZero. XMEMSET makes it defined. */
394
    XMEMSET(o, 0, sizeof(o));
395
    wc_MemZero_Add("wc_curve448_shared_secret_ex o", o, CURVE448_PUB_KEY_SIZE);
396
#endif
397
398
42
    if (ret == 0) {
399
42
        ret = curve448(o, private_key->k, public_key->p);
400
42
    }
401
42
#ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK
402
42
    if (ret == 0) {
403
42
        byte t = 0;
404
2.39k
        for (i = 0; i < CURVE448_PUB_KEY_SIZE; i++) {
405
2.35k
            t |= o[i];
406
2.35k
        }
407
42
        if (t == 0) {
408
0
            ret = ECC_OUT_OF_RANGE_E;
409
0
        }
410
42
    }
411
42
#endif
412
42
    if (ret == 0) {
413
42
        if (endian == EC448_BIG_ENDIAN) {
414
            /* put shared secret key in Big Endian format */
415
0
            for (i = 0; i < CURVE448_PUB_KEY_SIZE; i++) {
416
0
                 out[i] = o[CURVE448_PUB_KEY_SIZE - i -1];
417
0
            }
418
0
        }
419
42
        else {
420
            /* put shared secret key in Little Endian format */
421
42
            XMEMCPY(out, o, CURVE448_PUB_KEY_SIZE);
422
42
        }
423
424
42
        *outLen = CURVE448_PUB_KEY_SIZE;
425
42
    }
426
427
42
    ForceZero(o, CURVE448_PUB_KEY_SIZE);
428
#ifdef WOLFSSL_CHECK_MEM_ZERO
429
    wc_MemZero_Check(o, CURVE448_PUB_KEY_SIZE);
430
#endif
431
42
#endif /* WOLF_CRYPTO_CB_ONLY_CURVE448 */
432
433
42
    return ret;
434
42
}
435
436
#endif /* HAVE_CURVE448_SHARED_SECRET */
437
438
#ifdef HAVE_CURVE448_KEY_EXPORT
439
440
/* Export the curve448 public key.
441
 * Public key encoded big-endian.
442
 *
443
 * key     [in]      Curve448 public key.
444
 * out     [in]      Array to hold public key.
445
 * outLen  [in/out]  On in, the number of bytes in array.
446
 *                   On out, the number bytes put into array.
447
 * returns BAD_FUNC_ARG when a parameter is NULL,
448
 *         ECC_BAD_ARG_E when outLen is less than CURVE448_PUB_KEY_SIZE or
449
 *         neither the public nor the private key has been set,
450
 *         0 otherwise.
451
 */
452
int wc_curve448_export_public(curve448_key* key, byte* out, word32* outLen)
453
1
{
454
1
    return wc_curve448_export_public_ex(key, out, outLen, EC448_BIG_ENDIAN);
455
1
}
456
457
/* Export the curve448 public key.
458
 *
459
 * key     [in]      Curve448 public key.
460
 * out     [in]      Array to hold public key.
461
 * outLen  [in/out]  On in, the number of bytes in array.
462
 *                   On out, the number bytes put into array.
463
 * endian  [in]      Endianness to use when encoding number in array.
464
 * returns BAD_FUNC_ARG when a parameter is NULL,
465
 *         ECC_BAD_ARG_E when outLen is less than CURVE448_PUB_KEY_SIZE or
466
 *         neither the public nor the private key has been set,
467
 *         0 otherwise.
468
 */
469
int wc_curve448_export_public_ex(curve448_key* key, byte* out, word32* outLen,
470
                                 int endian)
471
502
{
472
502
    int ret = 0;
473
474
502
    if ((key == NULL) || (out == NULL) || (outLen == NULL)) {
475
112
        ret = BAD_FUNC_ARG;
476
112
    }
477
478
    /* check and set outgoing key size */
479
502
    if ((ret == 0) && (*outLen < CURVE448_PUB_KEY_SIZE)) {
480
31
        *outLen = CURVE448_PUB_KEY_SIZE;
481
31
        ret = ECC_BAD_ARG_E;
482
31
    }
483
484
    /* no public key to export and no private key to derive it from */
485
502
    if ((ret == 0) && (!key->pubSet) && (!key->privSet)) {
486
0
        ret = ECC_BAD_ARG_E;
487
0
    }
488
502
    if (ret == 0) {
489
        /* calculate public if missing */
490
359
        if (!key->pubSet) {
491
0
            ret = curve448_key_make_pub(key);
492
0
            key->pubSet = (ret == 0);
493
0
        }
494
359
    }
495
502
    if (ret == 0) {
496
359
        *outLen = CURVE448_PUB_KEY_SIZE;
497
359
        if (endian == EC448_BIG_ENDIAN) {
498
1
            int i;
499
            /* read keys in Big Endian format */
500
57
            for (i = 0; i < CURVE448_PUB_KEY_SIZE; i++) {
501
56
                out[i] = key->p[CURVE448_PUB_KEY_SIZE - i - 1];
502
56
            }
503
1
        }
504
358
        else {
505
358
            XMEMCPY(out, key->p, CURVE448_PUB_KEY_SIZE);
506
358
        }
507
359
    }
508
509
502
    return ret;
510
502
}
511
512
#endif /* HAVE_CURVE448_KEY_EXPORT */
513
514
#ifdef HAVE_CURVE448_KEY_IMPORT
515
516
/* Import a curve448 public key from a byte array.
517
 * Public key encoded in big-endian.
518
 *
519
 * in      [in]  Array holding public key.
520
 * inLen   [in]  Number of bytes of data in array.
521
 * key     [in]  Curve448 public key.
522
 * returns BAD_FUNC_ARG when a parameter is NULL,
523
 *         ECC_BAD_ARG_E when inLen is less than CURVE448_PUB_KEY_SIZE,
524
 *         0 otherwise.
525
 */
526
int wc_curve448_import_public(const byte* in, word32 inLen, curve448_key* key)
527
12
{
528
12
    return wc_curve448_import_public_ex(in, inLen, key, EC448_BIG_ENDIAN);
529
12
}
530
531
/* Import a curve448 public key from a byte array.
532
 *
533
 * in      [in]  Array holding public key.
534
 * inLen   [in]  Number of bytes of data in array.
535
 * key     [in]  Curve448 public key.
536
 * endian  [in]  Endianness of encoded number in byte array.
537
 * returns BAD_FUNC_ARG when a parameter is NULL,
538
 *         ECC_BAD_ARG_E when inLen is less than CURVE448_PUB_KEY_SIZE,
539
 *         0 otherwise.
540
 */
541
int wc_curve448_import_public_ex(const byte* in, word32 inLen,
542
                                 curve448_key* key, int endian)
543
88
{
544
88
    int ret = 0;
545
546
    /* sanity check */
547
88
    if ((key == NULL) || (in == NULL)) {
548
1
        ret = BAD_FUNC_ARG;
549
1
    }
550
551
    /* check size of incoming keys */
552
88
    if ((ret == 0) && (inLen != CURVE448_PUB_KEY_SIZE)) {
553
11
       ret = ECC_BAD_ARG_E;
554
11
    }
555
556
88
    if (ret == 0) {
557
76
        if (endian == EC448_BIG_ENDIAN) {
558
1
            int i;
559
            /* read keys in Big Endian format */
560
57
            for (i = 0; i < CURVE448_PUB_KEY_SIZE; i++) {
561
56
                key->p[i] = in[CURVE448_PUB_KEY_SIZE - i - 1];
562
56
            }
563
1
        }
564
75
        else
565
75
            XMEMCPY(key->p, in, inLen);
566
76
        key->pubSet = 1;
567
76
    }
568
569
88
    return ret;
570
88
}
571
572
/* Check the public key value (big or little endian)
573
 *
574
 * pub     [in]  Public key bytes.
575
 * pubSz   [in]  Size of public key in bytes.
576
 * endian  [in]  Public key bytes passed in as big-endian or little-endian.
577
 * returns BAD_FUNC_ARGS when pub is NULL,
578
 *         ECC_BAD_ARG_E when key length is not 56 bytes, or the public key
579
 *         value is a cheaply detectable low-order point: 0, 1, p-1 (u = -1)
580
 *         or the non-canonical encodings p and p+1 (p = 2^448 - 2^224 - 1);
581
 *         BUFFER_E when size of public key is zero;
582
 *         0 otherwise.
583
 *
584
 * RFC 7748 Section 5 requires the non-canonical range [p, 2^448-1] to be
585
 * accepted and processed as if reduced modulo p, so p+2 .. 2^448-1 are valid
586
 * inputs (the field arithmetic performs the reduction) and are not rejected
587
 * here.
588
 */
589
int wc_curve448_check_public(const byte* pub, word32 pubSz, int endian)
590
998
{
591
998
    int ret = 0;
592
593
998
    if (pub == NULL) {
594
0
        ret = BAD_FUNC_ARG;
595
0
    }
596
597
    /* Check for empty key data */
598
998
    if ((ret == 0) && (pubSz == 0)) {
599
4
        ret = BUFFER_E;
600
4
    }
601
602
    /* Check key length */
603
998
    if ((ret == 0) && (pubSz != CURVE448_PUB_KEY_SIZE)) {
604
39
        ret = ECC_BAD_ARG_E;
605
39
    }
606
607
998
    if (ret == 0) {
608
955
        word32 i;
609
610
955
        if (endian == EC448_LITTLE_ENDIAN) {
611
            /* Check for value of zero or one */
612
1.26k
            for (i = CURVE448_PUB_KEY_SIZE - 1; i > 0; i--) {
613
1.25k
                if (pub[i] != 0) {
614
178
                    break;
615
178
                }
616
1.25k
            }
617
193
            if ((i == 0) && (pub[0] == 0 || pub[0] == 1)) {
618
6
                return ECC_BAD_ARG_E;
619
6
            }
620
            /* Check for p-1, p and p+1, p = 2^448 - 2^224 - 1. Little-endian:
621
             *   p-1 = fe ff[27] fe ff[27]  (the low-order point u = -1)
622
             *   p   = ff[28]    fe ff[27]  (non-canonical encoding of 0)
623
             *   p+1 = 00[28]    ff ff[27]  (non-canonical encoding of 1)
624
             * The other non-canonical values, p+2 .. 2^448-1, must be accepted
625
             * and processed as if reduced modulo p (RFC 7748 Section 5); the
626
             * field arithmetic performs the reduction. */
627
2.75k
            for (i = CURVE448_PUB_KEY_SIZE - 1; i > 28; i--) {
628
2.67k
                if (pub[i] != 0xff) {
629
101
                    break;
630
101
                }
631
2.67k
            }
632
187
            if ((i == 28) && (pub[i] == 0xff)) {
633
                /* p+1: bytes 27..0 all zero. */
634
360
                for (--i; i > 0; i--) {
635
350
                    if (pub[i] != 0x00) {
636
17
                        break;
637
17
                    }
638
350
                }
639
27
                if ((i == 0) && (pub[i] == 0x00)) {
640
2
                    return ECC_BAD_ARG_E;
641
2
                }
642
27
            }
643
160
            else if ((i == 28) && (pub[i] == 0xfe)) {
644
                /* p-1 and p: bytes 27..1 all 0xff, byte 0 is 0xfe or 0xff. */
645
629
                for (--i; i > 0; i--) {
646
611
                    if (pub[i] != 0xff) {
647
23
                        break;
648
23
                    }
649
611
                }
650
41
                if ((i == 0) && (pub[i] >= 0xfe)) {
651
3
                    return ECC_BAD_ARG_E;
652
3
                }
653
41
            }
654
187
        }
655
762
        else {
656
            /* Check for value of zero or one */
657
1.18k
            for (i = 0; i < CURVE448_PUB_KEY_SIZE-1; i++) {
658
1.18k
                if (pub[i] != 0) {
659
759
                    break;
660
759
                }
661
1.18k
            }
662
762
            if ((i == CURVE448_PUB_KEY_SIZE - 1) &&
663
3
                (pub[i] == 0 || pub[i] == 1)) {
664
2
                ret = ECC_BAD_ARG_E;
665
2
            }
666
            /* Check for p-1, p and p+1 (see the little-endian case above). */
667
2.24k
            for (i = 0; i < 27; i++) {
668
2.19k
                if (pub[i] != 0xff) {
669
714
                    break;
670
714
                }
671
2.19k
            }
672
762
            if ((i == 27) && (pub[i] == 0xff)) {
673
                /* p+1: bytes 28..55 all zero. */
674
248
                for (++i; i < CURVE448_PUB_KEY_SIZE - 1; i++) {
675
243
                    if (pub[i] != 0x00) {
676
13
                        break;
677
13
                    }
678
243
                }
679
18
                if ((i == CURVE448_PUB_KEY_SIZE - 1) && (pub[i] == 0x00)) {
680
1
                    return ECC_BAD_ARG_E;
681
1
                }
682
18
            }
683
744
            else if ((i == 27) && (pub[i] == 0xfe)) {
684
                /* p-1 and p: bytes 28..54 all 0xff, byte 55 is 0xfe or 0xff. */
685
323
                for (++i; i < CURVE448_PUB_KEY_SIZE - 1; i++) {
686
317
                    if (pub[i] != 0xff) {
687
15
                        break;
688
15
                    }
689
317
                }
690
21
                if ((i == CURVE448_PUB_KEY_SIZE - 1) && (pub[i] >= 0xfe)) {
691
1
                    return ECC_BAD_ARG_E;
692
1
                }
693
21
            }
694
762
        }
695
955
    }
696
697
985
    return ret;
698
998
}
699
700
#endif /* HAVE_CURVE448_KEY_IMPORT */
701
702
703
#ifdef HAVE_CURVE448_KEY_EXPORT
704
705
/* Export the curve448 private key raw form.
706
 * Private key encoded big-endian.
707
 *
708
 * key     [in]      Curve448 private key.
709
 * out     [in]      Array to hold private key.
710
 * outLen  [in/out]  On in, the number of bytes in array.
711
 *                   On out, the number bytes put into array.
712
 * returns BAD_FUNC_ARG when a parameter is NULL,
713
 *         ECC_BAD_ARG_E when outLen is less than CURVE448_KEY_SIZE,
714
 *         0 otherwise.
715
 */
716
int wc_curve448_export_private_raw(curve448_key* key, byte* out, word32* outLen)
717
0
{
718
0
    return wc_curve448_export_private_raw_ex(key, out, outLen,
719
0
                                             EC448_BIG_ENDIAN);
720
0
}
721
722
/* Export the curve448 private key raw form.
723
 *
724
 * key     [in]      Curve448 private key.
725
 * out     [in]      Array to hold private key.
726
 * outLen  [in/out]  On in, the number of bytes in array.
727
 *                   On out, the number bytes put into array.
728
 * endian  [in]      Endianness to use when encoding number in array.
729
 * returns BAD_FUNC_ARG when a parameter is NULL,
730
 *         ECC_BAD_ARG_E when outLen is less than CURVE448_KEY_SIZE,
731
 *         0 otherwise.
732
 */
733
int wc_curve448_export_private_raw_ex(curve448_key* key, byte* out,
734
                                      word32* outLen, int endian)
735
651
{
736
651
    int ret = 0;
737
738
    /* sanity check */
739
651
    if ((key == NULL) || (out == NULL) || (outLen == NULL)) {
740
169
        ret = BAD_FUNC_ARG;
741
169
    }
742
743
651
    if ((ret == 0) && (!key->privSet)) {
744
0
        ret = ECC_BAD_ARG_E;
745
0
    }
746
747
    /* check size of outgoing buffer */
748
651
    if ((ret == 0) && (*outLen < CURVE448_KEY_SIZE)) {
749
36
        *outLen = CURVE448_KEY_SIZE;
750
36
        ret = ECC_BAD_ARG_E;
751
36
    }
752
651
    if (ret == 0) {
753
446
        *outLen = CURVE448_KEY_SIZE;
754
755
446
        if (endian == EC448_BIG_ENDIAN) {
756
0
            int i;
757
            /* put the key in Big Endian format */
758
0
            for (i = 0; i < CURVE448_KEY_SIZE; i++) {
759
0
                out[i] = key->k[CURVE448_KEY_SIZE - i - 1];
760
0
            }
761
0
        }
762
446
        else {
763
446
            XMEMCPY(out, key->k, CURVE448_KEY_SIZE);
764
446
        }
765
446
    }
766
767
651
    return ret;
768
651
}
769
770
/* Export the curve448 private and public keys in raw form.
771
 * Private and public key encoded big-endian.
772
 *
773
 * key     [in]      Curve448 private key.
774
 * priv    [in]      Array to hold private key.
775
 * privSz  [in/out]  On in, the number of bytes in private key array.
776
 *                   On out, the number bytes put into private key array.
777
 * pub     [in]      Array to hold public key.
778
 * pubSz   [in/out]  On in, the number of bytes in public key array.
779
 *                   On out, the number bytes put into public key array.
780
 * returns BAD_FUNC_ARG when a parameter is NULL,
781
 *         ECC_BAD_ARG_E when privSz is less than CURVE448_KEY_SIZE or pubSz is
782
 *         less than CURVE448_PUB_KEY_SIZE,
783
 *         0 otherwise.
784
 */
785
int wc_curve448_export_key_raw(curve448_key* key, byte* priv, word32 *privSz,
786
                               byte* pub, word32 *pubSz)
787
0
{
788
0
    return wc_curve448_export_key_raw_ex(key, priv, privSz, pub, pubSz,
789
0
                                         EC448_BIG_ENDIAN);
790
0
}
791
792
/* Export the curve448 private and public keys in raw form.
793
 *
794
 * key     [in]      Curve448 private key.
795
 * priv    [in]      Array to hold private key.
796
 * privSz  [in/out]  On in, the number of bytes in private key array.
797
 *                   On out, the number bytes put into private key array.
798
 * pub     [in]      Array to hold public key.
799
 * pubSz   [in/out]  On in, the number of bytes in public key array.
800
 *                   On out, the number bytes put into public key array.
801
 * endian  [in]      Endianness to use when encoding number in array.
802
 * returns BAD_FUNC_ARG when a parameter is NULL,
803
 *         ECC_BAD_ARG_E when privSz is less than CURVE448_KEY_SIZE or pubSz is
804
 *         less than CURVE448_PUB_KEY_SIZE,
805
 *         0 otherwise.
806
 */
807
int wc_curve448_export_key_raw_ex(curve448_key* key, byte* priv, word32 *privSz,
808
                                  byte* pub, word32 *pubSz, int endian)
809
0
{
810
0
    int ret;
811
812
    /* export private part */
813
0
    ret = wc_curve448_export_private_raw_ex(key, priv, privSz, endian);
814
0
    if (ret == 0) {
815
        /* export public part */
816
0
        ret = wc_curve448_export_public_ex(key, pub, pubSz, endian);
817
0
    }
818
819
0
    return ret;
820
0
}
821
822
#endif /* HAVE_CURVE448_KEY_EXPORT */
823
824
#ifdef HAVE_CURVE448_KEY_IMPORT
825
826
/* Import curve448 private and public keys from a byte arrays.
827
 * Private and public keys encoded in big-endian.
828
 *
829
 * piv     [in]  Array holding private key.
830
 * privSz  [in]  Number of bytes of data in private key array.
831
 * pub     [in]  Array holding public key.
832
 * pubSz   [in]  Number of bytes of data in public key array.
833
 * key     [in]  Curve448 private/public key.
834
 * returns BAD_FUNC_ARG when a parameter is NULL,
835
 *         ECC_BAD_ARG_E when privSz is less than CURVE448_KEY_SIZE or pubSz is
836
 *         less than CURVE448_PUB_KEY_SIZE,
837
 *         0 otherwise.
838
 */
839
int wc_curve448_import_private_raw(const byte* priv, word32 privSz,
840
                                   const byte* pub, word32 pubSz,
841
                                   curve448_key* key)
842
9
{
843
9
    return wc_curve448_import_private_raw_ex(priv, privSz, pub, pubSz, key,
844
9
                                             EC448_BIG_ENDIAN);
845
9
}
846
847
/* Import curve448 private and public keys from a byte arrays.
848
 *
849
 * piv     [in]  Array holding private key.
850
 * privSz  [in]  Number of bytes of data in private key array.
851
 * pub     [in]  Array holding public key.
852
 * pubSz   [in]  Number of bytes of data in public key array.
853
 * key     [in]  Curve448 private/public key.
854
 * endian  [in]  Endianness of encoded numbers in byte arrays.
855
 * returns BAD_FUNC_ARG when a parameter is NULL,
856
 *         ECC_BAD_ARG_E when privSz is less than CURVE448_KEY_SIZE or pubSz is
857
 *         less than CURVE448_PUB_KEY_SIZE,
858
 *         0 otherwise.
859
 */
860
int wc_curve448_import_private_raw_ex(const byte* priv, word32 privSz,
861
                                      const byte* pub, word32 pubSz,
862
                                      curve448_key* key, int endian)
863
9
{
864
9
    int ret;
865
866
    /* import private part */
867
9
    ret = wc_curve448_import_private_ex(priv, privSz, key, endian);
868
9
    if (ret == 0) {
869
        /* import public part */
870
1
        return wc_curve448_import_public_ex(pub, pubSz, key, endian);
871
1
    }
872
873
8
    return ret;
874
9
}
875
876
/* Import curve448 private key from a byte array.
877
 * Private key encoded in big-endian.
878
 *
879
 * piv     [in]  Array holding private key.
880
 * privSz  [in]  Number of bytes of data in private key array.
881
 * key     [in]  Curve448 private/public key.
882
 * returns BAD_FUNC_ARG when a parameter is NULL,
883
 *         ECC_BAD_ARG_E when privSz is less than CURVE448_KEY_SIZE,
884
 *         0 otherwise.
885
 */
886
int wc_curve448_import_private(const byte* priv, word32 privSz,
887
                               curve448_key* key)
888
0
{
889
0
    return wc_curve448_import_private_ex(priv, privSz, key, EC448_BIG_ENDIAN);
890
0
}
891
892
/* Import curve448 private key from a byte array.
893
 *
894
 * piv     [in]  Array holding private key.
895
 * privSz  [in]  Number of bytes of data in private key array.
896
 * key     [in]  Curve448 private/public key.
897
 * endian  [in]  Endianness of encoded number in byte array.
898
 * returns BAD_FUNC_ARG when a parameter is NULL,
899
 *         ECC_BAD_ARG_E when privSz is less than CURVE448_KEY_SIZE,
900
 *         0 otherwise.
901
 */
902
int wc_curve448_import_private_ex(const byte* priv, word32 privSz,
903
                                  curve448_key* key, int endian)
904
9
{
905
9
    int ret = 0;
906
907
    /* sanity check */
908
9
    if ((key == NULL) || (priv == NULL)) {
909
0
        ret = BAD_FUNC_ARG;
910
0
    }
911
912
    /* check size of incoming keys */
913
9
    if ((ret == 0) && ((int)privSz != CURVE448_KEY_SIZE)) {
914
8
        ret = ECC_BAD_ARG_E;
915
8
    }
916
917
9
    if (ret == 0) {
918
1
        if (endian == EC448_BIG_ENDIAN) {
919
1
            int i;
920
            /* read the key in Big Endian format */
921
57
            for (i = 0; i < CURVE448_KEY_SIZE; i++) {
922
56
                key->k[i] = priv[CURVE448_KEY_SIZE - i - 1];
923
56
            }
924
1
        }
925
0
        else {
926
0
            XMEMCPY(key->k, priv, CURVE448_KEY_SIZE);
927
0
        }
928
929
        /* Clamp the key */
930
1
        key->k[0] &= 0xfc;
931
1
        key->k[CURVE448_KEY_SIZE-1] |= 0x80;
932
933
1
        key->privSet = 1;
934
1
    }
935
936
9
    return ret;
937
9
}
938
939
#endif /* HAVE_CURVE448_KEY_IMPORT */
940
941
942
#ifndef WC_NO_CONSTRUCTORS
943
curve448_key* wc_curve448_new(void* heap, int devId, int* result_code)
944
0
{
945
0
    int ret;
946
0
    curve448_key* key = (curve448_key*)XMALLOC(sizeof(curve448_key), heap,
947
0
                         DYNAMIC_TYPE_CURVE448);
948
0
    if (key == NULL) {
949
0
        ret = MEMORY_E;
950
0
    }
951
0
    else {
952
0
        ret = wc_curve448_init_ex(key, heap, devId);
953
0
        if (ret != 0) {
954
0
            XFREE(key, heap, DYNAMIC_TYPE_CURVE448);
955
0
            key = NULL;
956
0
        }
957
0
    }
958
959
0
    if (result_code != NULL)
960
0
        *result_code = ret;
961
962
0
    return key;
963
0
}
964
965
0
int wc_curve448_delete(curve448_key* key, curve448_key** key_p) {
966
0
    void* heap;
967
0
    if (key == NULL)
968
0
        return BAD_FUNC_ARG;
969
0
    heap = key->heap;
970
0
    wc_curve448_free(key);
971
0
    XFREE(key, heap, DYNAMIC_TYPE_CURVE448);
972
0
    if (key_p != NULL)
973
0
        *key_p = NULL;
974
0
    return 0;
975
0
}
976
#endif /* !WC_NO_CONSTRUCTORS */
977
978
/* Initialize the curve448 key with a heap hint and crypto callback devId. */
979
int wc_curve448_init_ex(curve448_key* key, void* heap, int devId)
980
1.02k
{
981
1.02k
    int ret = 0;
982
983
1.02k
    if (key == NULL) {
984
0
       ret = BAD_FUNC_ARG;
985
0
    }
986
987
1.02k
    if (ret == 0) {
988
1.02k
        XMEMSET(key, 0, sizeof(*key));
989
990
1.02k
    #ifdef WOLF_CRYPTO_CB
991
1.02k
        key->devId = devId;
992
    #else
993
        (void)devId;
994
    #endif
995
1.02k
        key->heap = heap;
996
997
    /* field math is implemented in the callback in crypto cb only */
998
1.02k
    #ifndef WOLF_CRYPTO_CB_ONLY_CURVE448
999
1.02k
        fe448_init();
1000
1.02k
    #endif
1001
1002
    #ifdef WOLFSSL_CHECK_MEM_ZERO
1003
        wc_MemZero_Add("wc_curve448_init key->k", &key->k, CURVE448_KEY_SIZE);
1004
    #endif
1005
1.02k
    }
1006
1007
1.02k
    return ret;
1008
1.02k
}
1009
1010
/* Initialize the curve448 key.
1011
 *
1012
 * key  [in]  Curve448 key object.
1013
 * returns BAD_FUNC_ARG when key is NULL,
1014
 *         0 otherwise.
1015
 */
1016
int wc_curve448_init(curve448_key* key)
1017
823
{
1018
823
    return wc_curve448_init_ex(key, NULL, INVALID_DEVID);
1019
823
}
1020
1021
1022
/* Clears the curve448 key data.
1023
 *
1024
 * key  [in]  Curve448 key object.
1025
 */
1026
void wc_curve448_free(curve448_key* key)
1027
1.04k
{
1028
1.04k
    if (key != NULL) {
1029
1.02k
        ForceZero(key->k, sizeof(key->k));
1030
1.02k
        XMEMSET(key->p, 0, sizeof(key->p));
1031
1.02k
        key->pubSet = 0;
1032
1.02k
        key->privSet = 0;
1033
    #ifdef WOLFSSL_CHECK_MEM_ZERO
1034
        wc_MemZero_Check(key, sizeof(curve448_key));
1035
    #endif
1036
1.02k
    }
1037
1.04k
}
1038
1039
1040
/* Get the curve448 key's size.
1041
 *
1042
 * key  [in]  Curve448 key object.
1043
 * returns 0 if key is NULL,
1044
 *         CURVE448_KEY_SIZE otherwise.
1045
 */
1046
int wc_curve448_size(curve448_key* key)
1047
0
{
1048
0
    int ret = 0;
1049
1050
0
    if (key != NULL) {
1051
0
        ret = CURVE448_KEY_SIZE;
1052
0
    }
1053
1054
0
    return ret;
1055
0
}
1056
1057
#endif /* HAVE_CURVE448 */
1058