Coverage Report

Created: 2025-06-13 06:58

/src/openssl30/crypto/ec/curve448/eddsa.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
3
 * Copyright 2015-2016 Cryptography Research, Inc.
4
 *
5
 * Licensed under the Apache License 2.0 (the "License").  You may not use
6
 * this file except in compliance with the License.  You can obtain a copy
7
 * in the file LICENSE in the source distribution or at
8
 * https://www.openssl.org/source/license.html
9
 *
10
 * Originally written by Mike Hamburg
11
 */
12
#include <string.h>
13
#include <openssl/crypto.h>
14
#include <openssl/evp.h>
15
#include "crypto/ecx.h"
16
#include "curve448_local.h"
17
#include "word.h"
18
#include "ed448.h"
19
#include "internal/numbers.h"
20
21
25
#define COFACTOR 4
22
23
static c448_error_t oneshot_hash(OSSL_LIB_CTX *ctx, uint8_t *out, size_t outlen,
24
                                 const uint8_t *in, size_t inlen,
25
                                 const char *propq)
26
25
{
27
25
    EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
28
25
    EVP_MD *shake256 = NULL;
29
25
    c448_error_t ret = C448_FAILURE;
30
31
25
    if (hashctx == NULL)
32
0
        return C448_FAILURE;
33
34
25
    shake256 = EVP_MD_fetch(ctx, "SHAKE256", propq);
35
25
    if (shake256 == NULL)
36
0
        goto err;
37
38
25
    if (!EVP_DigestInit_ex(hashctx, shake256, NULL)
39
25
            || !EVP_DigestUpdate(hashctx, in, inlen)
40
25
            || !EVP_DigestFinalXOF(hashctx, out, outlen))
41
0
        goto err;
42
43
25
    ret = C448_SUCCESS;
44
25
 err:
45
25
    EVP_MD_CTX_free(hashctx);
46
25
    EVP_MD_free(shake256);
47
25
    return ret;
48
25
}
49
50
static void clamp(uint8_t secret_scalar_ser[EDDSA_448_PRIVATE_BYTES])
51
25
{
52
25
    secret_scalar_ser[0] &= -COFACTOR;
53
25
    secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 1] = 0;
54
25
    secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 2] |= 0x80;
55
25
}
56
57
static c448_error_t hash_init_with_dom(OSSL_LIB_CTX *ctx, EVP_MD_CTX *hashctx,
58
                                       uint8_t prehashed,
59
                                       uint8_t for_prehash,
60
                                       const uint8_t *context,
61
                                       size_t context_len,
62
                                       const char *propq)
63
55
{
64
#ifdef CHARSET_EBCDIC
65
    const char dom_s[] = {0x53, 0x69, 0x67, 0x45,
66
                          0x64, 0x34, 0x34, 0x38, 0x00};
67
#else
68
55
    const char dom_s[] = "SigEd448";
69
55
#endif
70
55
    uint8_t dom[2];
71
55
    EVP_MD *shake256 = NULL;
72
73
55
    if (context_len > UINT8_MAX)
74
0
        return C448_FAILURE;
75
76
55
    dom[0] = (uint8_t)(2 - (prehashed == 0 ? 1 : 0)
77
55
                       - (for_prehash == 0 ? 1 : 0));
78
55
    dom[1] = (uint8_t)context_len;
79
80
55
    shake256 = EVP_MD_fetch(ctx, "SHAKE256", propq);
81
55
    if (shake256 == NULL)
82
0
        return C448_FAILURE;
83
84
55
    if (!EVP_DigestInit_ex(hashctx, shake256, NULL)
85
55
            || !EVP_DigestUpdate(hashctx, dom_s, strlen(dom_s))
86
55
            || !EVP_DigestUpdate(hashctx, dom, sizeof(dom))
87
55
            || !EVP_DigestUpdate(hashctx, context, context_len)) {
88
0
        EVP_MD_free(shake256);
89
0
        return C448_FAILURE;
90
0
    }
91
92
55
    EVP_MD_free(shake256);
93
55
    return C448_SUCCESS;
94
55
}
95
96
/* In this file because it uses the hash */
97
c448_error_t
98
ossl_c448_ed448_convert_private_key_to_x448(
99
                            OSSL_LIB_CTX *ctx,
100
                            uint8_t x[X448_PRIVATE_BYTES],
101
                            const uint8_t ed [EDDSA_448_PRIVATE_BYTES],
102
                            const char *propq)
