diff --git a/src/public_include/decaf/crypto.hxx b/src/public_include/decaf/crypto.hxx index 00b332c..f86f3ff 100644 --- a/src/public_include/decaf/crypto.hxx +++ b/src/public_include/decaf/crypto.hxx @@ -51,7 +51,7 @@ public: } /** @brief Set the public key to a point */ - inline explicit PublicKey(const typename Group::Point &p) NOEXCEPT : ser(SecureBuffer(p)) {} + inline explicit PublicKey(const typename Group::Point &p) NOEXCEPT : ser(p.serialize()) {} /** @brief Get the private key for a given public key */ inline explicit PublicKey(const PrivateKey &priv) NOEXCEPT; @@ -111,7 +111,7 @@ public: inline PrivateKey(Rng &r) : sym(r), scalar(SHAKE::hash(sym, SCALAR_HASH_BYTES)), - pub_(SecureBuffer(Group::Precomputed::base() * scalar)) {} + pub_((Group::Precomputed::base() * scalar).serialize()) {} /** @brief Construct from buffer */ inline PrivateKey(const FixedBlock &sym_) : @@ -134,16 +134,16 @@ public: } /** @brief Sign from a SHAKE context. TODO: double check random oracle eval of this; destructive version? */ - inline SecureBuffer sign_shake(const SHAKE &ctx_) NOEXCEPT { + inline SecureBuffer sign_shake(const SHAKE &ctx_) throw(std::bad_alloc) { SHAKE ctx(ctx_); ctx << sym << "decaf_255_sign_shake"; typename Group::Scalar nonce(ctx.output(SCALAR_HASH_BYTES)); - SecureBuffer g_nonce(Group::Precomputed::base() * nonce); /* FIXME: make output fixed size, avoid std::bad_alloc */ + SecureBuffer g_nonce = (Group::Precomputed::base() * nonce).serialize(); ctx = ctx_; ctx << pub_.ser << g_nonce; SecureBuffer challenge(ctx.output(PublicKey::CHALLENGE_BYTES)); - SecureBuffer response((nonce - scalar * typename Group::Scalar(challenge)).encode()); + SecureBuffer response((nonce - scalar * typename Group::Scalar(challenge)).serialize()); SecureBuffer ret(PublicKey::SIG_BYTES); Buffer(ret).slice(0,Group::Point::SER_BYTES).assign(g_nonce); diff --git a/src/public_include/decaf/decaf_255.hxx b/src/public_include/decaf/decaf_255.hxx index a91805b..e06111f 100644 --- a/src/public_include/decaf/decaf_255.hxx +++ b/src/public_include/decaf/decaf_255.hxx @@ -38,8 +38,10 @@ /** @cond internal */ #if __cplusplus >= 201103L #define NOEXCEPT noexcept +#define FINAL final #else #define NOEXCEPT throw() +#define FINAL #endif /** @endcond */ @@ -64,8 +66,9 @@ class Precomputed; /** * @brief A scalar modulo the curve order. * Supports the usual arithmetic operations, all in constant time. + * FIXME: make it clearer which init-from-buffer operations reject scalars that are too big. */ -class Scalar { +class Scalar : public Serializable { private: /** @brief wrapped C type */ typedef decaf_255_scalar_t Wrapped; @@ -100,6 +103,14 @@ public: /** @brief Construct from arbitrary-length little-endian byte sequence. */ inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; } + + /** @brief Serializable instance */ + virtual inline size_t serSize() const NOEXCEPT FINAL { return SER_BYTES; } + + /** @brief Serializable instance */ + virtual inline void serializeInto(unsigned char *buffer) const NOEXCEPT FINAL { + decaf_255_scalar_encode(buffer, s); + } /** @brief Assignment. */ inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_255_scalar_copy(s,x.s); return *this; } @@ -133,21 +144,6 @@ public: return decaf_255_scalar_decode(sc.s,buffer.data()); } - /** @brief Encode to fixed-length string */ - inline operator SecureBuffer() const NOEXCEPT { - SecureBuffer buf(SER_BYTES); encode(buf); return buf; - } - - /** @brief Encode to fixed-length buffer */ - inline void encode(FixedBuffer buffer) const NOEXCEPT{ - decaf_255_scalar_encode(buffer.data(), s); - } - - /** @brief Encode to fixed-length buffer */ - inline SecureBuffer encode() const throw(std::bad_alloc) { - SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer; - } - /** Add. */ inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_add(r.s,s,q.s); return r; } @@ -201,7 +197,7 @@ public: /** * @brief Element of prime-order group. */ -class Point { +class Point : public Serializable { public: typedef decaf_255_point_t Wrapped; @@ -242,17 +238,6 @@ public: set_to_hash(b); } } - - /** - * @brief Initialize from C++ fixed-length byte string. - * The all-zero string maps to the identity. - * - * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, - * or was the identity and allow_identity was DECAF_FALSE. - */ - inline explicit Point(const Block &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) { - if (!decode(*this,s,allow_identity)) throw CryptoException(); - } /** * @brief Initialize from a fixed-length byte string. @@ -261,7 +246,7 @@ public: * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, * or was the identity and allow_identity was DECAF_FALSE. */ - inline explicit Point(const FixedBuffer buffer, decaf_bool_t allow_identity=DECAF_TRUE) + inline explicit Point(const FixedBlock &buffer, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); } /** @@ -273,7 +258,7 @@ public: * or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined. */ static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( - Point &p, const FixedBlock buffer, decaf_bool_t allow_identity=DECAF_TRUE + Point &p, const FixedBlock &buffer, decaf_bool_t allow_identity=DECAF_TRUE ) NOEXCEPT { return decaf_255_point_decode(p.p,buffer.data(),allow_identity); } @@ -309,24 +294,13 @@ public: decaf_255_point_from_hash_uniform(p,s.data()); } } - - /** - * @brief Encode to string. The identity encodes to the all-zero string. - */ - inline operator SecureBuffer() const NOEXCEPT { - SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer; - } - - /** - * @brief Encode to a C buffer. The identity encodes to all zeros. - */ - inline void encode(FixedBuffer buffer) const NOEXCEPT { - decaf_255_point_encode(buffer.data(), p); - } - /** @brief Encode to fixed-length buffer */ - inline SecureBuffer encode() const throw(std::bad_alloc) { - SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer; + /** @brief Serializable instance */ + virtual inline size_t serSize() const NOEXCEPT FINAL { return SER_BYTES; } + + /** @brief Serializable instance */ + virtual inline void serializeInto(unsigned char *buffer) const NOEXCEPT FINAL { + decaf_255_point_encode(buffer, p); } /** @brief Point add. */ @@ -570,6 +544,7 @@ inline SecureBuffer IsoEd25519::Scalar::direct_scalarmul ( /** endcond */ #undef NOEXCEPT +#undef FINAL } /* namespace decaf */ #endif /* __DECAF_255_HXX__ */ diff --git a/src/public_include/decaf/decaf_448.hxx b/src/public_include/decaf/decaf_448.hxx index 47aa969..3913ebc 100644 --- a/src/public_include/decaf/decaf_448.hxx +++ b/src/public_include/decaf/decaf_448.hxx @@ -38,8 +38,10 @@ /** @cond internal */ #if __cplusplus >= 201103L #define NOEXCEPT noexcept +#define FINAL final #else #define NOEXCEPT throw() +#define FINAL #endif /** @endcond */ @@ -65,7 +67,7 @@ class Precomputed; * @brief A scalar modulo the curve order. * Supports the usual arithmetic operations, all in constant time. */ -class Scalar { +class Scalar : public Serializable { private: /** @brief wrapped C type */ typedef decaf_448_scalar_t Wrapped; @@ -133,14 +135,12 @@ public: return decaf_448_scalar_decode(sc.s,buffer.data()); } - /** @brief Encode to fixed-length buffer */ - inline void encode(FixedBuffer buffer) const NOEXCEPT{ - decaf_448_scalar_encode(buffer.data(), s); - } + /** @brief Serializable instance */ + virtual inline size_t serSize() const NOEXCEPT FINAL { return SER_BYTES; } - /** @brief Encode to fixed-length buffer */ - inline SecureBuffer encode() const throw(std::bad_alloc) { - SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer; + /** @brief Serializable instance */ + virtual inline void serializeInto(unsigned char *buffer) const NOEXCEPT FINAL { + decaf_448_scalar_encode(buffer, s); } /** Add. */ @@ -201,7 +201,7 @@ public: /** * @brief Element of prime-order group. */ -class Point { +class Point : public Serializable { public: /** @brief Size of a serialized element */ static const size_t SER_BYTES = DECAF_448_SER_BYTES; @@ -240,17 +240,6 @@ public: set_to_hash(b); } } - - /** - * @brief Initialize from C++ fixed-length byte string. - * The all-zero string maps to the identity. - * - * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, - * or was the identity and allow_identity was DECAF_FALSE. - */ - inline explicit Point(const Block &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) { - if (!decode(*this,s,allow_identity)) throw CryptoException(); - } /** * @brief Initialize from a fixed-length byte string. @@ -259,7 +248,7 @@ public: * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, * or was the identity and allow_identity was DECAF_FALSE. */ - inline explicit Point(const FixedBuffer buffer, decaf_bool_t allow_identity=DECAF_TRUE) + inline explicit Point(const FixedBlock &buffer, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); } /** @@ -271,7 +260,7 @@ public: * or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined. */ static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( - Point &p, const FixedBlock buffer, decaf_bool_t allow_identity=DECAF_TRUE + Point &p, const FixedBlock &buffer, decaf_bool_t allow_identity=DECAF_TRUE ) NOEXCEPT { return decaf_448_point_decode(p.p,buffer.data(),allow_identity); } @@ -316,17 +305,13 @@ public: decaf_448_point_encode(buffer.data(), p); return buffer; } - - /** - * @brief Encode to a C buffer. The identity encodes to all zeros. - */ - inline void encode(FixedBuffer buffer) const NOEXCEPT{ - decaf_448_point_encode(buffer.data(), p); - } - - /** @brief Encode to fixed-length buffer */ - inline SecureBuffer encode() const throw(std::bad_alloc) { - SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer; + + /** @brief Serializable instance */ + virtual inline size_t serSize() const NOEXCEPT FINAL { return SER_BYTES; } + + /** @brief Serializable instance */ + virtual inline void serializeInto(unsigned char *buffer) const NOEXCEPT FINAL { + decaf_448_point_encode(buffer, p); } /** @brief Point add. */ @@ -559,6 +544,7 @@ public: }; /* struct Decaf448 */ #undef NOEXCEPT +#undef FINAL } /* namespace decaf */ #endif /* __DECAF_448_HXX__ */ diff --git a/src/public_include/decaf/secure_buffer.hxx b/src/public_include/decaf/secure_buffer.hxx index 58c6477..5550bf4 100644 --- a/src/public_include/decaf/secure_buffer.hxx +++ b/src/public_include/decaf/secure_buffer.hxx @@ -87,6 +87,38 @@ public: typedef std::vector > SecureBuffer; +/** Constant-time compare two buffers */ +template +inline bool memeq(const std::vector &a, const std::vector &b) { + if (a.size() != b.size()) return false; + return decaf_memeq(a.data(),b.data(),a.size()); +} + +/** Base class of objects which support serialization */ +class Serializable { +public: + /** @brief Return the number of bytes needed to serialize this object */ + virtual inline size_t serSize() const NOEXCEPT = 0; + + /** @brief Serialize this object into a buffer */ + virtual inline void serializeInto(unsigned char *buf) const NOEXCEPT = 0; + + /** @brief Serialize this object into a SecureBuffer and return it */ + inline SecureBuffer serialize() const throw(std::bad_alloc) { + SecureBuffer out(serSize()); + serializeInto(out.data()); + return out; + } + + /** Cast operator */ +#if __cplusplus >= 201103L + explicit +#endif + inline operator SecureBuffer() const throw(std::bad_alloc) { + return serialize(); + } +}; + /**@cond internal*/ class Buffer; /**@endcond*/ @@ -188,6 +220,11 @@ public: if (b.size() != size()) return false; return decaf_memeq(b.data(),data(),size()); } + + /* Create new block from this */ + inline operator SecureBuffer() const throw(std::bad_alloc) { + return SecureBuffer(data_,data_+size_); + } /** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */ inline virtual ~Block() {}; diff --git a/src/public_include/decaf/shake.hxx b/src/public_include/decaf/shake.hxx index 913e3d7..2aa5443 100644 --- a/src/public_include/decaf/shake.hxx +++ b/src/public_include/decaf/shake.hxx @@ -214,28 +214,43 @@ public: if (!strobe_key(sp, data.data(), data.size(), more)) throw ProtocolException(); } - inline void nonce(const Block &data, bool more = false + inline void key ( + const Serializable &data, bool more = false ) throw(ProtocolException) { + key(data.serialize(), more); + } + + inline void nonce(const Block &data, bool more = false) throw(ProtocolException) { if (!strobe_nonce(sp, data.data(), data.size(), more)) throw ProtocolException(); } - inline void send_plaintext(const Block &data, bool more = false - ) throw(ProtocolException) { + inline void send_plaintext(const Block &data, bool more = false) throw(ProtocolException) { if (!strobe_plaintext(sp, data.data(), data.size(), true, more)) throw(ProtocolException()); } + inline void send_plaintext(const Serializable &data, bool more = false) throw(ProtocolException) { + send_plaintext(data.serialize(), more); + } + inline void recv_plaintext(const Block &data, bool more = false ) throw(ProtocolException) { if (!strobe_plaintext(sp, data.data(), data.size(), false, more)) throw(ProtocolException()); } - inline void ad(const Block &data, bool more = false - ) throw(ProtocolException) { + inline void recv_plaintext(const Serializable &data, bool more = false) throw(ProtocolException) { + recv_plaintext(data.serialize(), more); + } + + inline void ad(const Block &data, bool more = false) throw(ProtocolException) { if (!strobe_ad(sp, data.data(), data.size(), more)) throw(ProtocolException()); } + + inline void ad(const Serializable &data, bool more = false) throw(ProtocolException) { + ad(data.serialize(), more); + } inline void encrypt_no_auth( Buffer out, const Block &data, bool more = false @@ -249,6 +264,11 @@ public: SecureBuffer out(data.size()); encrypt_no_auth(out, data, more); return out; } + inline SecureBuffer encrypt_no_auth(const Serializable &data, bool more = false + ) throw(ProtocolException) { + return encrypt_no_auth(data.serialize(), more); + } + inline void decrypt_no_auth( Buffer out, const Block &data, bool more = false ) throw(LengthException,ProtocolException) { @@ -261,6 +281,11 @@ public: SecureBuffer out(data.size()); decrypt_no_auth(out, data, more); return out; } + inline SecureBuffer decrypt_no_auth(const Serializable &data, bool more = false + ) throw(ProtocolException) { + return decrypt_no_auth(data.serialize(),more); + } + inline void produce_auth(Buffer out) throw(LengthException,ProtocolException) { if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); if (!strobe_produce_auth(sp, out.data(), out.size())) throw ProtocolException(); @@ -286,6 +311,12 @@ public: SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out; } + inline SecureBuffer encrypt ( + const Serializable &data, uint8_t auth = 8 + ) throw(LengthException,ProtocolException,std::bad_alloc ){ + return encrypt(data.serialize(), auth); + } + inline void decrypt ( Buffer out, const Block &data, uint8_t bytes = 8 ) throw(LengthException, CryptoException, ProtocolException) { @@ -294,6 +325,12 @@ public: verify_auth(data.slice(out.size(),bytes)); } + inline SecureBuffer decrypt ( + const Serializable &data, uint8_t auth = 8 + ) throw(LengthException,ProtocolException,CryptoException, std::bad_alloc ){ + return decrypt(data.serialize(), auth); + } + inline SecureBuffer decrypt ( const Block &data, uint8_t bytes = 8 ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { diff --git a/test/bench_decaf.cxx b/test/bench_decaf.cxx index c0e635b..f16e8e1 100644 --- a/test/bench_decaf.cxx +++ b/test/bench_decaf.cxx @@ -283,7 +283,7 @@ static void macro() { printf("Protocol benchmarks:\n"); SpongeRng clientRng(Block("client rng seed")); SpongeRng serverRng(Block("server rng seed")); - SecureBuffer hashedPassword("hello world"); + SecureBuffer hashedPassword(Block("hello world")); for (Benchmark b("Spake2ee c+s",0.1); b.iter(); ) { spake2ee(clientRng, serverRng, hashedPassword,false); } diff --git a/test/test_decaf.cxx b/test/test_decaf.cxx index ac12b8d..147bb1d 100644 --- a/test/test_decaf.cxx +++ b/test/test_decaf.cxx @@ -51,7 +51,7 @@ typedef typename Group::Precomputed Precomputed; static void print(const char *name, const Scalar &x) { unsigned char buffer[Scalar::SER_BYTES]; - x.encode(FixedBuffer(buffer)); + x.serializeInto(buffer); printf(" %s = 0x", name); for (int i=sizeof(buffer)-1; i>=0; i--) { printf("%02x", buffer[i]); @@ -68,8 +68,8 @@ static void hexprint(const char *name, const SecureBuffer &buffer) { } static void print(const char *name, const Point &x) { - FixedArrayBuffer buffer; - x.encode(buffer); + unsigned char buffer[Point::SER_BYTES]; + x.serializeInto(buffer); printf(" %s = 0x", name); for (int i=Point::SER_BYTES-1; i>=0; i--) { printf("%02x", buffer[i]); @@ -284,9 +284,9 @@ static void test_ec() { rng.read(buffer); Point r = Point::from_hash(buffer); - point_check(test,p,q,r,0,0,p,Point((SecureBuffer)p),"round-trip"); + point_check(test,p,q,r,0,0,p,Point(p.serialize()),"round-trip"); Point pp = p.debugging_torque().debugging_pscale(rng); - if (SecureBuffer(pp) != SecureBuffer(p)) { + if (!memeq(pp.serialize(),p.serialize())) { test.fail(); printf("Fail torque seq test\n"); } @@ -308,7 +308,7 @@ static void test_ec() { "unih = hash+add" ); - point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(SecureBuffer(p))),x*p,"direct mul"); + point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(p.serialize())),x*p,"direct mul"); } }