Crypto++  7.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 ANONYMOUS_NAMESPACE_END
51 
52 NAMESPACE_BEGIN(CryptoPP)
53 
54 // ******************** x25519 Agreement ************************* //
55 
56 x25519::x25519(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH])
57 {
58  std::memcpy(m_pk, y, SECRET_KEYLENGTH);
59  std::memcpy(m_sk, x, PUBLIC_KEYLENGTH);
60 
61  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
62  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
63 }
64 
65 x25519::x25519(const byte x[SECRET_KEYLENGTH])
66 {
67  std::memcpy(m_sk, x, SECRET_KEYLENGTH);
68  Donna::curve25519_mult(m_pk, m_sk);
69 
70  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
71  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
72 }
73 
74 x25519::x25519(const Integer &y, const Integer &x)
75 {
77  CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
78 
79  y.Encode(m_pk, PUBLIC_KEYLENGTH); std::reverse(m_pk+0, m_pk+PUBLIC_KEYLENGTH);
80  x.Encode(m_sk, SECRET_KEYLENGTH); std::reverse(m_sk+0, m_sk+SECRET_KEYLENGTH);
81 
82  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
83  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
84 }
85 
87 {
88  CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
89 
90  x.Encode(m_sk, SECRET_KEYLENGTH);
91  std::reverse(m_sk+0, m_sk+SECRET_KEYLENGTH);
92  Donna::curve25519_mult(m_pk, m_sk);
93 
94  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
95  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
96 }
97 
99 {
100  rng.GenerateBlock(m_sk, SECRET_KEYLENGTH);
101  m_sk[0] &= 248; m_sk[31] &= 127; m_sk[31] |= 64;
102  Donna::curve25519_mult(m_pk, m_sk);
103 }
104 
106 {
107  Load(params);
108 }
109 
110 void x25519::ClampKeys(byte y[PUBLIC_KEYLENGTH], byte x[SECRET_KEYLENGTH]) const
111 {
112  x[0] &= 248; x[31] &= 127; x[31] |= 64;
114 }
115 
116 bool x25519::IsClamped(const byte x[SECRET_KEYLENGTH]) const
117 {
118  return (x[0] & 248) == x[0] && (x[31] & 127) == x[31] && (x[31] | 64) == x[31];
119 }
120 
121 bool x25519::IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const
122 {
123  // The magic 12 is the count of blaklisted points
124  byte c[12] = { 0 };
125  for (size_t j = 0; j < PUBLIC_KEYLENGTH; j++) {
126  for (size_t i = 0; i < COUNTOF(blacklist); i++) {
127  c[i] |= y[j] ^ blacklist[i][j];
128  }
129  }
130 
131  unsigned int k = 0;
132  for (size_t i = 0; i < COUNTOF(blacklist); i++) {
133  k |= (c[i] - 1);
134  }
135 
136  return (bool)((k >> 8) & 1);
137 }
138 
140 {
141  // We have not yet determined the OID to use for this object.
142  // We can't use OID's decoder because it throws BERDecodeError
143  // if the OIDs do not match.
144  OID oid(bt);
145 
146  if (!m_oid.Empty() && m_oid != oid)
147  BERDecodeError(); // Only accept user specified OID
148  else if (oid == ASN1::curve25519() || oid == ASN1::X25519())
149  m_oid = oid; // Accept any of the x25519 OIDs
150  else
151  BERDecodeError();
152 }
153 
155 {
156  // https://tools.ietf.org/html/rfc8410, section 7 and
157  // https://www.cryptopp.com/wiki/curve25519_keys
158  BERSequenceDecoder privateKeyInfo(bt);
159  word32 version;
160  BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 1); // check version
161 
162  BERSequenceDecoder algorithm(privateKeyInfo);
163  // GetAlgorithmID().BERDecodeAndCheck(algorithm);
164  BERDecodeAndCheckAlgorithmID(algorithm);
165  algorithm.MessageEnd();
166 
167  BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
168  BERDecodePrivateKey(octetString, false, (size_t)privateKeyInfo.RemainingLength());
169  octetString.MessageEnd();
170 
171  bool generatePublicKey = true;
172  if (version == 1)
173  {
174  BERGeneralDecoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
175  SecByteBlock subjectPublicKey;
176  unsigned int unusedBits;
177  BERDecodeBitString(publicKey, subjectPublicKey, unusedBits);
178  CRYPTOPP_ASSERT(unusedBits == 0);
179  CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
180  if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
181  BERDecodeError();
182  std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
183  generatePublicKey = false;
184  publicKey.MessageEnd();
185  }
186 
187  privateKeyInfo.MessageEnd();
188 
189  if (generatePublicKey)
190  Donna::curve25519_mult(m_pk, m_sk);
191 
192  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
193  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
194 }
195 
196 void x25519::DEREncode(BufferedTransformation &bt, int version) const
197 {
198  // https://tools.ietf.org/html/rfc8410, section 7 and
199  // https://www.cryptopp.com/wiki/curve25519_keys
200  CRYPTOPP_ASSERT(version == 0 || version == 1);
201 
202  DERSequenceEncoder privateKeyInfo(bt);
203  DEREncodeUnsigned<word32>(privateKeyInfo, version);
204 
205  DERSequenceEncoder algorithm(privateKeyInfo);
206  GetAlgorithmID().DEREncode(algorithm);
207  algorithm.MessageEnd();
208 
209  DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
210  DEREncodePrivateKey(octetString);
211  octetString.MessageEnd();
212 
213  if (version == 1)
214  {
215  DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
216  DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH);
217  publicKey.MessageEnd();
218  }
219 
220  privateKeyInfo.MessageEnd();
221 }
222 
223 void x25519::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
224 {
225  // https://tools.ietf.org/html/rfc8410 and
226  // https://www.cryptopp.com/wiki/curve25519_keys
227 
228  BERGeneralDecoder privateKey(bt, OCTET_STRING);
229 
230  if (!privateKey.IsDefiniteLength())
231  BERDecodeError();
232 
233  size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH);
234  if (size != SECRET_KEYLENGTH)
235  BERDecodeError();
236 
237  // We don't know how to decode them
238  if (parametersPresent)
239  BERDecodeError();
240 
241  privateKey.MessageEnd();
242 }
243 
245 {
246  // https://tools.ietf.org/html/rfc8410
247  DERGeneralEncoder privateKey(bt, OCTET_STRING);
248  privateKey.Put(m_sk, SECRET_KEYLENGTH);
249  privateKey.MessageEnd();
250 }
251 
252 bool x25519::Validate(RandomNumberGenerator &rng, unsigned int level) const
253 {
254  CRYPTOPP_UNUSED(rng);
255  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
256  CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
257 
258  if (level >= 1 && IsClamped(m_sk) == false)
259  return false;
260  if (level >= 2 && IsSmallOrder(m_pk) == true)
261  return false;
262 
263  return true;
264 }
265 
266 bool x25519::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
267 {
268  if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0)
269  {
270  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
271  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false);
272  return true;
273  }
274 
275  if (std::strcmp(name, Name::PublicElement()) == 0)
276  {
277  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
278  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
279  return true;
280  }
281 
282  if (std::strcmp(name, Name::GroupOID()) == 0)
283  {
284  if (m_oid.Empty())
285  return false;
286 
287  this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
288  *reinterpret_cast<OID *>(pValue) = m_oid;
289  return true;
290  }
291 
292  return false;
293 }
294 
296 {
298  if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val))
299  {
300  std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH);
301  }
302 
303  if (source.GetValue(Name::PublicElement(), val))
304  {
305  std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH);
306  }
307 
308  OID oid;
309  if (source.GetValue(Name::GroupOID(), oid))
310  {
311  m_oid = oid;
312  }
313 }
314 
316 {
318  if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy())
319  rng.IncorporateEntropy(seed.begin(), seed.size());
320 
321  rng.GenerateBlock(m_sk, SECRET_KEYLENGTH);
322  m_sk[0] &= 248; m_sk[31] &= 127; m_sk[31] |= 64;
323  Donna::curve25519_mult(m_pk, m_sk);
324 }
325 
326 void x25519::GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
327 {
328  rng.GenerateBlock(privateKey, SECRET_KEYLENGTH);
329  privateKey[0] &= 248; privateKey[31] &= 127; privateKey[31] |= 64;
330 }
331 
332 void x25519::GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
333 {
334  CRYPTOPP_UNUSED(rng);
335  Donna::curve25519_mult(publicKey, privateKey);
336 }
337 
338 bool x25519::Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey) const
339 {
340  CRYPTOPP_ASSERT(agreedValue != NULLPTR);
341  CRYPTOPP_ASSERT(otherPublicKey != NULLPTR);
342 
343  if (validateOtherPublicKey && IsSmallOrder(otherPublicKey))
344  return false;
345 
346  return Donna::curve25519_mult(agreedValue, privateKey, otherPublicKey) == 0;
347 }
348 
349 // ******************** ed25519 Signer ************************* //
350 
351 void ed25519PrivateKey::ClampKeys(byte y[PUBLIC_KEYLENGTH], byte x[SECRET_KEYLENGTH]) const
352 {
353  x[0] &= 248; x[31] &= 127; x[31] |= 64;
354  int ret = Donna::ed25519_publickey(y, x);
355  CRYPTOPP_ASSERT(ret == 0); CRYPTOPP_UNUSED(ret);
356 }
357 
358 bool ed25519PrivateKey::IsClamped(const byte x[SECRET_KEYLENGTH]) const
359 {
360  return (x[0] & 248) == x[0] && (x[31] & 127) == x[31] && (x[31] | 64) == x[31];
361 }
362 
363 bool ed25519PrivateKey::Validate(RandomNumberGenerator &rng, unsigned int level) const
364 {
365  CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(level);
366  return true;
367 }
368 
369 bool ed25519PrivateKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
370 {
371  if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0)
372  {
373  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
374  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false);
375  return true;
376  }
377 
378  if (std::strcmp(name, Name::PublicElement()) == 0)
379  {
380  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
381  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
382  return true;
383  }
384 
385  if (std::strcmp(name, Name::GroupOID()) == 0)
386  {
387  if (m_oid.Empty())
388  return false;
389 
390  this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
391  *reinterpret_cast<OID *>(pValue) = m_oid;
392  return true;
393  }
394 
395  return false;
396 }
397 
399 {
401  if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val))
402  {
404  std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH);
405  }
406  if (source.GetValue(Name::PublicElement(), val))
407  {
409  std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH);
410  }
411 
412  OID oid;
413  if (source.GetValue(Name::GroupOID(), oid))
414  {
415  m_oid = oid;
416  }
417 
418  bool clamp = false;
419  if (source.GetValue("Clamp", clamp) && clamp == true)
420  ClampKeys(m_pk, m_sk);
421 }
422 
424 {
426  if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy())
427  rng.IncorporateEntropy(seed.begin(), seed.size());
428 
429  rng.GenerateBlock(m_sk, 32);
430  m_sk[0] &= 248; m_sk[31] &= 127; m_sk[31] |= 64;
431  int ret = Donna::ed25519_publickey(m_pk, m_sk);
432  CRYPTOPP_ASSERT(ret == 0); CRYPTOPP_UNUSED(ret);
433 }
434 
436 {
440 }
441 
443 {
444  // We have not yet determined the OID to use for this object.
445  // We can't use OID's decoder because it throws BERDecodeError
446  // if the OIDs do not match.
447  OID oid(bt);
448 
449  if (!m_oid.Empty() && m_oid != oid)
450  BERDecodeError(); // Only accept user specified OID
451  else if (oid == ASN1::curve25519() || oid == ASN1::Ed25519())
452  m_oid = oid; // Accept any of the ed25519PrivateKey OIDs
453  else
454  BERDecodeError();
455 }
456 
458 {
459  // https://tools.ietf.org/html/rfc8410, section 7 and
460  // https://www.cryptopp.com/wiki/curve25519_keys
461  BERSequenceDecoder privateKeyInfo(bt);
462  word32 version;
463  BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 1); // check version
464 
465  BERSequenceDecoder algorithm(privateKeyInfo);
466  // GetAlgorithmID().BERDecodeAndCheck(algorithm);
467  BERDecodeAndCheckAlgorithmID(algorithm);
468  algorithm.MessageEnd();
469 
470  BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
471  BERDecodePrivateKey(octetString, false, (size_t)privateKeyInfo.RemainingLength());
472  octetString.MessageEnd();
473 
474  bool generatePublicKey = true;
475  if (version == 1)
476  {
477  BERGeneralDecoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
478  SecByteBlock subjectPublicKey;
479  unsigned int unusedBits;
480  BERDecodeBitString(publicKey, subjectPublicKey, unusedBits);
481  CRYPTOPP_ASSERT(unusedBits == 0);
482  CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
483  if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
484  BERDecodeError();
485  std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
486  generatePublicKey = false;
487  publicKey.MessageEnd();
488  }
489 
490  privateKeyInfo.MessageEnd();
491 
492  if (generatePublicKey)
493  Donna::ed25519_publickey(m_pk, m_sk);
494 
495  CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
496 }
497 
499 {
500  // https://tools.ietf.org/html/rfc8410, section 7 and
501  // https://www.cryptopp.com/wiki/curve25519_keys
502  CRYPTOPP_ASSERT(version == 0 || version == 1);
503 
504  DERSequenceEncoder privateKeyInfo(bt);
505  DEREncodeUnsigned<word32>(privateKeyInfo, version);
506 
507  DERSequenceEncoder algorithm(privateKeyInfo);
508  GetAlgorithmID().DEREncode(algorithm);
509  algorithm.MessageEnd();
510 
511  DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
512  DEREncodePrivateKey(octetString);
513  octetString.MessageEnd();
514 
515  if (version == 1)
516  {
517  DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
518  DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH);
519  publicKey.MessageEnd();
520  }
521 
522  privateKeyInfo.MessageEnd();
523 }
524 
525 void ed25519PrivateKey::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
526 {
527  // https://tools.ietf.org/html/rfc8410 and
528  // https://www.cryptopp.com/wiki/curve25519_keys
529 
530  BERGeneralDecoder privateKey(bt, OCTET_STRING);
531 
532  if (!privateKey.IsDefiniteLength())
533  BERDecodeError();
534 
535  size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH);
536  if (size != SECRET_KEYLENGTH)
537  BERDecodeError();
538 
539  // We don't know how to decode them
540  if (parametersPresent)
541  BERDecodeError();
542 
543  privateKey.MessageEnd();
544 }
545 
547 {
548  // https://tools.ietf.org/html/rfc8410
549  DERGeneralEncoder privateKey(bt, OCTET_STRING);
550  privateKey.Put(m_sk, SECRET_KEYLENGTH);
551  privateKey.MessageEnd();
552 }
553 
554 void ed25519PrivateKey::SetPrivateExponent (const byte x[SECRET_KEYLENGTH])
555 {
558  ("Clamp", true));
559 }
560 
561 void ed25519PrivateKey::SetPrivateExponent (const Integer &x)
562 {
563  CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
564 
566  x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
567 
570  ("Clamp", true));
571 }
572 
573 const Integer& ed25519PrivateKey::GetPrivateExponent() const
574 {
576  return m_x;
577 }
578 
579 ////////////////////////
580 
581 ed25519Signer::ed25519Signer(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH])
582 {
586 }
587 
588 ed25519Signer::ed25519Signer(const byte x[SECRET_KEYLENGTH])
589 {
592  ("Clamp", true));
593 }
594 
596 {
598  CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
599 
601  y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
602  x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
603 
607 }
608 
610 {
611  CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
612 
614  x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
615 
618  ("Clamp", true));
619 }
620 
622 {
624 }
625 
627 {
628  AccessPrivateKey().Load(params);
629 }
630 
631 size_t ed25519Signer::SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const
632 {
633  CRYPTOPP_ASSERT(signature != NULLPTR); CRYPTOPP_UNUSED(rng);
634 
635  ed25519_MessageAccumulator& accum = static_cast<ed25519_MessageAccumulator&>(messageAccumulator);
636  const ed25519PrivateKey& pk = static_cast<const ed25519PrivateKey&>(GetPrivateKey());
637  int ret = Donna::ed25519_sign(accum.data(), accum.size(), pk.GetPrivateKeyBytePtr(), pk.GetPublicKeyBytePtr(), signature);
638  CRYPTOPP_ASSERT(ret == 0);
639 
640  if (restart)
641  accum.Restart();
642 
643  return ret == 0 ? SIGNATURE_LENGTH : 0;
644 }
645 
646 // ******************** ed25519 Verifier ************************* //
647 
648 bool ed25519PublicKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
649 {
650  if (std::strcmp(name, Name::PublicElement()) == 0)
651  {
652  this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
653  reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
654  return true;
655  }
656 
657  if (std::strcmp(name, Name::GroupOID()) == 0)
658  {
659  if (m_oid.Empty())
660  return false;
661 
662  this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
663  *reinterpret_cast<OID *>(pValue) = m_oid;
664  return true;
665  }
666 
667  return false;
668 }
669 
671 {
673  if (source.GetValue(Name::PublicElement(), ba))
674  {
675  std::memcpy(m_pk, ba.begin(), PUBLIC_KEYLENGTH);
676  }
677 
678  OID oid;
679  if (source.GetValue(Name::GroupOID(), oid))
680  {
681  m_oid = oid;
682  }
683 }
684 
686 {
687  // We have not yet determined the OID to use for this object.
688  // We can't use OID's decoder because it throws BERDecodeError
689  // if the OIDs do not match.
690  OID oid(bt);
691 
692  if (!m_oid.Empty() && m_oid != oid)
693  BERDecodeError(); // Only accept user specified OID
694  else if (oid == ASN1::curve25519() || oid == ASN1::Ed25519())
695  m_oid = oid; // Accept any of the ed25519PublicKey OIDs
696  else
697  BERDecodeError();
698 }
699 
701 {
702  BERSequenceDecoder publicKeyInfo(bt);
703 
704  BERSequenceDecoder algorithm(publicKeyInfo);
705  // GetAlgorithmID().BERDecodeAndCheck(algorithm);
706  BERDecodeAndCheckAlgorithmID(algorithm);
707  algorithm.MessageEnd();
708 
709  BERDecodePublicKey(publicKeyInfo, false, (size_t)publicKeyInfo.RemainingLength());
710 
711  publicKeyInfo.MessageEnd();
712 }
713 
715 {
716  DERSequenceEncoder publicKeyInfo(bt);
717 
718  DERSequenceEncoder algorithm(publicKeyInfo);
719  GetAlgorithmID().DEREncode(algorithm);
720  algorithm.MessageEnd();
721 
722  DEREncodePublicKey(publicKeyInfo);
723 
724  publicKeyInfo.MessageEnd();
725 }
726 
727 void ed25519PublicKey::BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
728 {
729  // We don't know how to decode them
730  if (parametersPresent)
731  BERDecodeError();
732 
733  SecByteBlock subjectPublicKey;
734  unsigned int unusedBits;
735  BERDecodeBitString(bt, subjectPublicKey, unusedBits);
736 
737  CRYPTOPP_ASSERT(unusedBits == 0);
738  CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
739  if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
740  BERDecodeError();
741 
742  std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
743 }
744 
746 {
748 }
749 
750 void ed25519PublicKey::SetPublicElement (const byte y[PUBLIC_KEYLENGTH])
751 {
752  std::memcpy(m_pk, y, PUBLIC_KEYLENGTH);
753 }
754 
755 void ed25519PublicKey::SetPublicElement (const Integer &y)
756 {
758 
760  y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
761 
762  std::memcpy(m_pk, by, PUBLIC_KEYLENGTH);
763 }
764 
765 const Integer& ed25519PublicKey::GetPublicElement() const
766 {
768  return m_y;
769 }
770 
771 bool ed25519PublicKey::Validate(RandomNumberGenerator &rng, unsigned int level) const
772 {
773  CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(level);
774  return true;
775 }
776 
777 ////////////////////////
778 
779 ed25519Verifier::ed25519Verifier(const byte y[PUBLIC_KEYLENGTH])
780 {
782  (Name::PublicElement(), ConstByteArrayParameter(y, PUBLIC_KEYLENGTH)));
783 }
784 
786 {
787  CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH);
788 
789  SecByteBlock by(PUBLIC_KEYLENGTH);
790  y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
791 
793  (Name::PublicElement(), ConstByteArrayParameter(by, PUBLIC_KEYLENGTH, false)));
794 }
795 
797 {
798  AccessPublicKey().Load(params);
799 }
800 
802 {
803  const ed25519PrivateKey& priv = static_cast<const ed25519PrivateKey&>(signer.GetPrivateKey());
805 }
806 
808 {
809  ed25519_MessageAccumulator& accum = static_cast<ed25519_MessageAccumulator&>(messageAccumulator);
810  const ed25519PublicKey& pk = static_cast<const ed25519PublicKey&>(GetPublicKey());
811  int ret = Donna::ed25519_sign_open(accum.data(), accum.size(), pk.GetPublicKeyBytePtr(), accum.signature());
812  accum.Restart();
813 
814  return ret == 0;
815 }
816 
817 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
static const int SECRET_KEYLENGTH
Size of the private key.
Definition: xed25519.h:480
Ed25519 private key.
Definition: xed25519.h:332
void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params)
Generate a random key or crypto parameters.
Definition: xed25519.cpp:315
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:807
void ClampKeys(byte y[PUBLIC_KEYLENGTH], byte x[SECRET_KEYLENGTH]) const
Clamp a private key.
Definition: xed25519.cpp:110
an unsigned value
Definition: integer.h:85
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: cryptlib.cpp:311
virtual void Load(BufferedTransformation &bt)
Loads a key from a BufferedTransformation.
Definition: cryptlib.h:2316
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:771
const byte * GetPublicKeyBytePtr() const
Retrieve public key byte array.
Definition: xed25519.h:653
void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size)
decode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header ...
Definition: xed25519.cpp:727
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:332
Interface for random number generators.
Definition: cryptlib.h:1349
void MakePublicKey(PublicKey &pub) const
Initializes a public key from this key.
Definition: xed25519.cpp:435
Common C++ header files.
ed25519Verifier()
Create a ed25519Verifier object.
Definition: xed25519.h:674
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:745
SecBlock<byte> typedef.
Definition: secblock.h:1052
BER Sequence Decoder.
Definition: asn.h:309
Interface for buffered transformations.
Definition: cryptlib.h:1564
OID GetAlgorithmID() const
Retrieves the OID of the algorithm.
Definition: xed25519.h:596
void DEREncode(BufferedTransformation &bt) const
Encode this object into a BufferedTransformation.
Definition: xed25519.cpp:714
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
Get a named value.
Definition: xed25519.cpp:369
byte order is little-endian
Definition: cryptlib.h:145
const char * PrivateExponent()
Integer.
Definition: argnames.h:35
PublicKey & AccessPublicKey()
Retrieves a reference to a Public Key.
Definition: xed25519.h:704
const PublicKey & GetPublicKey() const
Retrieves a reference to a Public Key.
Definition: xed25519.h:707
void ClampKeys(byte y[PUBLIC_KEYLENGTH], byte x[SECRET_KEYLENGTH]) const
Clamp a private key.
Definition: xed25519.cpp:351
bool IsClamped(const byte x[SECRET_KEYLENGTH]) const
Determine if private key is clamped.
Definition: xed25519.cpp:358
static const int PUBLIC_KEYLENGTH
Size of the public key.
Definition: xed25519.h:339
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:457
void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
Generate private key in this domain.
Definition: xed25519.cpp:326
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:700
bool Validate(RandomNumberGenerator &rng, unsigned int level) const
Check this object for errors.
Definition: xed25519.cpp:363
void DEREncode(BufferedTransformation &bt) const
DER encode this OID.
Definition: asn.cpp:259
static const int PUBLIC_KEYLENGTH
Size of the public key.
Definition: xed25519.h:483
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:266
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:539
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:154
void AssignFrom(const NameValuePairs &source)
Assign values to this object.
Definition: xed25519.cpp:398
void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size)
decode privateKey part of privateKeyInfo, without the OCTET STRING header
Definition: xed25519.cpp:223
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:60
void BERDecodeError()
Raises a BERDecodeErr.
Definition: asn.h:69
static const int SECRET_KEYLENGTH
Size of the private key.
Definition: xed25519.h:336
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:252
Implementation of BufferedTransformation&#39;s attachment interface.
Ed25519 signature algorithm.
Definition: xed25519.h:476
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:631
bool IsClamped(const byte x[SECRET_KEYLENGTH]) const
Determine if private key is clamped.
Definition: xed25519.cpp:116
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:121
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:56
OID GetAlgorithmID() const
Get the Object Identifier
Definition: xed25519.h:132
virtual void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params=g_nullNameValuePairs)
Generate a random key or crypto parameters.
Definition: cryptlib.h:2376
PrivateKey & AccessPrivateKey()
Retrieves a reference to a Private Key.
Definition: xed25519.h:536
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:670
void BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt)
Determine if OID is valid for this object.
Definition: xed25519.cpp:442
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:338
ed25519Signer()
Create a ed25519Signer object.
Definition: xed25519.h:494
void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size)
decode privateKey part of privateKeyInfo, without the OCTET STRING header
Definition: xed25519.cpp:525
BER General Decoder.
Definition: asn.h:258
const byte * GetPrivateKeyBytePtr() const
Retrieve private key byte array.
Definition: xed25519.h:456
void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params)
Generate a random key or crypto parameters.
Definition: xed25519.cpp:423
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
Get a named value.
Definition: xed25519.cpp:648
OID GetAlgorithmID() const
Retrieves the OID of the algorithm.
Definition: xed25519.h:352
Ed25519 public key.
Definition: xed25519.h:589
static const int SIGNATURE_LENGTH
Size of the siganture.
Definition: xed25519.h:488
void AssignFrom(const NameValuePairs &source)
Assign values to this object.
Definition: xed25519.cpp:295
void DEREncodePrivateKey(BufferedTransformation &bt) const
encode privateKey part of privateKeyInfo, without the OCTET STRING header
Definition: xed25519.cpp:546
Object Identifier.
Definition: asn.h:166
static const int PUBLIC_KEYLENGTH
Size of the public key.
Definition: xed25519.h:593
void BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt)
Determine if OID is valid for this object.
Definition: xed25519.cpp:139
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:244
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:463
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:685