Coverage Report

Created: 2024-11-21 07:03

/src/cryptopp/xed25519.cpp
Line
Count
Source (jump to first uncovered line)
1
// xed25519.cpp - written and placed in public domain by Jeffrey Walton
2
//                Crypto++ specific implementation wrapped around Andrew
3
//                Moon's public domain curve25519-donna and ed25519-donna,
4
//                https://github.com/floodyberry/curve25519-donna and
5
//                https://github.com/floodyberry/ed25519-donna.
6
7
#include "pch.h"
8
9
#include "cryptlib.h"
10
#include "asn.h"
11
#include "integer.h"
12
#include "filters.h"
13
#include "stdcpp.h"
14
15
#include "xed25519.h"
16
#include "donna.h"
17
18
ANONYMOUS_NAMESPACE_BEGIN
19
20
using CryptoPP::byte;
21
22
CRYPTOPP_ALIGN_DATA(16)
23
const byte blacklist[][32] = {
24
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
26
    { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
28
    { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
29
      0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 },
30
    { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
31
      0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 },
32
    { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
34
    { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
35
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
36
    { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
37
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
38
    { 0xcd, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
39
      0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x80 },
40
    { 0x4c, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
41
      0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7 },
42
    { 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
44
    { 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
46
    { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
48
};
49
50
bool HasSmallOrder(const byte y[32])
51
0
{
52
    // The magic 12 is the count of blaklisted points
53
0
    byte c[12] = { 0 };
54
0
    for (size_t j = 0; j < 32; j++) {
55
0
        for (size_t i = 0; i < COUNTOF(blacklist); i++) {
56
0
            c[i] |= y[j] ^ blacklist[i][j];
57
0
        }
58
0
    }
59
60
0
    unsigned int k = 0;
61
0
    for (size_t i = 0; i < COUNTOF(blacklist); i++) {
62
0
        k |= (c[i] - 1);
63
0
    }
64
65
0
    return (bool)((k >> 8) & 1);
66
0
}
67
68
ANONYMOUS_NAMESPACE_END
69
70
NAMESPACE_BEGIN(CryptoPP)
71
72
// ******************** x25519 Agreement ************************* //
73
74
x25519::x25519(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH])
75
0
{
76
0
    std::memcpy(m_pk, y, PUBLIC_KEYLENGTH);
77
0
    std::memcpy(m_sk, x, SECRET_KEYLENGTH);
78
79
0
    CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
80
0
    CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
81
0
}
Unexecuted instantiation: CryptoPP::x25519::x25519(unsigned char const*, unsigned char const*)
Unexecuted instantiation: CryptoPP::x25519::x25519(unsigned char const*, unsigned char const*)
82
83
x25519::x25519(const byte x[SECRET_KEYLENGTH])
84
0
{
85
0
    std::memcpy(m_sk, x, SECRET_KEYLENGTH);
86
0
    Donna::curve25519_mult(m_pk, m_sk);
87
88
0
    CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
89
0
    CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
90
0
}
Unexecuted instantiation: CryptoPP::x25519::x25519(unsigned char const*)
Unexecuted instantiation: CryptoPP::x25519::x25519(unsigned char const*)
91
92
x25519::x25519(const Integer &y, const Integer &x)
93
0
{
94
0
    CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH);
95
0
    CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
96
97
0
    y.Encode(m_pk, PUBLIC_KEYLENGTH); std::reverse(m_pk+0, m_pk+PUBLIC_KEYLENGTH);
98
0
    x.Encode(m_sk, SECRET_KEYLENGTH); std::reverse(m_sk+0, m_sk+SECRET_KEYLENGTH);
99
100
0
    CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
101
0
    CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
102
0
}
Unexecuted instantiation: CryptoPP::x25519::x25519(CryptoPP::Integer const&, CryptoPP::Integer const&)
Unexecuted instantiation: CryptoPP::x25519::x25519(CryptoPP::Integer const&, CryptoPP::Integer const&)
103
104
x25519::x25519(const Integer &x)
105
0
{
106
0
    CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
107
108
0
    x.Encode(m_sk, SECRET_KEYLENGTH);
109
0
    std::reverse(m_sk+0, m_sk+SECRET_KEYLENGTH);
110
0
    Donna::curve25519_mult(m_pk, m_sk);
111
112
0
    CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
113
0
    CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
114
0
}
Unexecuted instantiation: CryptoPP::x25519::x25519(CryptoPP::Integer const&)
Unexecuted instantiation: CryptoPP::x25519::x25519(CryptoPP::Integer const&)
115
116
x25519::x25519(RandomNumberGenerator &rng)
117
0
{
118
0
    rng.GenerateBlock(m_sk, SECRET_KEYLENGTH);
119
0
    ClampKey(m_sk);
120
0
    SecretToPublicKey(m_pk, m_sk);
121
0
}
Unexecuted instantiation: CryptoPP::x25519::x25519(CryptoPP::RandomNumberGenerator&)
Unexecuted instantiation: CryptoPP::x25519::x25519(CryptoPP::RandomNumberGenerator&)
122
123
x25519::x25519(BufferedTransformation &params)
124
0
{
125
0
    Load(params);
126
0
}
Unexecuted instantiation: CryptoPP::x25519::x25519(CryptoPP::BufferedTransformation&)
Unexecuted instantiation: CryptoPP::x25519::x25519(CryptoPP::BufferedTransformation&)
127
128
void x25519::ClampKey(byte x[SECRET_KEYLENGTH]) const
129
0
{
130
0
    x[0] &= 248; x[31] &= 127; x[31] |= 64;
131
0
}
132
133
bool x25519::IsClamped(const byte x[SECRET_KEYLENGTH]) const
134
0
{
135
0
    return (x[0] & 248) == x[0] && (x[31] & 127) == x[31] && (x[31] | 64) == x[31];
136
0
}
137
138
bool x25519::IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const
139
0
{
140
0
    return HasSmallOrder(y);
141
0
}
142
143
void x25519::SecretToPublicKey(byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) const
144
28
{
145
28
    Donna::curve25519_mult(y, x);
146
28
}
147
148
void x25519::BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt)
149
0
{
150
    // We have not yet determined the OID to use for this object.
151
    // We can't use OID's decoder because it throws BERDecodeError
152
    // if the OIDs do not match.
153
0
    OID oid(bt);
154
155
    // 1.3.6.1.4.1.3029.1.5.1/curvey25519 from Cryptlib used by OpenPGP.
156
    // https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-rfc4880bis
157
0
    if (!m_oid.Empty() && m_oid != oid)
158
0
        BERDecodeError();  // Only accept user specified OID
159
0
    else if (oid == ASN1::curve25519() || oid == ASN1::X25519() ||
160
0
        oid == OID(1)+3+6+1+4+1+3029+1+5)
161
0
        m_oid = oid;  // Accept any of the x25519 OIDs
162
0
    else
163
0
        BERDecodeError();
164
0
}
165
166
void x25519::BERDecode(BufferedTransformation &bt)
167
0
{
168
    // https://tools.ietf.org/html/rfc8410, section 7 and
169
    // https://www.cryptopp.com/wiki/curve25519_keys
170
0
    BERSequenceDecoder privateKeyInfo(bt);
171
0
        word32 version;
172
0
        BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 1);    // check version
173
174
0
        BERSequenceDecoder algorithm(privateKeyInfo);
175
            // GetAlgorithmID().BERDecodeAndCheck(algorithm);
176
0
            BERDecodeAndCheckAlgorithmID(algorithm);
177
0
        algorithm.MessageEnd();
178
179
0
        BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
180
0
            BERDecodePrivateKey(octetString, false, (size_t)privateKeyInfo.RemainingLength());
181
0
        octetString.MessageEnd();
182
183
        // publicKey [1] IMPLICIT PublicKey OPTIONAL
184
0
        bool generatePublicKey = true;
185
0
        if (privateKeyInfo.EndReached() == false /*version == 1?*/)
186
0
        {
187
            // Should we test this before decoding? In either case we
188
            // just throw a BERDecodeErr() when we can't parse it.
189
0
            BERGeneralDecoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
190
0
            SecByteBlock subjectPublicKey;
191
0
            unsigned int unusedBits;
192
0
            BERDecodeBitString(publicKey, subjectPublicKey, unusedBits);
193
0
                CRYPTOPP_ASSERT(unusedBits == 0);
194
0
                CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
195
0
                if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
196
0
                    BERDecodeError();
197
0
                std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
198
0
                generatePublicKey = false;
199
0
            publicKey.MessageEnd();
200
0
        }
201
202
0
    privateKeyInfo.MessageEnd();
203
204
0
    if (generatePublicKey)
205
0
        Donna::curve25519_mult(m_pk, m_sk);
206
207
0
    CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
208
0
    CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
209
0
}
210
211
void x25519::DEREncode(BufferedTransformation &bt, int version) const
212
0
{
213
    // https://tools.ietf.org/html/rfc8410, section 7 and
214
    // https://www.cryptopp.com/wiki/curve25519_keys
215
0
    CRYPTOPP_ASSERT(version == 0 || version == 1);
216
217
0
    DERSequenceEncoder privateKeyInfo(bt);
218
0
        DEREncodeUnsigned<word32>(privateKeyInfo, version);
219
220
0
        DERSequenceEncoder algorithm(privateKeyInfo);
221
0
            GetAlgorithmID().DEREncode(algorithm);
222
0
        algorithm.MessageEnd();
223
224
0
        DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
225
0
            DEREncodePrivateKey(octetString);
226
0
        octetString.MessageEnd();
227
228
0
        if (version == 1)
229
0
        {
230
0
            DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
231
0
                DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH);
232
0
            publicKey.MessageEnd();
233
0
        }
234
235
0
    privateKeyInfo.MessageEnd();
236
0
}
237
238
void x25519::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
239
0
{
240
    // https://tools.ietf.org/html/rfc8410 and
241
    // https://www.cryptopp.com/wiki/curve25519_keys
242
243
0
    BERGeneralDecoder privateKey(bt, OCTET_STRING);
244
245
0
        if (!privateKey.IsDefiniteLength())
246
0
            BERDecodeError();
247
248
0
        size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH);
249
0
        if (size != SECRET_KEYLENGTH)
250
0
            BERDecodeError();
251
252
        // We don't know how to decode them
253
0
        if (parametersPresent)
254
0
            BERDecodeError();
255
256
0
    privateKey.MessageEnd();
257
0
}
258
259
void x25519::DEREncodePrivateKey(BufferedTransformation &bt) const
260
0
{
261
    // https://tools.ietf.org/html/rfc8410
262
0
    DERGeneralEncoder privateKey(bt, OCTET_STRING);
263
0
        privateKey.Put(m_sk, SECRET_KEYLENGTH);
264
0
    privateKey.MessageEnd();
265
0
}
266
267
bool x25519::Validate(RandomNumberGenerator &rng, unsigned int level) const
268
0
{
269
0
    CRYPTOPP_UNUSED(rng);
270
0
    CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
271
0
    CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
272
273
0
    if (level >= 1 && IsClamped(m_sk) == false)
274
0
        return false;
275
0
    if (level >= 2 && IsSmallOrder(m_pk) == true)
276
0
        return false;
277
0
    if (level >= 3)
278
0
    {
279
        // Verify m_pk is pairwise consistent with m_sk
280
0
        SecByteBlock pk(PUBLIC_KEYLENGTH);
281
0
        SecretToPublicKey(pk, m_sk);
282
283
0
        if (VerifyBufsEqual(pk, m_pk, PUBLIC_KEYLENGTH) == false)
284
0
            return false;
285
0
    }
286
287
0
    return true;
288
0
}
289
290
bool x25519::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
291
0
{
292
0
    if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0)
293
0
    {
294
0
        this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
295
0
        reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false);
296
0
        return true;
297
0
    }
