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