summaryrefslogtreecommitdiff
path: root/xed25519.cpp
diff options
context:
space:
mode:
authorJeffrey Walton <noloader@gmail.com>2018-12-24 17:17:32 -0500
committerGitHub <noreply@github.com>2018-12-24 17:17:32 -0500
commitd62674b56145b6988cd0a9d8a658dff7cb6d8ec8 (patch)
treea30dc4f20697961ba0f347da15a112e38d88cfab /xed25519.cpp
parent2ba3c1fc73ff490fa335ae649f3ab42e762369f8 (diff)
downloadcryptopp-git-d62674b56145b6988cd0a9d8a658dff7cb6d8ec8.tar.gz
Add ed25519 (GH #764, PR #767)
Add ed25519
Diffstat (limited to 'xed25519.cpp')
-rw-r--r--xed25519.cpp790
1 files changed, 680 insertions, 110 deletions
diff --git a/xed25519.cpp b/xed25519.cpp
index 3d118839..c149c9ed 100644
--- a/xed25519.cpp
+++ b/xed25519.cpp
@@ -1,7 +1,8 @@
// xed25519.cpp - written and placed in public domain by Jeffrey Walton
// Crypto++ specific implementation wrapped around Andrew
-// Moon's public domain curve25519-donna. Also see
-// https://github.com/floodyberry/curve25519-donna.
+// Moon's public domain curve25519-donna and ed25519-donna,
+// https://github.com/floodyberry/curve25519-donna and
+// https://github.com/floodyberry/ed25519-donna.
#include "pch.h"
@@ -9,6 +10,7 @@
#include "asn.h"
#include "integer.h"
#include "filters.h"
+#include "stdcpp.h"
#include "xed25519.h"
#include "donna.h"
@@ -43,68 +45,36 @@ const byte blacklist[][32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
{ 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
- };
+};
ANONYMOUS_NAMESPACE_END
NAMESPACE_BEGIN(CryptoPP)
-bool x25519::IsClamped(const byte x[32])
-{
- return (x[0] & 248) == x[0] && (x[31] & 127) == x[31] && (x[31] | 64) == x[31];
-}
+// ******************** x25519 Agreement ************************* //
-// See the comments for the code in tweetnacl.cpp
-bool x25519::IsSmallOrder(const byte y[32])
+x25519::x25519(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH])
{
- // The magic 12 is the count of blaklisted points
- byte c[12] = { 0 };
- for (size_t j = 0; j < 32; j++) {
- for (size_t i = 0; i < COUNTOF(blacklist); i++) {
- c[i] |= y[j] ^ blacklist[i][j];
- }
- }
-
- unsigned int k = 0;
- for (size_t i = 0; i < COUNTOF(blacklist); i++) {
- k |= (c[i] - 1);
- }
-
- return (bool) ((k >> 8) & 1);
-}
-
-void x25519::ClampKey(byte x[32])
-{
- x[0] &= 248;
- x[31] &= 127;
- x[31] |= 64;
-}
-
-x25519::x25519(const byte y[32], const byte x[32])
-{
- std::memcpy(m_pk, y, 32);
- std::memcpy(m_sk, x, 32);
+ std::memcpy(m_pk, y, SECRET_KEYLENGTH);
+ std::memcpy(m_sk, x, PUBLIC_KEYLENGTH);
CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
}
-x25519::x25519(const byte x[32])
+x25519::x25519(const byte x[SECRET_KEYLENGTH])
{
- std::memcpy(m_sk, x, 32);
- GeneratePublicKey(NullRNG(), m_sk, m_pk);
-
- CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
- CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
+ std::memcpy(m_sk, x, SECRET_KEYLENGTH);
+ Donna::curve25519_mult(m_pk, m_sk);
}
x25519::x25519(const Integer &y, const Integer &x)
{
- ArraySink ys(m_pk, 32);
- y.Encode(ys, 32);
+ CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH);
+ CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
- ArraySink xs(m_sk, 32);
- x.Encode(xs, 32);
+ y.Encode(m_pk, PUBLIC_KEYLENGTH); std::reverse(m_pk+0, m_pk+PUBLIC_KEYLENGTH);
+ x.Encode(m_sk, SECRET_KEYLENGTH); std::reverse(m_sk+0, m_sk+SECRET_KEYLENGTH);
CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
@@ -112,9 +82,11 @@ x25519::x25519(const Integer &y, const Integer &x)
x25519::x25519(const Integer &x)
{
- ArraySink xs(m_sk, 32);
- x.Encode(xs, 32);
- GeneratePublicKey(NullRNG(), m_sk, m_pk);
+ CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
+
+ x.Encode(m_sk, SECRET_KEYLENGTH);
+ std::reverse(m_sk+0, m_sk+SECRET_KEYLENGTH);
+ Donna::curve25519_mult(m_pk, m_sk);
CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
@@ -122,68 +94,156 @@ x25519::x25519(const Integer &x)
x25519::x25519(RandomNumberGenerator &rng)
{
- GeneratePrivateKey(rng, m_sk);
- GeneratePublicKey(NullRNG(), m_sk, m_pk);
-
- CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
- CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
+ rng.GenerateBlock(m_sk, SECRET_KEYLENGTH);
+ m_sk[0] &= 248; m_sk[31] &= 127; m_sk[31] |= 64;
+ Donna::curve25519_mult(m_pk, m_sk);
}
x25519::x25519(BufferedTransformation &params)
{
- // TODO: Fix the on-disk format once we determine what it is.
- BERSequenceDecoder seq(params);
+ Load(params);
+}
- size_t read; byte unused;
+void x25519::ClampKeys(byte y[PUBLIC_KEYLENGTH], byte x[SECRET_KEYLENGTH]) const
+{
+ x[0] &= 248; x[31] &= 127; x[31] |= 64;
+ Donna::curve25519_mult(y, x);
+}
+
+bool x25519::IsClamped(const byte x[SECRET_KEYLENGTH]) const
+{
+ return (x[0] & 248) == x[0] && (x[31] & 127) == x[31] && (x[31] | 64) == x[31];
+}
- BERSequenceDecoder sk(seq, BIT_STRING);
- CRYPTOPP_ASSERT(sk.MaxRetrievable() >= 33);
+bool x25519::IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const
+{
+ // The magic 12 is the count of blaklisted points
+ byte c[12] = { 0 };
+ for (size_t j = 0; j < PUBLIC_KEYLENGTH; j++) {
+ for (size_t i = 0; i < COUNTOF(blacklist); i++) {
+ c[i] |= y[j] ^ blacklist[i][j];
+ }
+ }
- read = sk.Get(unused); // unused bits
- CRYPTOPP_ASSERT(read == 1 && unused == 0);
+ unsigned int k = 0;
+ for (size_t i = 0; i < COUNTOF(blacklist); i++) {
+ k |= (c[i] - 1);
+ }
- read = sk.Get(m_sk, 32);
- sk.MessageEnd();
+ return (bool)((k >> 8) & 1);
+}
- if (read != 32)
- throw BERDecodeErr();
+void x25519::BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt)
+{
+ // We have not yet determined the OID to use for this object.
+ // We can't use OID's decoder because it throws BERDecodeError
+ // if the OIDs do not match.
+ OID oid(bt);
+
+ if (!m_oid.Empty() && m_oid != oid)
+ BERDecodeError(); // Only accept user specified OID
+ else if (oid == ASN1::curve25519() || oid == ASN1::X25519())
+ m_oid = oid; // Accept any of the x25519 OIDs
+ else
+ BERDecodeError();
+}
- if (seq.EndReached())
- {
- GeneratePublicKey(NullRNG(), m_sk, m_pk);
- }
- else
- {
- BERSequenceDecoder pk(seq, OCTET_STRING);
- CRYPTOPP_ASSERT(pk.MaxRetrievable() >= 32);
- read = pk.Get(m_pk, 32);
- pk.MessageEnd();
+void x25519::BERDecode(BufferedTransformation &bt)
+{
+ // https://tools.ietf.org/html/rfc8410, section 7 and
+ // https://www.cryptopp.com/wiki/curve25519_keys
+ BERSequenceDecoder privateKeyInfo(bt);
+ word32 version;
+ BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 1); // check version
+
+ BERSequenceDecoder algorithm(privateKeyInfo);
+ // GetAlgorithmID().BERDecodeAndCheck(algorithm);
+ BERDecodeAndCheckAlgorithmID(algorithm);
+ algorithm.MessageEnd();
+
+ BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
+ BERDecodePrivateKey(octetString, false, (size_t)privateKeyInfo.RemainingLength());
+ octetString.MessageEnd();
+
+ bool generatePublicKey = true;
+ if (version == 1)
+ {
+ BERGeneralDecoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
+ SecByteBlock subjectPublicKey;
+ unsigned int unusedBits;
+ BERDecodeBitString(publicKey, subjectPublicKey, unusedBits);
+ CRYPTOPP_ASSERT(unusedBits == 0);
+ CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
+ if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
+ BERDecodeError();
+ std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
+ generatePublicKey = false;
+ publicKey.MessageEnd();
+ }
- if (read != 32)
- throw BERDecodeErr();
- }
+ privateKeyInfo.MessageEnd();
- seq.MessageEnd();
+ if (generatePublicKey)
+ Donna::curve25519_mult(m_pk, m_sk);
CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false);
}
-void x25519::DEREncode(BufferedTransformation &params) const
+void x25519::DEREncode(BufferedTransformation &bt, int version) const
{
- // TODO: Fix the on-disk format once we determine what it is.
- DERSequenceEncoder seq(params);
+ // https://tools.ietf.org/html/rfc8410, section 7 and
+ // https://www.cryptopp.com/wiki/curve25519_keys
+ CRYPTOPP_ASSERT(version == 0 || version == 1);
- DERSequenceEncoder sk(seq, BIT_STRING);
- sk.Put((byte)0); // unused bits
- sk.Put(m_sk, 32);
- sk.MessageEnd();
+ DERSequenceEncoder privateKeyInfo(bt);
+ DEREncodeUnsigned<word32>(privateKeyInfo, version);
- DERSequenceEncoder pk(seq, OCTET_STRING);
- pk.Put(m_pk, 32);
- pk.MessageEnd();
+ DERSequenceEncoder algorithm(privateKeyInfo);
+ GetAlgorithmID().DEREncode(algorithm);
+ algorithm.MessageEnd();
- seq.MessageEnd();
+ DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
+ DEREncodePrivateKey(octetString);
+ octetString.MessageEnd();
+
+ if (version == 1)
+ {
+ DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
+ DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH);
+ publicKey.MessageEnd();
+ }
+
+ privateKeyInfo.MessageEnd();
+}
+
+void x25519::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
+{
+ // https://tools.ietf.org/html/rfc8410 and
+ // https://www.cryptopp.com/wiki/curve25519_keys
+
+ BERGeneralDecoder privateKey(bt, OCTET_STRING);
+
+ if (!privateKey.IsDefiniteLength())
+ BERDecodeError();
+
+ size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH);
+ if (size != SECRET_KEYLENGTH)
+ BERDecodeError();
+
+ // We don't know how to decode them
+ if (parametersPresent)
+ BERDecodeError();
+
+ privateKey.MessageEnd();
+}
+
+void x25519::DEREncodePrivateKey(BufferedTransformation &bt) const
+{
+ // https://tools.ietf.org/html/rfc8410
+ DERGeneralEncoder privateKey(bt, OCTET_STRING);
+ privateKey.Put(m_sk, SECRET_KEYLENGTH);
+ privateKey.MessageEnd();
}
bool x25519::Validate(RandomNumberGenerator &rng, unsigned int level) const
@@ -202,18 +262,28 @@ bool x25519::Validate(RandomNumberGenerator &rng, unsigned int level) const
bool x25519::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
{
- if (valueType == typeid(ConstByteArrayParameter))
+ if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0)
{
- if (std::strcmp(name, "SecretKey") == 0)
- {
- std::memcpy(pValue, m_sk, 32);
- return true;
- }
- else if (std::strcmp(name, "PublicKey") == 0)
- {
- std::memcpy(pValue, m_pk, 32);
- return true;
- }
+ this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
+ reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false);
+ return true;
+ }
+
+ if (std::strcmp(name, Name::PublicElement()) == 0)
+ {
+ this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
+ reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
+ return true;
+ }
+
+ if (std::strcmp(name, Name::GroupOID()) == 0)
+ {
+ if (m_oid.Empty())
+ return false;
+
+ this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
+ *reinterpret_cast<OID *>(pValue) = m_oid;
+ return true;
}
return false;
@@ -222,27 +292,44 @@ bool x25519::GetVoidValue(const char *name, const std::type_info &valueType, voi
void x25519::AssignFrom(const NameValuePairs &source)
{
ConstByteArrayParameter val;
- if (source.GetValue("SecretKey", val))
+ if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val))
{
- std::memcpy(m_sk, val.begin(), 32);
+ std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH);
}
- else if (source.GetValue("PublicKey", val))
+
+ if (source.GetValue(Name::PublicElement(), val))
{
- std::memcpy(m_pk, val.begin(), 32);
+ std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH);
+ }
+
+ OID oid;
+ if (source.GetValue(Name::GroupOID(), oid))
+ {
+ m_oid = oid;
}
}
+void x25519::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params)
+{
+ ConstByteArrayParameter seed;
+ if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy())
+ rng.IncorporateEntropy(seed.begin(), seed.size());
+
+ rng.GenerateBlock(m_sk, SECRET_KEYLENGTH);
+ m_sk[0] &= 248; m_sk[31] &= 127; m_sk[31] |= 64;
+ Donna::curve25519_mult(m_pk, m_sk);
+}
+
void x25519::GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
{
- rng.GenerateBlock(privateKey, 32);
- ClampKey(privateKey);
+ rng.GenerateBlock(privateKey, SECRET_KEYLENGTH);
+ privateKey[0] &= 248; privateKey[31] &= 127; privateKey[31] |= 64;
}
void x25519::GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
{
CRYPTOPP_UNUSED(rng);
-
- (void)Donna::curve25519(publicKey, privateKey);
+ Donna::curve25519_mult(publicKey, privateKey);
}
bool x25519::Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey) const
@@ -253,7 +340,490 @@ bool x25519::Agree(byte *agreedValue, const byte *privateKey, const byte *otherP
if (validateOtherPublicKey && IsSmallOrder(otherPublicKey))
return false;
- return Donna::curve25519(agreedValue, privateKey, otherPublicKey) == 0;
+ return Donna::curve25519_mult(agreedValue, privateKey, otherPublicKey) == 0;
+}
+
+// ******************** ed25519 Signer ************************* //
+
+void ed25519PrivateKey::ClampKeys(byte y[PUBLIC_KEYLENGTH], byte x[SECRET_KEYLENGTH]) const
+{
+ x[0] &= 248; x[31] &= 127; x[31] |= 64;
+ int ret = Donna::ed25519_publickey(y, x);
+ CRYPTOPP_ASSERT(ret == 0);
+}
+
+bool ed25519PrivateKey::IsClamped(const byte x[SECRET_KEYLENGTH]) const
+{
+ return (x[0] & 248) == x[0] && (x[31] & 127) == x[31] && (x[31] | 64) == x[31];
+}
+
+bool ed25519PrivateKey::Validate(RandomNumberGenerator &rng, unsigned int level) const
+{
+ CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(level);
+ return true;
+}
+
+bool ed25519PrivateKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
+{
+ if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0)
+ {
+ this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
+ reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false);
+ return true;
+ }
+
+ if (std::strcmp(name, Name::PublicElement()) == 0)
+ {
+ this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
+ reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
+ return true;
+ }
+
+ if (std::strcmp(name, Name::GroupOID()) == 0)
+ {
+ if (m_oid.Empty())
+ return false;
+
+ this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
+ *reinterpret_cast<OID *>(pValue) = m_oid;
+ return true;
+ }
+
+ return false;
+}
+
+void ed25519PrivateKey::AssignFrom(const NameValuePairs &source)
+{
+ ConstByteArrayParameter val;
+ if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val))
+ {
+ CRYPTOPP_ASSERT(val.size() == SECRET_KEYLENGTH);
+ std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH);
+ }
+ if (source.GetValue(Name::PublicElement(), val))
+ {
+ CRYPTOPP_ASSERT(val.size() == PUBLIC_KEYLENGTH);
+ std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH);
+ }
+
+ OID oid;
+ if (source.GetValue(Name::GroupOID(), oid))
+ {
+ m_oid = oid;
+ }
+
+ bool clamp = false;
+ if (source.GetValue("Clamp", clamp) && clamp == true)
+ ClampKeys(m_pk, m_sk);
+}
+
+void ed25519PrivateKey::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params=g_nullNameValuePairs)
+{
+ ConstByteArrayParameter seed;
+ if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy())
+ rng.IncorporateEntropy(seed.begin(), seed.size());
+
+ rng.GenerateBlock(m_sk, 32);
+ m_sk[0] &= 248; m_sk[31] &= 127; m_sk[31] |= 64;
+ int ret = Donna::ed25519_publickey(m_pk, m_sk);
+ CRYPTOPP_ASSERT(ret == 0);
+}
+
+void ed25519PrivateKey::MakePublicKey (PublicKey &pub) const
+{
+ pub.AssignFrom(MakeParameters
+ (Name::PublicElement(), ConstByteArrayParameter(m_pk.begin(), PUBLIC_KEYLENGTH))
+ (Name::GroupOID(), GetAlgorithmID()));
+}
+
+void ed25519PrivateKey::BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt)
+{
+ // We have not yet determined the OID to use for this object.
+ // We can't use OID's decoder because it throws BERDecodeError
+ // if the OIDs do not match.
+ OID oid(bt);
+
+ if (!m_oid.Empty() && m_oid != oid)
+ BERDecodeError(); // Only accept user specified OID
+ else if (oid == ASN1::curve25519() || oid == ASN1::Ed25519())
+ m_oid = oid; // Accept any of the ed25519PrivateKey OIDs
+ else
+ BERDecodeError();
+}
+
+void ed25519PrivateKey::BERDecode(BufferedTransformation &bt)
+{
+ // https://tools.ietf.org/html/rfc8410, section 7 and
+ // https://www.cryptopp.com/wiki/curve25519_keys
+ BERSequenceDecoder privateKeyInfo(bt);
+ word32 version;
+ BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 1); // check version
+
+ BERSequenceDecoder algorithm(privateKeyInfo);
+ // GetAlgorithmID().BERDecodeAndCheck(algorithm);
+ BERDecodeAndCheckAlgorithmID(algorithm);
+ algorithm.MessageEnd();
+
+ BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
+ BERDecodePrivateKey(octetString, false, (size_t)privateKeyInfo.RemainingLength());
+ octetString.MessageEnd();
+
+ bool generatePublicKey = true;
+ if (version == 1)
+ {
+ BERGeneralDecoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
+ SecByteBlock subjectPublicKey;
+ unsigned int unusedBits;
+ BERDecodeBitString(publicKey, subjectPublicKey, unusedBits);
+ CRYPTOPP_ASSERT(unusedBits == 0);
+ CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
+ if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
+ BERDecodeError();
+ std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
+ generatePublicKey = false;
+ publicKey.MessageEnd();
+ }
+
+ privateKeyInfo.MessageEnd();
+
+ if (generatePublicKey)
+ Donna::ed25519_publickey(m_pk, m_sk);
+
+ CRYPTOPP_ASSERT(IsClamped(m_sk) == true);
+}
+
+void ed25519PrivateKey::DEREncode(BufferedTransformation &bt, int version) const
+{
+ // https://tools.ietf.org/html/rfc8410, section 7 and
+ // https://www.cryptopp.com/wiki/curve25519_keys
+ CRYPTOPP_ASSERT(version == 0 || version == 1);
+
+ DERSequenceEncoder privateKeyInfo(bt);
+ DEREncodeUnsigned<word32>(privateKeyInfo, version);
+
+ DERSequenceEncoder algorithm(privateKeyInfo);
+ GetAlgorithmID().DEREncode(algorithm);
+ algorithm.MessageEnd();
+
+ DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
+ DEREncodePrivateKey(octetString);
+ octetString.MessageEnd();
+
+ if (version == 1)
+ {
+ DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1);
+ DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH);
+ publicKey.MessageEnd();
+ }
+
+ privateKeyInfo.MessageEnd();
+}
+
+void ed25519PrivateKey::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
+{
+ // https://tools.ietf.org/html/rfc8410 and
+ // https://www.cryptopp.com/wiki/curve25519_keys
+
+ BERGeneralDecoder privateKey(bt, OCTET_STRING);
+
+ if (!privateKey.IsDefiniteLength())
+ BERDecodeError();
+
+ size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH);
+ if (size != SECRET_KEYLENGTH)
+ BERDecodeError();
+
+ // We don't know how to decode them
+ if (parametersPresent)
+ BERDecodeError();
+
+ privateKey.MessageEnd();
+}
+
+void ed25519PrivateKey::DEREncodePrivateKey(BufferedTransformation &bt) const
+{
+ // https://tools.ietf.org/html/rfc8410
+ DERGeneralEncoder privateKey(bt, OCTET_STRING);
+ privateKey.Put(m_sk, SECRET_KEYLENGTH);
+ privateKey.MessageEnd();
+}
+
+void ed25519PrivateKey::SetPrivateExponent (const byte x[SECRET_KEYLENGTH])
+{
+ AssignFrom(MakeParameters
+ (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH))
+ ("Clamp", true));
+}
+
+void ed25519PrivateKey::SetPrivateExponent (const Integer &x)
+{
+ CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
+
+ SecByteBlock bx(SECRET_KEYLENGTH);
+ x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
+
+ AssignFrom(MakeParameters
+ (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false))
+ ("Clamp", true));
+}
+
+const Integer& ed25519PrivateKey::GetPrivateExponent() const
+{
+ m_x = Integer(m_sk, SECRET_KEYLENGTH, Integer::UNSIGNED, LITTLE_ENDIAN_ORDER);
+ return m_x;
+}
+
+////////////////////////
+
+ed25519Signer::ed25519Signer(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH])
+{
+ AccessPrivateKey().AssignFrom(MakeParameters
+ (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH, false))
+ (Name::PublicElement(), ConstByteArrayParameter(y, PUBLIC_KEYLENGTH, false)));
+}
+
+ed25519Signer::ed25519Signer(const byte x[SECRET_KEYLENGTH])
+{
+ AccessPrivateKey().AssignFrom(MakeParameters
+ (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH, false))
+ ("Clamp", true));
+}
+
+ed25519Signer::ed25519Signer(const Integer &y, const Integer &x)
+{
+ CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH);
+ CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
+
+ SecByteBlock by(PUBLIC_KEYLENGTH), bx(SECRET_KEYLENGTH);
+ y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
+ x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
+
+ AccessPrivateKey().AssignFrom(MakeParameters
+ (Name::PublicElement(), ConstByteArrayParameter(by, PUBLIC_KEYLENGTH, false))
+ (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false)));
+}
+
+ed25519Signer::ed25519Signer(const Integer &x)
+{
+ CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH);
+
+ SecByteBlock bx(SECRET_KEYLENGTH);
+ x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH);
+
+ AccessPrivateKey().AssignFrom(MakeParameters
+ (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false))
+ ("Clamp", true));
+}
+
+ed25519Signer::ed25519Signer(RandomNumberGenerator &rng)
+{
+ AccessPrivateKey().GenerateRandom(rng);
+}
+
+ed25519Signer::ed25519Signer(BufferedTransformation &params)
+{
+ ed25519PrivateKey& key = static_cast<ed25519PrivateKey&>(AccessPrivateKey());
+ key.BERDecode(params);
+}
+
+size_t ed25519Signer::SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const
+{
+ CRYPTOPP_ASSERT(signature != NULLPTR); CRYPTOPP_UNUSED(rng);
+
+ ed25519_MessageAccumulator& accum = static_cast<ed25519_MessageAccumulator&>(messageAccumulator);
+ const ed25519PrivateKey& pk = static_cast<const ed25519PrivateKey&>(GetPrivateKey());
+ int ret = Donna::ed25519_sign(accum.data(), accum.size(), pk.m_sk, pk.m_pk, signature);
+ CRYPTOPP_ASSERT(ret == 0);
+
+ if (restart)
+ accum.Restart();
+
+ return ret == 0 ? SIGNATURE_LENGTH : 0;
+}
+
+// ******************** ed25519 Verifier ************************* //
+
+bool ed25519PublicKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
+{
+ if (std::strcmp(name, Name::PublicElement()) == 0)
+ {
+ this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType);
+ reinterpret_cast<ConstByteArrayParameter*>(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false);
+ return true;
+ }
+
+ if (std::strcmp(name, Name::GroupOID()) == 0)
+ {
+ if (m_oid.Empty())
+ return false;
+
+ this->ThrowIfTypeMismatch(name, typeid(OID), valueType);
+ *reinterpret_cast<OID *>(pValue) = m_oid;
+ return true;
+ }
+
+ return false;
+}
+
+void ed25519PublicKey::AssignFrom(const NameValuePairs &source)
+{
+ ConstByteArrayParameter ba;
+ if (source.GetValue(Name::PublicElement(), ba))
+ {
+ std::memcpy(m_pk, ba.begin(), PUBLIC_KEYLENGTH);
+ }
+
+ OID oid;
+ if (source.GetValue(Name::GroupOID(), oid))
+ {
+ m_oid = oid;
+ }
+}
+
+void ed25519PublicKey::BERDecodeAndCheckAlgorithmID(BufferedTransformation& bt)
+{
+ // We have not yet determined the OID to use for this object.
+ // We can't use OID's decoder because it throws BERDecodeError
+ // if the OIDs do not match.
+ OID oid(bt);
+
+ if (!m_oid.Empty() && m_oid != oid)
+ BERDecodeError(); // Only accept user specified OID
+ else if (oid == ASN1::curve25519() || oid == ASN1::Ed25519())
+ m_oid = oid; // Accept any of the ed25519PublicKey OIDs
+ else
+ BERDecodeError();
+}
+
+void ed25519PublicKey::BERDecode(BufferedTransformation &bt)
+{
+ BERSequenceDecoder publicKeyInfo(bt);
+
+ BERSequenceDecoder algorithm(publicKeyInfo);
+ // GetAlgorithmID().BERDecodeAndCheck(algorithm);
+ BERDecodeAndCheckAlgorithmID(algorithm);
+ algorithm.MessageEnd();
+
+ BERDecodePublicKey(publicKeyInfo, false, (size_t)publicKeyInfo.RemainingLength());
+
+ publicKeyInfo.MessageEnd();
+}
+
+void ed25519PublicKey::DEREncode(BufferedTransformation &bt) const
+{
+ DERSequenceEncoder publicKeyInfo(bt);
+
+ DERSequenceEncoder algorithm(publicKeyInfo);
+ GetAlgorithmID().DEREncode(algorithm);
+ algorithm.MessageEnd();
+
+ DEREncodePublicKey(publicKeyInfo);
+
+ publicKeyInfo.MessageEnd();
+}
+
+void ed25519PublicKey::BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/)
+{
+ // We don't know how to decode them
+ if (parametersPresent)
+ BERDecodeError();
+
+ SecByteBlock subjectPublicKey;
+ unsigned int unusedBits;
+ BERDecodeBitString(bt, subjectPublicKey, unusedBits);
+
+ CRYPTOPP_ASSERT(unusedBits == 0);
+ CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH);
+ if (subjectPublicKey.size() != PUBLIC_KEYLENGTH)
+ BERDecodeError();
+
+ std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH);
+}
+
+void ed25519PublicKey::DEREncodePublicKey(BufferedTransformation &bt) const
+{
+ DEREncodeBitString(bt, m_pk, PUBLIC_KEYLENGTH);
+}
+
+void ed25519PublicKey::SetPublicElement (const byte y[PUBLIC_KEYLENGTH])
+{
+ std::memcpy(m_pk, y, PUBLIC_KEYLENGTH);
+}
+
+void ed25519PublicKey::SetPublicElement (const Integer &y)
+{
+ CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH);
+
+ SecByteBlock by(PUBLIC_KEYLENGTH);
+ y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
+
+ std::memcpy(m_pk, by, PUBLIC_KEYLENGTH);
+}
+
+const Integer& ed25519PublicKey::GetPublicElement() const
+{
+ m_y = Integer(m_pk, PUBLIC_KEYLENGTH, Integer::UNSIGNED, LITTLE_ENDIAN_ORDER);
+ return m_y;
+}
+
+bool ed25519PublicKey::Validate(RandomNumberGenerator &rng, unsigned int level) const
+{
+ CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(level);
+ return true;
+}
+
+////////////////////////
+
+ed25519Verifier::ed25519Verifier(const byte y[PUBLIC_KEYLENGTH])
+{
+ AccessPublicKey().AssignFrom(MakeParameters
+ (Name::PublicElement(), ConstByteArrayParameter(y, PUBLIC_KEYLENGTH)));
+}
+
+ed25519Verifier::ed25519Verifier(const Integer &y)
+{
+ CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH);
+
+ SecByteBlock by(PUBLIC_KEYLENGTH);
+ y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH);
+
+ AccessPublicKey().AssignFrom(MakeParameters
+ (Name::PublicElement(), ConstByteArrayParameter(by, PUBLIC_KEYLENGTH, false)));
+}
+
+ed25519Verifier::ed25519Verifier(BufferedTransformation &params)
+{
+ // TODO: Fix the on-disk format once we determine what it is.
+ BERSequenceDecoder seq(params);
+
+ size_t read;
+ BERSequenceDecoder pk(seq, OCTET_STRING);
+
+ CRYPTOPP_ASSERT(pk.MaxRetrievable() >= PUBLIC_KEYLENGTH);
+ read = pk.Get(m_key.m_pk, PUBLIC_KEYLENGTH);
+
+ pk.MessageEnd();
+
+ if (read != PUBLIC_KEYLENGTH)
+ throw BERDecodeErr();
+
+ seq.MessageEnd();
+}
+
+ed25519Verifier::ed25519Verifier(const ed25519Signer& signer)
+{
+ const ed25519PrivateKey& priv = static_cast<const ed25519PrivateKey&>(signer.GetPrivateKey());
+ priv.MakePublicKey(AccessPublicKey());
+}
+
+bool ed25519Verifier::VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const
+{
+ ed25519_MessageAccumulator& accum = static_cast<ed25519_MessageAccumulator&>(messageAccumulator);
+ const ed25519PublicKey& pk = static_cast<const ed25519PublicKey&>(GetPublicKey());
+ int ret = Donna::ed25519_sign_open(accum.data(), accum.size(), pk.m_pk.begin(), accum.signature());
+ accum.Restart();
+
+ return ret == 0;
}
NAMESPACE_END // CryptoPP