298
299
0
    if (std::strcmp(name, Name::PublicElement()) == 0)
300
0
    {
301
0
        this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
302
0
        reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
303
0
        return true;
304
0
    }
305
306
0
    if (std::strcmp(name, Name::GroupOID()) == 0)
307
0
    {
308
0
        if (m_oid.Empty())
309
0
            return false;
310
311
0
        this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
312
0
        *reinterpret_cast<OID *>(pValue) = m_oid;
313
0
        return true;
314
0
    }
315
316
0
    return false;
317
0
}
318
319
void x25519::AssignFrom(const NameValuePairs &source)
320
0
{
321
0
    ConstByteArrayParameter val;
322
0
    if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val))
323
0
    {
324
0
        std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH);
325
0
    }
326
327
0
    if (source.GetValue(Name::PublicElement(), val))
328
0
    {
329
0
        std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH);
330
0
    }
331
332
0
    OID oid;
333
0
    if (source.GetValue(Name::GroupOID(), oid))
334
0
    {
335
0
        m_oid = oid;
336
0
    }
337
338
0
    bool derive = false;
339
0
    if (source.GetValue("DerivePublicKey", derive) && derive == true)
340
0
        SecretToPublicKey(m_pk, m_sk);
341
0
}
342
343
void x25519::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params)
344
0
{
345
0
    ConstByteArrayParameter seed;
346
0
    if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy())
