diff --git a/donna.h b/donna.h index 926a4521..69883b77 100644 --- a/donna.h +++ b/donna.h @@ -57,7 +57,25 @@ NAMESPACE_BEGIN(CryptoPP) NAMESPACE_BEGIN(Donna) -int curve25519(byte pubkey[32], const byte seckey[32], const byte basepoint[32]); +/// \brief Generate public key +/// \param publicKey byte array for the public key +/// \param secretKey byte array with the private key +/// \returns 0 on success, non-0 otherwise +/// \details This curve25519() overload generates a public key from an existing +/// secret key. Internally curve25519() performs a scalar multiplication +/// using the base point and writes the result to pubkey. +int curve25519(byte publicKey[32], const byte secretKey[32]); + +/// \brief Generate shared key +/// \param sharedKey byte array for the shared secret +/// \param secretKey byte array with the private key +/// \param othersKey byte array with the peer's public key +/// \returns 0 on success, non-0 otherwise +/// \details This curve25519() overload generates a shared key from an existing +/// a secret key and the other party's public key. Internally curve25519() +/// performs a scalar multiplication using the two keys and writes the result +/// to sharedKey. +int curve25519(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]); NAMESPACE_END // Donna NAMESPACE_END // CryptoPP diff --git a/donna_32.cpp b/donna_32.cpp index 08bff4dd..69c7e2f8 100644 --- a/donna_32.cpp +++ b/donna_32.cpp @@ -873,23 +873,29 @@ ANONYMOUS_NAMESPACE_END NAMESPACE_BEGIN(CryptoPP) NAMESPACE_BEGIN(Donna) -int curve25519(byte pubkey[32], const byte seckey[32], const byte basepoint[32]) +int curve25519(byte publicKey[32], const byte secretKey[32]) +{ + const byte basePoint[32] = {9}; + return curve25519(publicKey, secretKey, basePoint); +} + +int curve25519(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]) { limb bp[10], x[10], z[11], zmone[10]; - byte e[32]; int i; + byte e[32]; - for (i = 0; i < 32; ++i) - e[i] = seckey[i]; + for (unsigned int i = 0; i < 32; ++i) + e[i] = secretKey[i]; e[0] &= 248; e[31] &= 127; e[31] |= 64; - fexpand(bp, basepoint); + fexpand(bp, othersKey); cmult(x, z, e, bp); crecip(zmone, z); fmul(z, x, zmone); - fcontract(pubkey, z); + fcontract(sharedKey, z); return 0; } diff --git a/donna_64.cpp b/donna_64.cpp index 16bff906..564a8a92 100644 --- a/donna_64.cpp +++ b/donna_64.cpp @@ -482,24 +482,29 @@ ANONYMOUS_NAMESPACE_END NAMESPACE_BEGIN(CryptoPP) NAMESPACE_BEGIN(Donna) -int curve25519(byte pubkey[32], const byte seckey[32], const byte basepoint[32]) +int curve25519(byte publicKey[32], const byte secretKey[32]) +{ + const byte basePoint[32] = {9}; + return curve25519(publicKey, secretKey, basePoint); +} + +int curve25519(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]) { limb bp[5], x[5], z[5], zmone[5]; uint8_t e[32]; - int i; - for (i = 0;i < 32;++i) - e[i] = seckey[i]; + for (unsigned int i = 0;i < 32;++i) + e[i] = secretKey[i]; e[0] &= 248; e[31] &= 127; e[31] |= 64; - fexpand(bp, basepoint); + fexpand(bp, othersKey); cmult(x, z, e, bp); crecip(zmone, z); fmul(z, x, zmone); - fcontract(pubkey, z); + fcontract(sharedKey, z); return 0; } diff --git a/validat0.cpp b/validat0.cpp index e4138bd5..6155d97f 100644 --- a/validat0.cpp +++ b/validat0.cpp @@ -437,27 +437,30 @@ bool TestCurve25519() SecByteBlock priv1(32), priv2(32), pub1(32), pub2(32), share1(32), share2(32); for (unsigned int i=0; i> 8) & 1); } +int is_clamped(const byte s[32]) +{ + return (s[0] & 248) == s[0] && (s[31] & 127) == s[31] && (s[31] | 64) == s[31]; +} + ANONYMOUS_NAMESPACE_END NAMESPACE_BEGIN(CryptoPP) @@ -71,12 +76,18 @@ x25519::x25519(const byte y[32], const byte x[32]) { std::memcpy(m_pk, y, 32); std::memcpy(m_sk, x, 32); + + CRYPTOPP_ASSERT(is_clamped(m_sk) != 0); + CRYPTOPP_ASSERT(is_small_order(m_pk) == 0); } x25519::x25519(const byte x[32]) { std::memcpy(m_sk, x, 32); GeneratePublicKey(NullRNG(), m_sk, m_pk); + + CRYPTOPP_ASSERT(is_clamped(m_sk) != 0); + CRYPTOPP_ASSERT(is_small_order(m_pk) == 0); } x25519::x25519(const Integer &y, const Integer &x) @@ -86,6 +97,9 @@ x25519::x25519(const Integer &y, const Integer &x) ArraySink xs(m_sk, 32); x.Encode(xs, 32); + + CRYPTOPP_ASSERT(is_clamped(m_sk) != 0); + CRYPTOPP_ASSERT(is_small_order(m_pk) == 0); } x25519::x25519(const Integer &x) @@ -93,46 +107,72 @@ x25519::x25519(const Integer &x) ArraySink xs(m_sk, 32); x.Encode(xs, 32); GeneratePublicKey(NullRNG(), m_sk, m_pk); + + CRYPTOPP_ASSERT(is_clamped(m_sk) != 0); + CRYPTOPP_ASSERT(is_small_order(m_pk) == 0); } x25519::x25519(RandomNumberGenerator &rng) { GeneratePrivateKey(rng, m_sk); GeneratePublicKey(NullRNG(), m_sk, m_pk); + + CRYPTOPP_ASSERT(is_clamped(m_sk) != 0); + CRYPTOPP_ASSERT(is_small_order(m_pk) == 0); } x25519::x25519(BufferedTransformation ¶ms) { - // TODO: Fix the on-disk format once we know what it is. + // TODO: Fix the on-disk format once we determine what it is. BERSequenceDecoder seq(params); - BERGeneralDecoder x(seq, BIT_STRING); - if (!x.IsDefiniteLength() || x.MaxRetrievable() < 32) - BERDecodeError(); - x.Get(m_sk, 32); - x.MessageEnd(); + size_t read; byte unused; - BERGeneralDecoder y(seq, OCTET_STRING); - if (!y.IsDefiniteLength() || y.MaxRetrievable() < 32) - BERDecodeError(); - y.Get(m_pk, 32); - y.MessageEnd(); + BERSequenceDecoder sk(seq, BIT_STRING); + read = sk.Get(unused); // unused bits + CRYPTOPP_ASSERT(read == 1 && unused == 0); + + CRYPTOPP_ASSERT(sk.MaxRetrievable() >= 32); + read = sk.Get(m_sk, 32); + sk.MessageEnd(); + + if (read != 32) + throw BERDecodeErr(); + + 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(); + + if (read != 32) + throw BERDecodeErr(); + } seq.MessageEnd(); + + CRYPTOPP_ASSERT(is_clamped(m_sk) != 0); + CRYPTOPP_ASSERT(is_small_order(m_pk) == 0); } void x25519::DEREncode(BufferedTransformation ¶ms) const { - // TODO: Fix the on-disk format once we know what it is. + // TODO: Fix the on-disk format once we determine what it is. DERSequenceEncoder seq(params); - DERSequenceEncoder x(seq, BIT_STRING); - x.Put(m_sk, 32); - x.MessageEnd(); + DERSequenceEncoder sk(seq, BIT_STRING); + sk.Put((byte)0); // unused bits + sk.Put(m_sk, 32); + sk.MessageEnd(); - DERSequenceEncoder y(seq, OCTET_STRING); - y.Put(m_pk, 32); - y.MessageEnd(); + DERSequenceEncoder pk(seq, OCTET_STRING); + pk.Put(m_pk, 32); + pk.MessageEnd(); seq.MessageEnd(); } @@ -140,8 +180,12 @@ void x25519::DEREncode(BufferedTransformation ¶ms) const bool x25519::Validate(RandomNumberGenerator &rng, unsigned int level) const { CRYPTOPP_UNUSED(rng); + CRYPTOPP_ASSERT(is_clamped(m_sk) != 0); + CRYPTOPP_ASSERT(is_small_order(m_pk) == 0); - if (level >= 2 && is_small_order(m_pk) != 0) + if (level >= 1 && is_clamped(m_sk) == 0) + return false; + else if (level >= 2 && is_small_order(m_pk) != 0) return false; return true;