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 ¶ms)
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 ¶ms)
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 ¶ms=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 ¶ms)
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 ¶ms)
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