347
0
        rng.IncorporateEntropy(seed.begin(), seed.size());
348
349
0
    rng.GenerateBlock(m_sk, SECRET_KEYLENGTH);
350
0
    ClampKey(m_sk);
351
0
    SecretToPublicKey(m_pk, m_sk);
352
0
}
353
354
void x25519::GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
355
0
{
356
0
    rng.GenerateBlock(privateKey, SECRET_KEYLENGTH);
357
0
    ClampKey(privateKey);
358
0
}
359
360
void x25519::GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
361
28
{
362
28
    CRYPTOPP_UNUSED(rng);
363
28
    SecretToPublicKey(publicKey, privateKey);
364
28
}
365
366
bool x25519::Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey) const
367
0
{
368
0
    CRYPTOPP_ASSERT(agreedValue != NULLPTR);
369
0
    CRYPTOPP_ASSERT(otherPublicKey != NULLPTR);
370
371
0
    if (validateOtherPublicKey && IsSmallOrder(otherPublicKey))
372
0
        return false;
373
374
0
    return Donna::curve25519_mult(agreedValue, privateKey, otherPublicKey) == 0;
375
0
}
376
377
// ******************** ed25519 Signer ************************* //
378
379
void ed25519PrivateKey::SecretToPublicKey(byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) const
380
0
{
381
0
    int ret = Donna::ed25519_publickey(y, x);
382
0
    CRYPTOPP_ASSERT(ret == 0); CRYPTOPP_UNUSED(ret);
383
0
}
384
385
bool ed25519PrivateKey::IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const
386
0
{
387
0
    return HasSmallOrder(y);
388
0
}
389
390
bool ed25519PrivateKey::Validate(RandomNumberGenerator &rng, unsigned int level) const
391
0
{
392
0
    CRYPTOPP_UNUSED(rng);
393
0
    CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
394
395
0
    if (level >= 1 && IsSmallOrder(m_pk) == true)
396
0
        return false;
397
0
    if (level >= 3)
398
0
    {
399
        // Verify m_pk is pairwise consistent with m_sk
400
0
        SecByteBlock pk(PUBLIC_KEYLENGTH);
401
0
        SecretToPublicKey(pk, m_sk);
402
403
0
        if (VerifyBufsEqual(pk, m_pk, PUBLIC_KEYLENGTH) == false)
404
0
            return false;
405
0
    }
406
407
0
    return true;
408
0
}
409
410
bool ed25519PrivateKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
411
0
{
412
0
     if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0)