103
0
{
104
    /* pass the private key through oneshot_hash function */
105
    /* and keep the first X448_PRIVATE_BYTES bytes */
106
0
    return oneshot_hash(ctx, x, X448_PRIVATE_BYTES, ed,
107
0
                        EDDSA_448_PRIVATE_BYTES, propq);
108
0
}
109
110
c448_error_t
111
ossl_c448_ed448_derive_public_key(
112
                        OSSL_LIB_CTX *ctx,
113
                        uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
114
                        const uint8_t privkey[EDDSA_448_PRIVATE_BYTES],
115
                        const char *propq)
116
25
{
117
    /* only this much used for keygen */
118
25
    uint8_t secret_scalar_ser[EDDSA_448_PRIVATE_BYTES];
119
25
    curve448_scalar_t secret_scalar;
120
25
    unsigned int c;
121
25
    curve448_point_t p;
122
123
25
    if (!oneshot_hash(ctx, secret_scalar_ser, sizeof(secret_scalar_ser),
124
25
                      privkey,
125
25
                      EDDSA_448_PRIVATE_BYTES,
126
25
                      propq))
127
0
        return C448_FAILURE;
128
129
25
    clamp(secret_scalar_ser);
130
131
25
    ossl_curve448_scalar_decode_long(secret_scalar, secret_scalar_ser,
132
25
                                     sizeof(secret_scalar_ser));
133
134
    /*
135
     * Since we are going to mul_by_cofactor during encoding, divide by it
136
     * here. However, the EdDSA base point is not the same as the decaf base
137
     * point if the sigma isogeny is in use: the EdDSA base point is on
138
     * Etwist_d/(1-d) and the decaf base point is on Etwist_d, and when
139
     * converted it effectively picks up a factor of 2 from the isogenies.  So
140
     * we might start at 2 instead of 1.
141
     */
142
75
    for (c = 1; c < C448_EDDSA_ENCODE_RATIO; c <<= 1)
143
50
        ossl_curve448_scalar_halve(secret_scalar, secret_scalar);
144
145
25
    ossl_curve448_precomputed_scalarmul(p, ossl_curve448_precomputed_base,
146
25
                                        secret_scalar);
147
148
25
    ossl_curve448_point_mul_by_ratio_and_encode_like_eddsa(pubkey, p);
149
150
    /* Cleanup */
151
25
    ossl_curve448_scalar_destroy(secret_scalar);
152
25
    ossl_curve448_point_destroy(p);
153
25
    OPENSSL_cleanse(secret_scalar_ser, sizeof(secret_scalar_ser));
154
155
25
    return C448_SUCCESS;
156
25
}
157
158
c448_error_t
159
ossl_c448_ed448_sign(OSSL_LIB_CTX *ctx,
160
                     uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
161
                     const uint8_t privkey[EDDSA_448_PRIVATE_BYTES],
162
                     const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
163
                     const uint8_t *message, size_t message_len,
164
                     uint8_t prehashed, const uint8_t *context,
165
                     size_t context_len, const char *propq)
