| @@ -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<Group> &priv) NOEXCEPT; | |||
| @@ -111,7 +111,7 @@ public: | |||
| inline PrivateKey(Rng &r) : | |||
| sym(r), | |||
| scalar(SHAKE<SHAKE_BITS>::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_BYTES> &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<SHAKE_BITS> &ctx_) NOEXCEPT { | |||
| inline SecureBuffer sign_shake(const SHAKE<SHAKE_BITS> &ctx_) throw(std::bad_alloc) { | |||
| SHAKE<SHAKE_BITS> 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<Group>::CHALLENGE_BYTES)); | |||
| SecureBuffer response((nonce - scalar * typename Group::Scalar(challenge)).encode()); | |||
| SecureBuffer response((nonce - scalar * typename Group::Scalar(challenge)).serialize()); | |||
| SecureBuffer ret(PublicKey<Group>::SIG_BYTES); | |||
| Buffer(ret).slice(0,Group::Point::SER_BYTES).assign(g_nonce); | |||
| @@ -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<SER_BYTES> 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<SER_BYTES> buffer, decaf_bool_t allow_identity=DECAF_TRUE) | |||
| inline explicit Point(const FixedBlock<SER_BYTES> &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<SER_BYTES> buffer, decaf_bool_t allow_identity=DECAF_TRUE | |||
| Point &p, const FixedBlock<SER_BYTES> &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<SER_BYTES> 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__ */ | |||
| @@ -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<SER_BYTES> 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<SER_BYTES> buffer, decaf_bool_t allow_identity=DECAF_TRUE) | |||
| inline explicit Point(const FixedBlock<SER_BYTES> &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<SER_BYTES> buffer, decaf_bool_t allow_identity=DECAF_TRUE | |||
| Point &p, const FixedBlock<SER_BYTES> &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<SER_BYTES> 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__ */ | |||
| @@ -87,6 +87,38 @@ public: | |||
| typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer; | |||
| /** Constant-time compare two buffers */ | |||
| template<class T,class U, class V, class W> | |||
| inline bool memeq(const std::vector<T,U> &a, const std::vector<V,W> &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() {}; | |||
| @@ -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) { | |||
| @@ -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); | |||
| } | |||
| @@ -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<Scalar::SER_BYTES>(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<Point::SER_BYTES> 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"); | |||
| } | |||
| } | |||