413
0
     {
414
0
        this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
415
0
        reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false);
416
0
        return true;
417
0
    }
418
419
0
    if (std::strcmp(name, Name::PublicElement()) == 0)
420
0
    {
421
0
        this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
422
0
        reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
423
0
        return true;
424
0
    }
425
426
0
    if (std::strcmp(name, Name::GroupOID()) == 0)
427
0
    {
428
0
        if (m_oid.Empty())
429
0
            return false;
430
431
0
        this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
432
0
        *reinterpret_cast<OID *>(pValue) = m_oid;
433
0
        return true;
434
0
    }
435
436
0
    return false;
437
0
}
438
439
void ed25519PrivateKey::AssignFrom(const NameValuePairs &source)
440
0
{
441
0
    ConstByteArrayParameter val;
442
0
    if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val))
443
0
    {
444
0
        CRYPTOPP_ASSERT(val.size() == SECRET_KEYLENGTH);
445
0
        std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH);
446
0
    }
447
0
    if (source.GetValue(Name::PublicElement(), val))
448
0
    {
449
0
        CRYPTOPP_ASSERT(val.size() == PUBLIC_KEYLENGTH);
450
0
        std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH);
451
0
    }
452
453
0
    OID oid;
454
0
    if (source.GetValue(Name::GroupOID(), oid))
455
0
    {
456
0
        m_oid = oid;
457
0
    }
458
459
0
    bool derive = false;
460
0
    if (source.GetValue("DerivePublicKey", derive) && derive == true)
461
0
        SecretToPublicKey(m_pk, m_sk);
462
463
0
    CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
464
0
}
465
466
void ed25519PrivateKey::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params=g_nullNameValuePairs)
467
0
{
468
0
    ConstByteArrayParameter seed;
469
0
    if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy())
470
0
        rng.IncorporateEntropy(seed.begin(), seed.size());