166
0
{
167
0
    curve448_scalar_t secret_scalar;
168
0
    EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
169
0
    c448_error_t ret = C448_FAILURE;
170
0
    curve448_scalar_t nonce_scalar;
171
0
    uint8_t nonce_point[EDDSA_448_PUBLIC_BYTES] = { 0 };
172
0
    unsigned int c;
173
0
    curve448_scalar_t challenge_scalar;
174
175
0
    if (hashctx == NULL)
176
0
        return C448_FAILURE;
177
178
0
    {
179
        /*
180
         * Schedule the secret key, First EDDSA_448_PRIVATE_BYTES is serialized
181
         * secret scalar,next EDDSA_448_PRIVATE_BYTES bytes is the seed.
182
         */
183
0
        uint8_t expanded[EDDSA_448_PRIVATE_BYTES * 2];
184
185
0
        if (!oneshot_hash(ctx, expanded, sizeof(expanded), privkey,
186
0
                          EDDSA_448_PRIVATE_BYTES, propq))
187
0
            goto err;
188
0
        clamp(expanded);
189
0
        ossl_curve448_scalar_decode_long(secret_scalar, expanded,
190
0
                                         EDDSA_448_PRIVATE_BYTES);
191
192
        /* Hash to create the nonce */
193
0
        if (!hash_init_with_dom(ctx, hashctx, prehashed, 0, context,
194
0
                                context_len, propq)
195
0
                || !EVP_DigestUpdate(hashctx,
196
0
                                     expanded + EDDSA_448_PRIVATE_BYTES,
197
0
                                     EDDSA_448_PRIVATE_BYTES)
198
0
                || !EVP_DigestUpdate(hashctx, message, message_len)) {
199
0
            OPENSSL_cleanse(expanded, sizeof(expanded));
200
0
            goto err;
201
0
        }
202
0
        OPENSSL_cleanse(expanded, sizeof(expanded));
203
0
    }
204
205
    /* Decode the nonce */
206
0
    {
207
0
        uint8_t nonce[2 * EDDSA_448_PRIVATE_BYTES];
208
209
0
        if (!EVP_DigestFinalXOF(hashctx, nonce, sizeof(nonce)))
210
0
            goto err;
211
0
        ossl_curve448_scalar_decode_long(nonce_scalar, nonce, sizeof(nonce));
212
0
        OPENSSL_cleanse(nonce, sizeof(nonce));
213
0
    }
214
215
0
    {
216
        /* Scalarmul to create the nonce-point */
217
0
        curve448_scalar_t nonce_scalar_2;
218
0
        curve448_point_t p;
219
220
0
        ossl_curve448_scalar_halve(nonce_scalar_2, nonce_scalar);
221
0
        for (c = 2; c < C448_EDDSA_ENCODE_RATIO; c <<= 1)
222
0
            ossl_curve448_scalar_halve(nonce_scalar_2, nonce_scalar_2);
223
224
0
        ossl_curve448_precomputed_scalarmul(p, ossl_curve448_precomputed_base,
225
0
                                            nonce_scalar_2);
226
0
        ossl_curve448_point_mul_by_ratio_and_encode_like_eddsa(nonce_point, p);
227
0
        ossl_curve448_point_destroy(p);
228
0
        ossl_curve448_scalar_destroy(nonce_scalar_2);
229
0
    }
230
231
0
    {
232
0
        uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES];
233
234
        /* Compute the challenge */
235
0
        if (!hash_init_with_dom(ctx, hashctx, prehashed, 0, context, context_len,
236
0
                                propq)
237
0
                || !EVP_DigestUpdate(hashctx, nonce_point, sizeof(nonce_point))
238
0
                || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES)
239
0
                || !EVP_DigestUpdate(hashctx, message, message_len)
240
0
                || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge)))
241
0
            goto err;
242
243
0
        ossl_curve448_scalar_decode_long(challenge_scalar, challenge,
244
0
                                         sizeof(challenge));
245
0
        OPENSSL_cleanse(challenge, sizeof(challenge));
246
0
    }
247
248
0
    ossl_curve448_scalar_mul(challenge_scalar, challenge_scalar, secret_scalar);
249
0
    ossl_curve448_scalar_add(challenge_scalar, challenge_scalar, nonce_scalar);
250
251
0
    OPENSSL_cleanse(signature, EDDSA_448_SIGNATURE_BYTES);
