@@ -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"); | |||
} | |||
} | |||