471
472
0
    rng.GenerateBlock(m_sk, SECRET_KEYLENGTH);
473
0
    int ret = Donna::ed25519_publickey(m_pk, m_sk);
474
0
    CRYPTOPP_ASSERT(ret == 0); CRYPTOPP_UNUSED(ret);
475
0
}
476
477
void ed25519PrivateKey::MakePublicKey (PublicKey &pub) const
478
0
{
479
0
    pub.AssignFrom(MakeParameters
480
0
        (Name::PublicElement(), ConstByteArrayParameter(m_pk.begin(), PUBLIC_KEYLENGTH))
481
0
        (Name::GroupOID(), GetAlgorithmID()));
482
0
}
483
484
void ed25519PrivateKey::BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt)
485
0
{
486
    // We have not yet determined the OID to use for this object.
487
    // We can't use OID's decoder because it throws BERDecodeError
488
    // if the OIDs do not match.
489
0
    OID oid(bt);
490
491
0
    if (!m_oid.Empty() && m_oid != oid)
492
0
        BERDecodeError();  // Only accept user specified OID
493
0
    else if (oid == ASN1::curve25519() || oid == ASN1::Ed25519())
494
0
        m_oid = oid;  // Accept any of the ed25519PrivateKey OIDs
495
0
    else
496
0
        BERDecodeError();
497
0
}
498
499
void ed25519PrivateKey::BERDecode(BufferedTransformation &bt)
500
0
{
501
    // https://tools.ietf.org/html/rfc8410, section 7 and
502
    // https://www.cryptopp.com/wiki/curve25519_keys
503
0
    BERSequenceDecoder privateKeyInfo(bt);
504
0
        word32 version;
505
0
        BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 1);    // check version
506
507
0
        BERSequenceDecoder algorithm(privateKeyInfo);
508
            // GetAlgorithmID().BERDecodeAndCheck(algorithm);
509
0
            BERDecodeAndCheckAlgorithmID(algorithm);
510
0
        algorithm.MessageEnd();
511
512
0
        BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
513
0
            BERDecodePrivateKey(octetString, false, (size_t)privateKeyInfo.RemainingLength());
514
0
        octetString.MessageEnd();
515
516
        // publicKey [1] IMPLICIT PublicKey OPTIONAL
517
0
        bool generatePublicKey = true;
518
0
        if (privateKeyInfo.EndReached() == false /*version == 1?*/)
519
0
        {
520
            // Should we test this before decoding? In either case we
521
            // just throw a BERDecodeErr() when we can't parse it.
522
0
            BERGeneralDecoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
523
0
            SecByteBlock subjectPublicKey;
524
0
            unsigned int unusedBits;
525
0
            BERDecodeBitString(publicKey, subjectPublicKey, unusedBits);
526
0
                CRYPTOPP_ASSERT(unusedBits == 0);
527
0
                CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
528
0
                if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
529
0
                    BERDecodeError();
530
0
                std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
531
0
                generatePublicKey = false;
532
0
            publicKey.MessageEnd();
533
0
        }
534
535
0
    privateKeyInfo.MessageEnd();
536
537
0
    if (generatePublicKey)
538
0
        Donna::ed25519_publickey(m_pk, m_sk);
539
540
0
    CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
541
0
}
542
543
void ed25519PrivateKey::DEREncode(BufferedTransformation &bt, int version) const
544
0
{
545
    // https://tools.ietf.org/html/rfc8410, section 7 and
546
    // https://www.cryptopp.com/wiki/curve25519_keys
547
0
    CRYPTOPP_ASSERT(version == 0 || version == 1);
548
549
0
    DERSequenceEncoder privateKeyInfo(bt);
550
0
        DEREncodeUnsigned<word32>(privateKeyInfo, version);
551
552
0
        DERSequenceEncoder algorithm(privateKeyInfo);
553
0
            GetAlgorithmID().DEREncode(algorithm);
554
0
        algorithm.MessageEnd();
555
556
0
        DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
557
0
            DEREncodePrivateKey(octetString);
558
0
        octetString.MessageEnd();
559
560
0
        if (version == 1)
561
0
        {
562
0
            DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
563
0
                DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH);
564
0
            publicKey.MessageEnd();
565
0
        }
566
567
0
    privateKeyInfo.MessageEnd();