252
0
    memcpy(signature, nonce_point, sizeof(nonce_point));
253
0
    ossl_curve448_scalar_encode(&signature[EDDSA_448_PUBLIC_BYTES],
254
0
                                challenge_scalar);
255
256
0
    ossl_curve448_scalar_destroy(secret_scalar);
257
0
    ossl_curve448_scalar_destroy(nonce_scalar);
258
0
    ossl_curve448_scalar_destroy(challenge_scalar);
259
260
0
    ret = C448_SUCCESS;
261
0
 err:
262
0
    EVP_MD_CTX_free(hashctx);
263
0
    return ret;
264
0
}
265
266
c448_error_t
267
ossl_c448_ed448_sign_prehash(
268
                        OSSL_LIB_CTX *ctx,
269
                        uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
270
                        const uint8_t privkey[EDDSA_448_PRIVATE_BYTES],
271
                        const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
272
                        const uint8_t hash[64], const uint8_t *context,
273
                        size_t context_len, const char *propq)
274
0
{
275
0
    return ossl_c448_ed448_sign(ctx, signature, privkey, pubkey, hash, 64, 1,
276
0
                                context, context_len, propq);
277
0
}
278
279
c448_error_t
280
ossl_c448_ed448_verify(
281
                    OSSL_LIB_CTX *ctx,
282
                    const uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
283
                    const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
284
                    const uint8_t *message, size_t message_len,
285
                    uint8_t prehashed, const uint8_t *context,
286
                    uint8_t context_len, const char *propq)
287
63
{
288
63
    curve448_point_t pk_point, r_point;
289
63
    c448_error_t error;
290
63
    curve448_scalar_t challenge_scalar;
291
63
    curve448_scalar_t response_scalar;
292
    /* Order in little endian format */
293
63
    static const uint8_t order[] = {
294
63
        0xF3, 0x44, 0x58, 0xAB, 0x92, 0xC2, 0x78, 0x23, 0x55, 0x8F, 0xC5, 0x8D,
295
63
        0x72, 0xC2, 0x6C, 0x21, 0x90, 0x36, 0xD6, 0xAE, 0x49, 0xDB, 0x4E, 0xC4,
296
63
        0xE9, 0x23, 0xCA, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
297
63
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
298
63
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00
299
63
    };
300
63
    int i;
301
302
    /*
303
     * Check that s (second 57 bytes of the sig) is less than the order. Both
304
     * s and the order are in little-endian format. This can be done in
305
     * variable time, since if this is not the case the signature if publicly
306
     * invalid.
307
     */
308
159
    for (i = EDDSA_448_PUBLIC_BYTES - 1; i >= 0; i--) {
309
159
        if (signature[i + EDDSA_448_PUBLIC_BYTES] > order[i])
310
2
            return C448_FAILURE;
311
157
        if (signature[i + EDDSA_448_PUBLIC_BYTES] < order[i])
312
61
            break;
313
157
    }
314
61
    if (i < 0)
315
0
        return C448_FAILURE;
316
317
61
    error =
318
61
        ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(pk_point, pubkey);
319
320
61
    if (C448_SUCCESS != error)
321
4
        return error;
322
323
57
    error =
324
57
        ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(r_point, signature);
325
57
    if (C448_SUCCESS != error)
326
2
        return error;
327
328
55
    {
329
        /* Compute the challenge */
330
55
        EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
331
55
        uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES];
332
333
55
        if (hashctx == NULL
334
55
                || !hash_init_with_dom(ctx, hashctx, prehashed, 0, context,
335
55
                                       context_len, propq)
336
55
                || !EVP_DigestUpdate(hashctx, signature, EDDSA_448_PUBLIC_BYTES)
337
55
                || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES)
338
55
                || !EVP_DigestUpdate(hashctx, message, message_len)
339
55
                || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge))) {
340
0
            EVP_MD_CTX_free(hashctx);
341
0
            return C448_FAILURE;
342
0
        }
