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