568
0
}
569
570
void ed25519PrivateKey::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
571
0
{
572
    // https://tools.ietf.org/html/rfc8410 and
573
    // https://www.cryptopp.com/wiki/curve25519_keys
574
575
0
    BERGeneralDecoder privateKey(bt, OCTET_STRING);
576
577
0
        if (!privateKey.IsDefiniteLength())
578
0
            BERDecodeError();
579
580
0
        size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH);
581
0
        if (size != SECRET_KEYLENGTH)
582
0
            BERDecodeError();
583
584
        // We don't know how to decode them
585
0
        if (parametersPresent)
586
0
            BERDecodeError();
587
588
0
    privateKey.MessageEnd();
589
0
}
590
591
void ed25519PrivateKey::DEREncodePrivateKey(BufferedTransformation &bt) const
592
0
{
593
    // https://tools.ietf.org/html/rfc8410
594
0
    DERGeneralEncoder privateKey(bt, OCTET_STRING);
595
0
        privateKey.Put(m_sk, SECRET_KEYLENGTH);
596
0
    privateKey.MessageEnd();
597
0
}
598
599
void ed25519PrivateKey::SetPrivateExponent (const byte x[SECRET_KEYLENGTH])
600
0
{
601
0
    AssignFrom(MakeParameters
602
0
        (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH))
603
0
        ("DerivePublicKey", true));
604
0
}
605
606
void ed25519PrivateKey::SetPrivateExponent (const Integer &x)
607
0
{
608
0
    CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
609
610
0
    SecByteBlock bx(SECRET_KEYLENGTH);
611
0
    x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
612
613
0
    AssignFrom(MakeParameters
614
0
        (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false))
615
0
        ("DerivePublicKey", true));
616
0
}
617
618
const Integer& ed25519PrivateKey::GetPrivateExponent() const
619
0
{
620
0
    m_x = Integer(m_sk, SECRET_KEYLENGTH, Integer::UNSIGNED, LITTLE_ENDIAN_ORDER);
621
0
    return m_x;
622
0
}
623
624
////////////////////////
625
626
ed25519Signer::ed25519Signer(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH])
627
0
{
628
0
    AccessPrivateKey().AssignFrom(MakeParameters
629
0
        (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH, false))
630
0
        (Name::PublicElement(), ConstByteArrayParameter(y, PUBLIC_KEYLENGTH, false)));
631
0
}
632
633
ed25519Signer::ed25519Signer(const byte x[SECRET_KEYLENGTH])
634
0
{
635
0
    AccessPrivateKey().AssignFrom(MakeParameters
636
0
        (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH, false))
637
0
        ("DerivePublicKey", true));
638
0
}
639
640
ed25519Signer::ed25519Signer(const Integer &y, const Integer &x)
641
0
{
642
0
    CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH);
643
0
    CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
644
645
0
    SecByteBlock by(PUBLIC_KEYLENGTH), bx(SECRET_KEYLENGTH);
646
0
    y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
647
0
    x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
648
649
0
    AccessPrivateKey().AssignFrom(MakeParameters
650
0
        (Name::PublicElement(), ConstByteArrayParameter(by, PUBLIC_KEYLENGTH, false))
651
0
        (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false)));
652
0
}
653
654
ed25519Signer::ed25519Signer(const Integer &x)
655
0
{
656
0
    CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
657
658
0
    SecByteBlock bx(SECRET_KEYLENGTH);
659
0
    x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
660
661
0
    AccessPrivateKey().AssignFrom(MakeParameters
662
0
        (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false))
663
0
        ("DerivePublicKey", true));