343
344
55
        EVP_MD_CTX_free(hashctx);
345
55
        ossl_curve448_scalar_decode_long(challenge_scalar, challenge,
346
55
                                         sizeof(challenge));
347
55
        OPENSSL_cleanse(challenge, sizeof(challenge));
348
55
    }
349
0
    ossl_curve448_scalar_sub(challenge_scalar, ossl_curve448_scalar_zero,
350
55
                             challenge_scalar);
351
352
55
    ossl_curve448_scalar_decode_long(response_scalar,
353
55
                                     &signature[EDDSA_448_PUBLIC_BYTES],
354
55
                                     EDDSA_448_PRIVATE_BYTES);
355
356
    /* pk_point = -c(x(P)) + (cx + k)G = kG */
357
55
    ossl_curve448_base_double_scalarmul_non_secret(pk_point,
358
55
                                                   response_scalar,
359
55
                                                   pk_point, challenge_scalar);
360
55
    return c448_succeed_if(ossl_curve448_point_eq(pk_point, r_point));
361
55
}
362
363
c448_error_t
364
ossl_c448_ed448_verify_prehash(
365
                    OSSL_LIB_CTX *ctx,
366
                    const uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
367
                    const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
368
                    const uint8_t hash[64], const uint8_t *context,
369
                    uint8_t context_len, const char *propq)
370
0
{
371
0
    return ossl_c448_ed448_verify(ctx, signature, pubkey, hash, 64, 1, context,
372
0
                                  context_len, propq);
373
0
}
374
375
int
376
ossl_ed448_sign(OSSL_LIB_CTX *ctx, uint8_t *out_sig, const uint8_t *message,
377
                size_t message_len, const uint8_t public_key[57],
378
                const uint8_t private_key[57], const uint8_t *context,
379
                size_t context_len, const char *propq)
380
0
{
381
0
    return ossl_c448_ed448_sign(ctx, out_sig, private_key, public_key, message,
382
0
                                message_len, 0, context, context_len,
383
0
                                propq) == C448_SUCCESS;
384
0
}
385
386
int
387
ossl_ed448_verify(OSSL_LIB_CTX *ctx, const uint8_t *message, size_t message_len,
388
                  const uint8_t signature[114], const uint8_t public_key[57],
389
                  const uint8_t *context, size_t context_len, const char *propq)
390
63
{
391
63
    return ossl_c448_ed448_verify(ctx, signature, public_key, message,
392
63
                                  message_len, 0, context, (uint8_t)context_len,
393
63
                                  propq) == C448_SUCCESS;
394
63
}
395
396
int
397
ossl_ed448ph_sign(OSSL_LIB_CTX *ctx, uint8_t *out_sig, const uint8_t hash[64],
398
                  const uint8_t public_key[57], const uint8_t private_key[57],
399
                  const uint8_t *context, size_t context_len, const char *propq)
400
0
{
401
0
    return ossl_c448_ed448_sign_prehash(ctx, out_sig, private_key, public_key,
402
0
                                        hash, context, context_len,
403
0
                                        propq) == C448_SUCCESS;
404
0
}
405
406
int
407
ossl_ed448ph_verify(OSSL_LIB_CTX *ctx, const uint8_t hash[64],
408
                    const uint8_t signature[114], const uint8_t public_key[57],
409
                    const uint8_t *context, size_t context_len,
410
                    const char *propq)
411
0
{
412
0
    return ossl_c448_ed448_verify_prehash(ctx, signature, public_key, hash,
413
0
                                          context, (uint8_t)context_len,
414
0
                                          propq) == C448_SUCCESS;
415
0
}
416
417
int
418
ossl_ed448_public_from_private(OSSL_LIB_CTX *ctx, uint8_t out_public_key[57],
419
                               const uint8_t private_key[57], const char *propq)
420
25
{
421
25
    return ossl_c448_ed448_derive_public_key(ctx, out_public_key, private_key,
422
25
                                             propq) == C448_SUCCESS;
423
25
}