Crypto++  8.0
Free C++ class library of cryptographic schemes
xed25519.cpp
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 {
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 
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, SECRET_KEYLENGTH);
77  std::memcpy(m_sk, x, PUBLIC_KEYLENGTH);
78 
79  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
80  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
81 }
82 
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 
92 x25519::x25519(const Integer &y, const Integer &x)
93 {
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 
105 {
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 
117 {
118  rng.GenerateBlock(m_sk, SECRET_KEYLENGTH);
119  m_sk[0] &= 248; m_sk[31] &= 127; m_sk[31] |= 64;
120  Donna::curve25519_mult(m_pk, m_sk);
121 }
122 
124 {
125  Load(params);
126 }
127 
129 {
130  x[0] &= 248; x[31] &= 127; x[31] |= 64;
132 }
133 
134 bool x25519::IsClamped(const byte x[SECRET_KEYLENGTH]) const
135 {
136  return (x[0] & 248) == x[0] && (x[31] & 127) == x[31] && (x[31] | 64) == x[31];
137 }
138 
139 bool x25519::IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const
140 {
141  return HasSmallOrder(y);
142 }
143 
145 {
146  // We have not yet determined the OID to use for this object.
147  // We can't use OID's decoder because it throws BERDecodeError
148  // if the OIDs do not match.
149  OID oid(bt);
150 
151  if (!m_oid.Empty() && m_oid != oid)
152  BERDecodeError(); // Only accept user specified OID
153  else if (oid == ASN1::curve25519() || oid == ASN1::X25519())
154  m_oid = oid; // Accept any of the x25519 OIDs
155  else
156  BERDecodeError();
157 }
158 
160 {
161  // https://tools.ietf.org/html/rfc8410, section 7 and
162  // https://www.cryptopp.com/wiki/curve25519_keys
163  BERSequenceDecoder privateKeyInfo(bt);
164  word32 version;
165  BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 1); // check version
166 
167  BERSequenceDecoder algorithm(privateKeyInfo);
168  // GetAlgorithmID().BERDecodeAndCheck(algorithm);
169  BERDecodeAndCheckAlgorithmID(algorithm);
170  algorithm.MessageEnd();
171 
172  BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
173  BERDecodePrivateKey(octetString, false, (size_t)privateKeyInfo.RemainingLength());
174  octetString.MessageEnd();
175 
176  // publicKey [1] IMPLICIT PublicKey OPTIONAL
177  bool generatePublicKey = true;
178  if (privateKeyInfo.EndReached() == false /*version == 1?*/)
179  {
180  // Should we test this before decoding? In either case we
181  // just throw a BERDecodeErr() when we can't parse it.
182  BERGeneralDecoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
183  SecByteBlock subjectPublicKey;
184  unsigned int unusedBits;
185  BERDecodeBitString(publicKey, subjectPublicKey, unusedBits);
186  CRYPTOPP_ASSERT(unusedBits == 0);
187  CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
188  if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
189  BERDecodeError();
190  std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
191  generatePublicKey = false;
192  publicKey.MessageEnd();
193  }
194 
195  privateKeyInfo.MessageEnd();
196 
197  if (generatePublicKey)
198  Donna::curve25519_mult(m_pk, m_sk);
199 
200  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
201  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
202 }
203 
204 void x25519::DEREncode(BufferedTransformation &bt, int version) const
205 {
206  // https://tools.ietf.org/html/rfc8410, section 7 and
207  // https://www.cryptopp.com/wiki/curve25519_keys
208  CRYPTOPP_ASSERT(version == 0 || version == 1);
209 
210  DERSequenceEncoder privateKeyInfo(bt);
211  DEREncodeUnsigned<word32>(privateKeyInfo, version);
212 
213  DERSequenceEncoder algorithm(privateKeyInfo);
214  GetAlgorithmID().DEREncode(algorithm);
215  algorithm.MessageEnd();
216 
217  DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
218  DEREncodePrivateKey(octetString);
219  octetString.MessageEnd();
220 
221  if (version == 1)
222  {
223  DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
224  DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH);
225  publicKey.MessageEnd();
226  }
227 
228  privateKeyInfo.MessageEnd();
229 }
230 
231 void x25519::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
232 {
233  // https://tools.ietf.org/html/rfc8410 and
234  // https://www.cryptopp.com/wiki/curve25519_keys
235 
236  BERGeneralDecoder privateKey(bt, OCTET_STRING);
237 
238  if (!privateKey.IsDefiniteLength())
239  BERDecodeError();
240 
241  size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH);
242  if (size != SECRET_KEYLENGTH)
243  BERDecodeError();
244 
245  // We don't know how to decode them
246  if (parametersPresent)
247  BERDecodeError();
248 
249  privateKey.MessageEnd();
250 }
251 
253 {
254  // https://tools.ietf.org/html/rfc8410
255  DERGeneralEncoder privateKey(bt, OCTET_STRING);
256  privateKey.Put(m_sk, SECRET_KEYLENGTH);
257  privateKey.MessageEnd();
258 }
259 
260 bool x25519::Validate(RandomNumberGenerator &rng, unsigned int level) const
261 {
262  CRYPTOPP_UNUSED(rng);
263  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
264  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
265 
266  if (level >= 1 && IsClamped(m_sk) == false)
267  return false;
268  if (level >= 2 && IsSmallOrder(m_pk) == true)
269  return false;
270  if (level >= 3)
271  {
273  ClampKeys(pk, sk);
274 
275  // Secret key is already clamped, bufs are equal
276  if (VerifyBufsEqual(pk, m_pk, PUBLIC_KEYLENGTH) == false)
277  return false;
278  }
279 
280  return true;
281 }
282 
283 bool x25519::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
284 {
285  if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0)
286  {
287  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
288  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false);
289  return true;
290  }
291 
292  if (std::strcmp(name, Name::PublicElement()) == 0)
293  {
294  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
295  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
296  return true;
297  }
298 
299  if (std::strcmp(name, Name::GroupOID()) == 0)
300  {
301  if (m_oid.Empty())
302  return false;
303 
304  this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
305  *reinterpret_cast<OID *>(pValue) = m_oid;
306  return true;
307  }
308 
309  return false;
310 }
311 
313 {
315  if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val))
316  {
317  std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH);
318  }
319 
320  if (source.GetValue(Name::PublicElement(), val))
321  {
322  std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH);
323  }
324 
325  OID oid;
326  if (source.GetValue(Name::GroupOID(), oid))
327  {
328  m_oid = oid;
329  }
330 }
331 
333 {
335  if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy())
336  rng.IncorporateEntropy(seed.begin(), seed.size());
337 
338  rng.GenerateBlock(m_sk, SECRET_KEYLENGTH);
339  m_sk[0] &= 248; m_sk[31] &= 127; m_sk[31] |= 64;
340  Donna::curve25519_mult(m_pk, m_sk);
341 }
342 
343 void x25519::GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
344 {
345  rng.GenerateBlock(privateKey, SECRET_KEYLENGTH);
346  privateKey[0] &= 248; privateKey[31] &= 127; privateKey[31] |= 64;
347 }
348 
349 void x25519::GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
350 {
351  CRYPTOPP_UNUSED(rng);
352  Donna::curve25519_mult(publicKey, privateKey);
353 }
354 
355 bool x25519::Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey) const
356 {
357  CRYPTOPP_ASSERT(agreedValue != NULLPTR);
358  CRYPTOPP_ASSERT(otherPublicKey != NULLPTR);
359 
360  if (validateOtherPublicKey && IsSmallOrder(otherPublicKey))
361  return false;
362 
363  return Donna::curve25519_mult(agreedValue, privateKey, otherPublicKey) == 0;
364 }
365 
366 // ******************** ed25519 Signer ************************* //
367 
369 {
370  x[0] &= 248; x[31] &= 127; x[31] |= 64;
371  int ret = Donna::ed25519_publickey(y, x);
372  CRYPTOPP_ASSERT(ret == 0); CRYPTOPP_UNUSED(ret);
373 }
374 
376 {
377  return (x[0] & 248) == x[0] && (x[31] & 127) == x[31] && (x[31] | 64) == x[31];
378 }
379 
381 {
382  return HasSmallOrder(y);
383 }
384 
385 bool ed25519PrivateKey::Validate(RandomNumberGenerator &rng, unsigned int level) const
386 {
387  CRYPTOPP_UNUSED(rng);
388  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
389  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
390 
391  if (level >= 1 && IsClamped(m_sk) == false)
392  return false;
393  if (level >= 2 && IsSmallOrder(m_pk) == true)
394  return false;
395  if (level >= 3)
396  {
398  ClampKeys(pk, sk);
399 
400  // Secret key is already clamped, bufs are equal
401  if (VerifyBufsEqual(pk, m_pk, PUBLIC_KEYLENGTH) == false)
402  return false;
403  }
404 
405  return true;
406 }
407 
408 bool ed25519PrivateKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
409 {
410  if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0)
411  {
412  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
413  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false);
414  return true;
415  }
416 
417  if (std::strcmp(name, Name::PublicElement()) == 0)
418  {
419  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
420  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
421  return true;
422  }
423 
424  if (std::strcmp(name, Name::GroupOID()) == 0)
425  {
426  if (m_oid.Empty())
427  return false;
428 
429  this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
430  *reinterpret_cast<OID *>(pValue) = m_oid;
431  return true;
432  }
433 
434  return false;
435 }
436 
438 {
440  if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val))
441  {
443  std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH);
444  }
445  if (source.GetValue(Name::PublicElement(), val))
446  {
448  std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH);
449  }
450 
451  OID oid;
452  if (source.GetValue(Name::GroupOID(), oid))
453  {
454  m_oid = oid;
455  }
456 
457  bool clamp = false;
458  if (source.GetValue("Clamp", clamp) && clamp == true)
459  ClampKeys(m_pk, m_sk);
460 
461  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
462  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
463 }
464 
466 {
468  if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy())
469  rng.IncorporateEntropy(seed.begin(), seed.size());
470 
471  rng.GenerateBlock(m_sk, 32);
472  m_sk[0] &= 248; m_sk[31] &= 127; m_sk[31] |= 64;
473  int ret = Donna::ed25519_publickey(m_pk, m_sk);
474  CRYPTOPP_ASSERT(ret == 0); CRYPTOPP_UNUSED(ret);
475 }
476 
478 {
482 }
483 
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 
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(IsClamped(m_sk) == true);
541  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
542 }
543 
545 {
546  // https://tools.ietf.org/html/rfc8410, section 7 and
547  // https://www.cryptopp.com/wiki/curve25519_keys
548  CRYPTOPP_ASSERT(version == 0 || version == 1);
549 
550  DERSequenceEncoder privateKeyInfo(bt);
551  DEREncodeUnsigned<word32>(privateKeyInfo, version);
552 
553  DERSequenceEncoder algorithm(privateKeyInfo);
554  GetAlgorithmID().DEREncode(algorithm);
555  algorithm.MessageEnd();
556 
557  DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
558  DEREncodePrivateKey(octetString);
559  octetString.MessageEnd();
560 
561  if (version == 1)
562  {
563  DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
564  DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH);
565  publicKey.MessageEnd();
566  }
567 
568  privateKeyInfo.MessageEnd();
569 }
570 
571 void ed25519PrivateKey::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
572 {
573  // https://tools.ietf.org/html/rfc8410 and
574  // https://www.cryptopp.com/wiki/curve25519_keys
575 
576  BERGeneralDecoder privateKey(bt, OCTET_STRING);
577 
578  if (!privateKey.IsDefiniteLength())
579  BERDecodeError();
580 
581  size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH);
582  if (size != SECRET_KEYLENGTH)
583  BERDecodeError();
584 
585  // We don't know how to decode them
586  if (parametersPresent)
587  BERDecodeError();
588 
589  privateKey.MessageEnd();
590 }
591 
593 {
594  // https://tools.ietf.org/html/rfc8410
595  DERGeneralEncoder privateKey(bt, OCTET_STRING);
596  privateKey.Put(m_sk, SECRET_KEYLENGTH);
597  privateKey.MessageEnd();
598 }
599 
600 void ed25519PrivateKey::SetPrivateExponent (const byte x[SECRET_KEYLENGTH])
601 {
603  (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH))
604  ("Clamp", true));
605 }
606 
607 void ed25519PrivateKey::SetPrivateExponent (const Integer &x)
608 {
610 
611  SecByteBlock bx(SECRET_KEYLENGTH);
612  x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
613 
615  (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false))
616  ("Clamp", true));
617 }
618 
619 const Integer& ed25519PrivateKey::GetPrivateExponent() const
620 {
621  m_x = Integer(m_sk, SECRET_KEYLENGTH, Integer::UNSIGNED, LITTLE_ENDIAN_ORDER);
622  return m_x;
623 }
624 
625 ////////////////////////
626 
627 ed25519Signer::ed25519Signer(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH])
628 {
629  AccessPrivateKey().AssignFrom(MakeParameters
630  (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH, false))
631  (Name::PublicElement(), ConstByteArrayParameter(y, PUBLIC_KEYLENGTH, false)));
632 }
633 
634 ed25519Signer::ed25519Signer(const byte x[SECRET_KEYLENGTH])
635 {
636  AccessPrivateKey().AssignFrom(MakeParameters
637  (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH, false))
638  ("Clamp", true));
639 }
640 
642 {
645 
646  SecByteBlock by(PUBLIC_KEYLENGTH), bx(SECRET_KEYLENGTH);
647  y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
648  x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
649 
650  AccessPrivateKey().AssignFrom(MakeParameters
652  (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false)));
653 }
654 
656 {
658 
659  SecByteBlock bx(SECRET_KEYLENGTH);
660  x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
661 
662  AccessPrivateKey().AssignFrom(MakeParameters
663  (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false))
664  ("Clamp", true));
665 }
666 
668 {
669  AccessPrivateKey().GenerateRandom(rng);
670 }
671 
673 {
674  AccessPrivateKey().Load(params);
675 }
676 
677 size_t ed25519Signer::SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const
678 {
679  CRYPTOPP_ASSERT(signature != NULLPTR); CRYPTOPP_UNUSED(rng);
680 
681  ed25519_MessageAccumulator& accum = static_cast<ed25519_MessageAccumulator&>(messageAccumulator);
682  const ed25519PrivateKey& pk = static_cast<const ed25519PrivateKey&>(GetPrivateKey());
683  int ret = Donna::ed25519_sign(accum.data(), accum.size(), pk.GetPrivateKeyBytePtr(), pk.GetPublicKeyBytePtr(), signature);
684  CRYPTOPP_ASSERT(ret == 0);
685 
686  if (restart)
687  accum.Restart();
688 
689  return ret == 0 ? SIGNATURE_LENGTH : 0;
690 }
691 
692 // ******************** ed25519 Verifier ************************* //
693 
694 bool ed25519PublicKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
695 {
696  if (std::strcmp(name, Name::PublicElement()) == 0)
697  {
698  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
699  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
700  return true;
701  }
702 
703  if (std::strcmp(name, Name::GroupOID()) == 0)
704  {
705  if (m_oid.Empty())
706  return false;
707 
708  this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
709  *reinterpret_cast<OID *>(pValue) = m_oid;
710  return true;
711  }
712 
713  return false;
714 }
715 
717 {
719  if (source.GetValue(Name::PublicElement(), ba))
720  {
721  std::memcpy(m_pk, ba.begin(), PUBLIC_KEYLENGTH);
722  }
723 
724  OID oid;
725  if (source.GetValue(Name::GroupOID(), oid))
726  {
727  m_oid = oid;
728  }
729 }
730 
732 {
733  // We have not yet determined the OID to use for this object.
734  // We can't use OID's decoder because it throws BERDecodeError
735  // if the OIDs do not match.
736  OID oid(bt);
737 
738  if (!m_oid.Empty() && m_oid != oid)
739  BERDecodeError(); // Only accept user specified OID
740  else if (oid == ASN1::curve25519() || oid == ASN1::Ed25519())
741  m_oid = oid; // Accept any of the ed25519PublicKey OIDs
742  else
743  BERDecodeError();
744 }
745 
747 {
748  BERSequenceDecoder publicKeyInfo(bt);
749 
750  BERSequenceDecoder algorithm(publicKeyInfo);
751  // GetAlgorithmID().BERDecodeAndCheck(algorithm);
752  BERDecodeAndCheckAlgorithmID(algorithm);
753  algorithm.MessageEnd();
754 
755  BERDecodePublicKey(publicKeyInfo, false, (size_t)publicKeyInfo.RemainingLength());
756 
757  publicKeyInfo.MessageEnd();
758 }
759 
761 {
762  DERSequenceEncoder publicKeyInfo(bt);
763 
764  DERSequenceEncoder algorithm(publicKeyInfo);
765  GetAlgorithmID().DEREncode(algorithm);
766  algorithm.MessageEnd();
767 
768  DEREncodePublicKey(publicKeyInfo);
769 
770  publicKeyInfo.MessageEnd();
771 }
772 
773 void ed25519PublicKey::BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
774 {
775  // We don't know how to decode them
776  if (parametersPresent)
777  BERDecodeError();
778 
779  SecByteBlock subjectPublicKey;
780  unsigned int unusedBits;
781  BERDecodeBitString(bt, subjectPublicKey, unusedBits);
782 
783  CRYPTOPP_ASSERT(unusedBits == 0);
784  CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
785  if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
786  BERDecodeError();
787 
788  std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
789 }
790 
792 {
794 }
795 
796 void ed25519PublicKey::SetPublicElement (const byte y[PUBLIC_KEYLENGTH])
797 {
798  std::memcpy(m_pk, y, PUBLIC_KEYLENGTH);
799 }
800 
801 void ed25519PublicKey::SetPublicElement (const Integer &y)
802 {
804 
805  SecByteBlock by(PUBLIC_KEYLENGTH);
806  y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
807 
808  std::memcpy(m_pk, by, PUBLIC_KEYLENGTH);
809 }
810 
811 const Integer& ed25519PublicKey::GetPublicElement() const
812 {
813  m_y = Integer(m_pk, PUBLIC_KEYLENGTH, Integer::UNSIGNED, LITTLE_ENDIAN_ORDER);
814  return m_y;
815 }
816 
817 bool ed25519PublicKey::Validate(RandomNumberGenerator &rng, unsigned int level) const
818 {
819  CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(level);
820  return true;
821 }
822 
823 ////////////////////////
824 
825 ed25519Verifier::ed25519Verifier(const byte y[PUBLIC_KEYLENGTH])
826 {
827  AccessPublicKey().AssignFrom(MakeParameters
828  (Name::PublicElement(), ConstByteArrayParameter(y, PUBLIC_KEYLENGTH)));
829 }
830 
832 {
834 
835  SecByteBlock by(PUBLIC_KEYLENGTH);
836  y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
837 
838  AccessPublicKey().AssignFrom(MakeParameters
839  (Name::PublicElement(), ConstByteArrayParameter(by, PUBLIC_KEYLENGTH, false)));
840 }
841 
843 {
844  AccessPublicKey().Load(params);
845 }
846 
848 {
849  const ed25519PrivateKey& priv = static_cast<const ed25519PrivateKey&>(signer.GetPrivateKey());
850  priv.MakePublicKey(AccessPublicKey());
851 }
852 
854 {
855  ed25519_MessageAccumulator& accum = static_cast<ed25519_MessageAccumulator&>(messageAccumulator);
856  const ed25519PublicKey& pk = static_cast<const ed25519PublicKey&>(GetPublicKey());
857  int ret = Donna::ed25519_sign_open(accum.data(), accum.size(), pk.GetPublicKeyBytePtr(), accum.signature());
858  accum.Restart();
859 
860  return ret == 0;
861 }
862 
863 NAMESPACE_END // CryptoPP
Used to pass byte array input as part of a NameValuePairs object.
Definition: algparam.h:20
virtual void AssignFrom(const NameValuePairs &source)=0
Assign values to this object.
x25519 with key validation
Definition: xed25519.h:54
Ed25519 private key.
Definition: xed25519.h:332
void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params)
Generate a random key or crypto parameters.
Definition: xed25519.cpp:332
void DEREncode(BufferedTransformation &bt) const
Encode this object into a BufferedTransformation.
Definition: xed25519.h:194
bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const
Check whether messageAccumulator contains a valid signature and message, and restart messageAccumulat...
Definition: xed25519.cpp:853
void ClampKeys(byte y[PUBLIC_KEYLENGTH], byte x[SECRET_KEYLENGTH]) const
Clamp a private key.
Definition: xed25519.cpp:128
an unsigned value
Definition: integer.h:85
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: cryptlib.cpp:311
size_t size() const
Length of the memory block.
Definition: algparam.h:84
bool Validate(RandomNumberGenerator &rng, unsigned int level) const
Check this object for errors.
Definition: xed25519.cpp:817
const byte * GetPublicKeyBytePtr() const
Retrieve public key byte array.
Definition: xed25519.h:657
void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size)
decode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header ...
Definition: xed25519.cpp:773
Abstract base classes that provide a uniform interface to this library.
void Restart()
Reset the accumulator.
Definition: xed25519.h:279
size_t size() const
Retrieve size of data buffer.
Definition: xed25519.h:304
void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
Generate a public key from a private key in this domain.
Definition: xed25519.cpp:349
Interface for random number generators.
Definition: cryptlib.h:1349
void MakePublicKey(PublicKey &pub) const
Initializes a public key from this key.
Definition: xed25519.cpp:477
Common C++ header files.
ed25519Verifier()
Create a ed25519Verifier object.
Definition: xed25519.h:678
static const int SECRET_KEYLENGTH
Size of the private key.
Definition: xed25519.h:59
void DEREncodePublicKey(BufferedTransformation &bt) const
encode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header ...
Definition: xed25519.cpp:791
SecBlock<byte> typedef.
Definition: secblock.h:1052
BER Sequence Decoder.
Definition: asn.h:309
Interface for buffered transformations.
Definition: cryptlib.h:1564
void DEREncode(BufferedTransformation &bt) const
Encode this object into a BufferedTransformation.
Definition: xed25519.cpp:760
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
Get a named value.
Definition: xed25519.cpp:408
byte order is little-endian
Definition: cryptlib.h:145
const char * PrivateExponent()
Integer.
Definition: argnames.h:35
void ClampKeys(byte y[PUBLIC_KEYLENGTH], byte x[SECRET_KEYLENGTH]) const
Clamp a private key.
Definition: xed25519.cpp:368
bool IsClamped(const byte x[SECRET_KEYLENGTH]) const
Determine if private key is clamped.
Definition: xed25519.cpp:375
int ed25519_sign(const byte *message, size_t messageLength, const byte secretKey[32], const byte publicKey[32], byte signature[64])
Creates a signature on a message.
size_t MinEncodedSize(Signedness sign=UNSIGNED) const
Minimum number of bytes to encode this integer.
Definition: integer.cpp:3388
int curve25519_mult(byte publicKey[32], const byte secretKey[32])
Generate a public key.
void BERDecode(BufferedTransformation &bt)
Decode this object from a BufferedTransformation.
Definition: xed25519.cpp:499
void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
Generate private key in this domain.
Definition: xed25519.cpp:343
const byte * data() const
Retrieve pointer to data buffer.
Definition: xed25519.h:298
const byte * begin() const
Pointer to the first byte in the memory block.
Definition: algparam.h:80
size_t Put(byte inByte, bool blocking=true)
Input a byte for processing.
Definition: cryptlib.h:1586
AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed=true)
Create an object that implements NameValuePairs.
Definition: algparam.h:502
void BERDecode(BufferedTransformation &bt)
Decode this object from a BufferedTransformation.
Definition: xed25519.cpp:746
bool Validate(RandomNumberGenerator &rng, unsigned int level) const
Check this object for errors.
Definition: xed25519.cpp:385
void DEREncode(BufferedTransformation &bt) const
DER encode this OID.
Definition: asn.cpp:259
const char * GroupOID()
OID.
Definition: argnames.h:41
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
Get a named value.
Definition: xed25519.cpp:283
static const int PUBLIC_KEYLENGTH
Size of the public key.
Definition: xed25519.h:62
Multiple precision integer with arithmetic operations.
Definition: integer.h:49
const PrivateKey & GetPrivateKey() const
Retrieves a reference to a Private Key.
Definition: xed25519.h:543
Precompiled header file.
void DEREncode(BufferedTransformation &bt) const
Encode this object into a BufferedTransformation.
Definition: xed25519.h:404
int ed25519_sign_open(const byte *message, size_t messageLength, const byte publicKey[32], const byte signature[64])
Verifies a signature on a message.
const NameValuePairs & g_nullNameValuePairs
An empty set of name-value pairs.
Definition: cryptlib.h:500
virtual bool CanIncorporateEntropy() const
Determines if a generator can accept additional entropy.
Definition: cryptlib.h:1370
#define COUNTOF(arr)
Counts elements in an array.
Definition: misc.h:181
const char * Seed()
ConstByteArrayParameter.
Definition: argnames.h:19
Classes for x25519 and ed25519 operations.
void BERDecode(BufferedTransformation &bt)
Decode this object from a BufferedTransformation.
Definition: xed25519.cpp:159
void AssignFrom(const NameValuePairs &source)
Assign values to this object.
Definition: xed25519.cpp:437
void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size)
decode privateKey part of privateKeyInfo, without the OCTET STRING header
Definition: xed25519.cpp:231
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:60
void BERDecodeError()
Raises a BERDecodeErr.
Definition: asn.h:69
Classes and functions for working with ANS.1 objects.
ed25519 message accumulator
Definition: xed25519.h:253
iterator begin()
Provides an iterator pointing to the first element in the memory block.
Definition: secblock.h:766
bool Validate(RandomNumberGenerator &rng, unsigned int level) const
Check this object for errors.
Definition: xed25519.cpp:260
Implementation of BufferedTransformation&#39;s attachment interface.
Ed25519 signature algorithm.
Definition: xed25519.h:480
Interface for accumulating messages to be signed or verified.
Definition: cryptlib.h:2711
size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const
Sign and restart messageAccumulator.
Definition: xed25519.cpp:677
bool IsClamped(const byte x[SECRET_KEYLENGTH]) const
Determine if private key is clamped.
Definition: xed25519.cpp:134
DER Sequence Encoder.
Definition: asn.h:319
void Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const
Encode in big-endian format.
Definition: integer.cpp:3404
static void ThrowIfTypeMismatch(const char *name, const std::type_info &stored, const std::type_info &retrieving)
Ensures an expected name and type is present.
Definition: cryptlib.h:425
bool IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const
Test if a key has small order.
Definition: xed25519.cpp:139
DER General Encoder.
Definition: asn.h:291
x25519(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH])
Create a x25519 object.
Definition: xed25519.cpp:74
OID GetAlgorithmID() const
Get the Object Identifier
Definition: xed25519.h:132
bool VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count)
Performs a near constant-time comparison of two equally sized buffers.
Definition: misc.cpp:100
Multiple precision integer with arithmetic operations.
size_t BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits)
DER decode bit string.
Definition: asn.cpp:191
void AssignFrom(const NameValuePairs &source)
Assign values to this object.
Definition: xed25519.cpp:716
void BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt)
Determine if OID is valid for this object.
Definition: xed25519.cpp:484
bool IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const
Test if a key has small order.
Definition: xed25519.cpp:380
virtual size_t Get(byte &outByte)
Retrieve a 8-bit byte.
Definition: cryptlib.cpp:527
Interface for public keys.
Definition: cryptlib.h:2391
Crypto++ library namespace.
int ed25519_publickey(byte publicKey[32], const byte secretKey[32])
Creates a public key from a secret key.
bool GetValue(const char *name, T &value) const
Get a named value.
Definition: cryptlib.h:350
bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const
Derive agreed value.
Definition: xed25519.cpp:355
ed25519Signer()
Create a ed25519Signer object.
Definition: xed25519.h:498
void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size)
decode privateKey part of privateKeyInfo, without the OCTET STRING header
Definition: xed25519.cpp:571
BER General Decoder.
Definition: asn.h:258
const byte * GetPrivateKeyBytePtr() const
Retrieve private key byte array.
Definition: xed25519.h:460
void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params)
Generate a random key or crypto parameters.
Definition: xed25519.cpp:465
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
Get a named value.
Definition: xed25519.cpp:694
Ed25519 public key.
Definition: xed25519.h:593
void AssignFrom(const NameValuePairs &source)
Assign values to this object.
Definition: xed25519.cpp:312
void DEREncodePrivateKey(BufferedTransformation &bt) const
encode privateKey part of privateKeyInfo, without the OCTET STRING header
Definition: xed25519.cpp:592
Object Identifier.
Definition: asn.h:166
void BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt)
Determine if OID is valid for this object.
Definition: xed25519.cpp:144
const char * PublicElement()
Integer.
Definition: argnames.h:36
void DEREncodePrivateKey(BufferedTransformation &bt) const
encode privateKey part of privateKeyInfo, without the OCTET STRING header
Definition: xed25519.cpp:252
void Load(BufferedTransformation &bt)
BER decode ASN.1 object.
Definition: xed25519.h:188
size_type size() const
Provides the count of elements in the SecBlock.
Definition: secblock.h:791
const byte * GetPublicKeyBytePtr() const
Retrieve public key byte array.
Definition: xed25519.h:467
virtual void IncorporateEntropy(const byte *input, size_t length)
Update RNG state with additional unpredictable values.
Definition: cryptlib.h:1362
size_t DEREncodeBitString(BufferedTransformation &bt, const byte *str, size_t strLen, unsigned int unusedBits=0)
DER encode bit string.
Definition: asn.cpp:182
byte * signature()
Retrieve pointer to signature buffer.
Definition: xed25519.h:286
Interface for retrieving values given their names.
Definition: cryptlib.h:293
void BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt)
Determine if OID is valid for this object.
Definition: xed25519.cpp:731