664
0
}
665
666
ed25519Signer::ed25519Signer(const PKCS8PrivateKey &key)
667
0
{
668
    // Load all fields from the other key
669
0
    ByteQueue queue;
670
0
    key.Save(queue);
671
0
    AccessPrivateKey().Load(queue);
672
0
}
673
674
ed25519Signer::ed25519Signer(RandomNumberGenerator &rng)
675
0
{
676
0
    AccessPrivateKey().GenerateRandom(rng);
677
0
}
678
679
ed25519Signer::ed25519Signer(BufferedTransformation &params)
680
0
{
681
0
    AccessPrivateKey().Load(params);
682
0
}
683
684
size_t ed25519Signer::SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const
685
0
{
686
0
    CRYPTOPP_ASSERT(signature != NULLPTR); CRYPTOPP_UNUSED(rng);
687
688
0
    ed25519_MessageAccumulator& accum = dynamic_cast<ed25519_MessageAccumulator&>(messageAccumulator);
689
0
    const ed25519PrivateKey& pk = dynamic_cast<const ed25519PrivateKey&>(GetPrivateKey());
690
0
    int ret = Donna::ed25519_sign(accum.data(), accum.size(), pk.GetPrivateKeyBytePtr(), pk.GetPublicKeyBytePtr(), signature);
691
0
    CRYPTOPP_ASSERT(ret == 0);
692
693
0
    if (restart)
694
0
        accum.Restart();
695
696
0
    return ret == 0 ? SIGNATURE_LENGTH : 0;
697
0
}
698
699
size_t ed25519Signer::SignStream (RandomNumberGenerator &rng, std::istream& stream, byte *signature) const
700
0
{
701
0
    CRYPTOPP_ASSERT(signature != NULLPTR); CRYPTOPP_UNUSED(rng);
702
703
0
    const ed25519PrivateKey& pk = dynamic_cast<const ed25519PrivateKey&>(GetPrivateKey());
704
0
    int ret = Donna::ed25519_sign(stream, pk.GetPrivateKeyBytePtr(), pk.GetPublicKeyBytePtr(), signature);
705
0
    CRYPTOPP_ASSERT(ret == 0);
706
707
0
    return ret == 0 ? SIGNATURE_LENGTH : 0;
708
0
}
709
710
// ******************** ed25519 Verifier ************************* //
711
712
bool ed25519PublicKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
713
0
{
714
0
    if (std::strcmp(name, Name::PublicElement()) == 0)
715
0
    {
716
0
        this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
717
0
        reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
718
0
        return true;
719
0
    }
720
721
0
    if (std::strcmp(name, Name::GroupOID()) == 0)
722
0
    {
723
0
        if (m_oid.Empty())
724
0
            return false;
725
726
0
        this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
727
0
        *reinterpret_cast<OID *>(pValue) = m_oid;
728
0
        return true;
729
0
    }
730
731
0
    return false;
732
0
}
733
734
void ed25519PublicKey::AssignFrom(const NameValuePairs &source)
735
0
{
736
0
    ConstByteArrayParameter ba;
737
0
    if (source.GetValue(Name::PublicElement(), ba))
738
0
    {
739
0
        std::memcpy(m_pk, ba.begin(), PUBLIC_KEYLENGTH);
740
0
    }
741
742
0
    OID oid;
743
0
    if (source.GetValue(Name::GroupOID(), oid))
744
0
    {
745
0
        m_oid = oid;
746
0
    }
747
0
}
748
749
void ed25519PublicKey::BERDecodeAndCheckAlgorithmID(BufferedTransformation& bt)
750
0
{
751
    // We have not yet determined the OID to use for this object.
752
    // We can't use OID's decoder because it throws BERDecodeError
753
    // if the OIDs do not match.
754
0
    OID oid(bt);
755
756
0
    if (!m_oid.Empty() && m_oid != oid)
757
0
        BERDecodeError();  // Only accept user specified OID
758
0
    else if (oid == ASN1::curve25519() || oid == ASN1::Ed25519())
759
0
        m_oid = oid;  // Accept any of the ed25519PublicKey OIDs
760
0
    else
761
0
        BERDecodeError();
762
0
}
763
764
void ed25519PublicKey::BERDecode(BufferedTransformation &bt)
765
0
{
766
0
    BERSequenceDecoder publicKeyInfo(bt);
767
768
0
        BERSequenceDecoder algorithm(publicKeyInfo);
769
            // GetAlgorithmID().BERDecodeAndCheck(algorithm);
770
0
            BERDecodeAndCheckAlgorithmID(algorithm);
771
0
        algorithm.MessageEnd();
772
773
0
        BERDecodePublicKey(publicKeyInfo, false, (size_t)publicKeyInfo.RemainingLength());
774
775
0
    publicKeyInfo.MessageEnd();
776
0
}
777
778
void ed25519PublicKey::DEREncode(BufferedTransformation &bt) const
779
0
{
780
0
    DERSequenceEncoder publicKeyInfo(bt);
781
782
0
        DERSequenceEncoder algorithm(publicKeyInfo);
783
0
            GetAlgorithmID().DEREncode(algorithm);
784
0
        algorithm.MessageEnd();
785
786
0
        DEREncodePublicKey(publicKeyInfo);
787
788
0
    publicKeyInfo.MessageEnd();
789
0
}
790
791
void ed25519PublicKey::BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
792
0
{
793
    // We don't know how to decode them
794
0
    if (parametersPresent)
795
0
        BERDecodeError();
796
797
0
    SecByteBlock subjectPublicKey;
798
0
    unsigned int unusedBits;
799
0
    BERDecodeBitString(bt, subjectPublicKey, unusedBits);
800
801
0
    CRYPTOPP_ASSERT(unusedBits == 0);
802
0
    CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
803
0
    if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
804
0
        BERDecodeError();
805
806
0
    std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
807
0
}
808
809
void ed25519PublicKey::DEREncodePublicKey(BufferedTransformation &bt) const
810
0
{
811
0
    DEREncodeBitString(bt, m_pk, PUBLIC_KEYLENGTH);
812
0
}
813
814
void ed25519PublicKey::SetPublicElement (const byte y[PUBLIC_KEYLENGTH])
815
0
{
816
0
    std::memcpy(m_pk, y, PUBLIC_KEYLENGTH);
817
0
}
818
819
void ed25519PublicKey::SetPublicElement (const Integer &y)
820
0
{
821
0
    CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH);
