From e97d6d0ff5c5ae428d70954116f1587d09227772 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Wed, 12 Dec 2018 03:56:09 -0500 Subject: Fix failed self test when NO_OS_DEPENDENCE (GH #761) Add is_clamped for secret key validation. Cleanup paramter names in Donna::curve25519 to follow function. Overload Donna::curve25519 to implicitly use base point if not provided. Add additional asserts to let the code debug itself. Update documentation. --- xed25519.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 19 deletions(-) (limited to 'xed25519.cpp') diff --git a/xed25519.cpp b/xed25519.cpp index b97182e4..f00347f3 100644 --- a/xed25519.cpp +++ b/xed25519.cpp @@ -63,6 +63,11 @@ int is_small_order(const byte s[32]) return (int) ((k >> 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; + + 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(); - BERGeneralDecoder y(seq, OCTET_STRING); - if (!y.IsDefiniteLength() || y.MaxRetrievable() < 32) - BERDecodeError(); - y.Get(m_pk, 32); - y.MessageEnd(); + 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; -- cgit v1.2.1