822
823
0
    SecByteBlock by(PUBLIC_KEYLENGTH);
824
0
    y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
825
826
0
    std::memcpy(m_pk, by, PUBLIC_KEYLENGTH);
827
0
}
828
829
const Integer& ed25519PublicKey::GetPublicElement() const
830
0
{
831
0
    m_y = Integer(m_pk, PUBLIC_KEYLENGTH, Integer::UNSIGNED, LITTLE_ENDIAN_ORDER);
832
0
    return m_y;
833
0
}
834
835
bool ed25519PublicKey::Validate(RandomNumberGenerator &rng, unsigned int level) const
836
0
{
837
0
    CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(level);
838
0
    return true;
839
0
}
840
841
////////////////////////
842
843
ed25519Verifier::ed25519Verifier(const byte y[PUBLIC_KEYLENGTH])
844
0
{
845
0
    AccessPublicKey().AssignFrom(MakeParameters
846
0
        (Name::PublicElement(), ConstByteArrayParameter(y, PUBLIC_KEYLENGTH)));
847
0
}
848
849
ed25519Verifier::ed25519Verifier(const Integer &y)
850
0
{
851
0
    CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH);
852
853
0
    SecByteBlock by(PUBLIC_KEYLENGTH);
854
0
    y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
855
856
0
    AccessPublicKey().AssignFrom(MakeParameters
857
0
        (Name::PublicElement(), ConstByteArrayParameter(by, PUBLIC_KEYLENGTH, false)));
858
0
}
859
860
ed25519Verifier::ed25519Verifier(const X509PublicKey &key)
861
0
{
862
    // Load all fields from the other key
863
0
    ByteQueue queue;
864
0
    key.Save(queue);
865
0
    AccessPublicKey().Load(queue);
866
0
}
867
868
ed25519Verifier::ed25519Verifier(BufferedTransformation &params)
869
0
{
870
0
    AccessPublicKey().Load(params);
871
0
}
872
873
ed25519Verifier::ed25519Verifier(const ed25519Signer& signer)
874
0
{
875
0
    const ed25519PrivateKey& priv = dynamic_cast<const ed25519PrivateKey&>(signer.GetPrivateKey());
876
0
    priv.MakePublicKey(AccessPublicKey());
877
0
}
878
879
bool ed25519Verifier::VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const
880
0
{
881
0
    ed25519_MessageAccumulator& accum = static_cast<ed25519_MessageAccumulator&>(messageAccumulator);
882
0
    const ed25519PublicKey& pk = dynamic_cast<const ed25519PublicKey&>(GetPublicKey());
883
0
    int ret = Donna::ed25519_sign_open(accum.data(), accum.size(), pk.GetPublicKeyBytePtr(), accum.signature());
884
0
    accum.Restart();
885
886
0
    return ret == 0;
887
0
}
888
889
bool ed25519Verifier::VerifyStream(std::istream& stream, const byte *signature, size_t signatureLen) const
890
0
{
891
0
    CRYPTOPP_ASSERT(signatureLen == SIGNATURE_LENGTH);
892
0
    CRYPTOPP_UNUSED(signatureLen);
893
894
0
    const ed25519PublicKey& pk = static_cast<const ed25519PublicKey&>(GetPublicKey());
895
0
    int ret = Donna::ed25519_sign_open(stream, pk.GetPublicKeyBytePtr(), signature);
896
897
0
    return ret == 0;
898
0
}
899
900
NAMESPACE_END  // CryptoPP