@@ -17,8 +17,10 @@ | |||
/** @cond internal */ | |||
#if __cplusplus >= 201103L | |||
#define NOEXCEPT noexcept | |||
#define FINAL final | |||
#else | |||
#define NOEXCEPT throw() | |||
#define FINAL | |||
#endif | |||
/** @endcond */ | |||
@@ -29,27 +31,26 @@ namespace decaf { | |||
template <typename Group> class PrivateKey; | |||
/** @brief A public key using a particular EC group */ | |||
template <typename Group> class PublicKey { | |||
template <typename Group> class PublicKey : public Serializable { | |||
private: | |||
/** @cond internal */ | |||
friend class PrivateKey<Group>; | |||
//const typename Group::Point p; | |||
const FixedArrayBuffer<Group::Point::SER_BYTES> ser; | |||
static const size_t CHALLENGE_BYTES = Group::Scalar::SER_BYTES; | |||
//const typename Group::Point p; | |||
FixedArrayBuffer<Group::Point::SER_BYTES> ser; | |||
/** @endcond */ | |||
public: | |||
/** Create without init */ | |||
PublicKey(NOINIT) : ser(NOINIT()) {} | |||
/** SHAKE instance size for sigs etc */ | |||
static const size_t SHAKE_BITS = 256; | |||
/** Size of a signature */ | |||
static const size_t SIG_BYTES = Group::Point::SER_BYTES + Group::Scalar::SER_BYTES; | |||
/** @brief Return a pointer to the serialized version of the point. */ | |||
inline operator FixedBlock<Group::Point::SER_BYTES>() const NOEXCEPT { | |||
return ser; | |||
} | |||
/** @brief Set the public key to a point */ | |||
inline explicit PublicKey(const typename Group::Point &p) NOEXCEPT : ser(p.serialize()) {} | |||
@@ -78,18 +79,29 @@ public: | |||
throw CryptoException(); | |||
} | |||
/** @brief Sign from a message. */ | |||
inline void verify(const Block &message, const FixedBlock<SIG_BYTES> &sig) throw(CryptoException) { | |||
SHAKE<SHAKE_BITS> ctx; | |||
ctx << message; | |||
verify_shake(ctx,sig); | |||
} | |||
/** @brief Serialize into a buffer. */ | |||
inline void serializeInto(unsigned char *x) const NOEXCEPT FINAL { | |||
memcpy(x,ser.data(),Group::Point::SER_BYTES); | |||
} | |||
/** @brief Serialize into a buffer. */ | |||
inline size_t serSize() const NOEXCEPT FINAL { | |||
return Group::Point::SER_BYTES; | |||
} | |||
/** @brief Copy operator */ | |||
inline PublicKey &operator=(const PublicKey &x) NOEXCEPT { ser = x.ser; return *this; } | |||
}; | |||
/** @brief A private key using a particular EC group */ | |||
template <typename Group> class PrivateKey { | |||
template <typename Group> class PrivateKey : public Serializable { | |||
public: | |||
/** Size of associated symmetric key */ | |||
static const size_t SYM_BYTES = 32; | |||
@@ -101,12 +113,15 @@ private: | |||
/** @cond internal */ | |||
static const size_t SCALAR_HASH_BYTES = Group::Scalar::SER_BYTES + 8; | |||
friend class PublicKey<Group>; | |||
const FixedArrayBuffer<SYM_BYTES> sym; | |||
const typename Group::Scalar scalar; | |||
const PublicKey<Group> pub_; | |||
FixedArrayBuffer<SYM_BYTES> sym; | |||
typename Group::Scalar scalar; | |||
PublicKey<Group> pub_; | |||
/** @endcond */ | |||
public: | |||
/** @brief Don't initialize */ | |||
inline PrivateKey(const NOINIT &ni) NOEXCEPT : sym(ni), scalar(ni), pub_(ni) {} | |||
/** @brief Construct at random */ | |||
inline PrivateKey(Rng &r) : | |||
sym(r), | |||
@@ -123,6 +138,16 @@ public: | |||
inline const FixedBlock<SYM_BYTES> &ser_compressed() const NOEXCEPT { | |||
return sym; | |||
} | |||
/** @brief Serialize */ | |||
inline size_t serSize() const NOEXCEPT FINAL { | |||
return SYM_BYTES; | |||
} | |||
/** @brief Serialize */ | |||
inline void serializeInto(unsigned char *target) const NOEXCEPT FINAL { | |||
memcpy(target,sym.data(),serSize()); | |||
} | |||
/** @brief Uncompressed representation */ | |||
inline SecureBuffer ser_uncompressed() const throw(std::bad_alloc) { | |||
@@ -160,6 +185,14 @@ public: | |||
/** @brief Get the corresponding public key */ | |||
inline const PublicKey<Group> &pub() const { return pub_; } | |||
/** @brief Copy operator */ | |||
inline PrivateKey &operator=(const PrivateKey &x) NOEXCEPT { | |||
sym = x.sym; | |||
scalar = x.scalar; | |||
pub_ = x.pub_; | |||
return *this; | |||
} | |||
}; | |||
/** @cond internal */ | |||
@@ -15,6 +15,9 @@ | |||
#include <sys/types.h> | |||
#include <stdio.h> | |||
#include <vector> | |||
#include <stdexcept> | |||
#include <cstddef> | |||
#include <limits> | |||
/** @cond internal */ | |||
#if __cplusplus >= 201103L | |||
@@ -44,7 +47,7 @@ public: | |||
typedef T& reference; | |||
typedef const T& const_reference; | |||
typedef size_t size_type; | |||
typedef ptrdiff_t difference_type; | |||
typedef std::ptrdiff_t difference_type; | |||
template<typename U> struct rebind { typedef SanitizingAllocator<U> other; }; | |||
inline SanitizingAllocator() NOEXCEPT {} | |||
@@ -112,11 +115,10 @@ public: | |||
/** Cast operator */ | |||
#if __cplusplus >= 201103L | |||
explicit | |||
#endif | |||
inline operator SecureBuffer() const throw(std::bad_alloc) { | |||
explicit inline operator SecureBuffer() const throw(std::bad_alloc) { | |||
return serialize(); | |||
} | |||
#endif | |||
}; | |||
/**@cond internal*/ | |||
@@ -242,6 +244,7 @@ private: | |||
inline decaf_bool_t operator<=(const Block &b) const NOEXCEPT DELETE; | |||
inline decaf_bool_t operator> (const Block &b) const NOEXCEPT DELETE; | |||
inline decaf_bool_t operator< (const Block &b) const NOEXCEPT DELETE; | |||
inline void operator= (const Block &b) const NOEXCEPT DELETE; | |||
/** @endcond */ | |||
}; | |||
@@ -297,6 +300,9 @@ public: | |||
/** Securely set the buffer to 0. */ | |||
inline void zeroize() NOEXCEPT { really_bzero(data(),size()); } | |||
private: | |||
inline void operator= (const Block &b) const NOEXCEPT DELETE; | |||
}; | |||
@@ -320,6 +326,9 @@ public: | |||
inline operator FixedBlock<Size>() const NOEXCEPT { | |||
return FixedBlock<Size>(data()); | |||
} | |||
private: | |||
inline void operator= (const Block &b) const NOEXCEPT DELETE; | |||
}; | |||
/** A fixed-size stack-allocated buffer (for NOEXCEPT semantics) */ | |||
@@ -343,6 +352,21 @@ public: | |||
memcpy(storage,b.data(),Size); | |||
} | |||
/** Copy operator */ | |||
inline FixedArrayBuffer& operator=(const FixedBlock<Size> &b) NOEXCEPT { | |||
memcpy(storage,b.data(),Size); return *this; | |||
} | |||
/** Copy operator */ | |||
inline FixedArrayBuffer& operator=(const FixedArrayBuffer<Size> &b) NOEXCEPT { | |||
memcpy(storage,b.data(),Size); return *this; | |||
} | |||
/** Copy operator */ | |||
inline FixedArrayBuffer& operator=(const Block &b) throw(LengthException) { | |||
*this = FixedBlock<Size>(b); | |||
} | |||
/** Copy constructor */ | |||
inline explicit FixedArrayBuffer(const Block &b) throw(LengthException) : FixedBuffer<Size>(storage) { | |||
if (b.size() != Size) throw LengthException(); | |||
@@ -12,6 +12,7 @@ | |||
#include <decaf.hxx> | |||
#include <decaf/shake.hxx> | |||
#include <decaf/crypto.h> | |||
#include <decaf/crypto.hxx> | |||
#include <stdio.h> | |||
#include <sys/time.h> | |||
#include <assert.h> | |||
@@ -153,12 +154,12 @@ static void tdh ( | |||
Strobe client(Strobe::CLIENT), server(Strobe::SERVER); | |||
Scalar xe(clientRng); | |||
SecureBuffer gxe = Precomputed::base() * xe; | |||
SecureBuffer gxe((Precomputed::base() * xe).serialize()); | |||
client.send_plaintext(gxe); | |||
server.recv_plaintext(gxe); | |||
Scalar ye(serverRng); | |||
SecureBuffer gye = Precomputed::base() * ye; | |||
SecureBuffer gye((Precomputed::base() * ye).serialize()); | |||
server.send_plaintext(gye); | |||
client.recv_plaintext(gye); | |||
@@ -196,14 +197,14 @@ static void fhmqv ( | |||
Scalar xe(clientRng); | |||
client.send_plaintext(gx); | |||
server.recv_plaintext(gx); | |||
SecureBuffer gxe = Precomputed::base() * xe; | |||
SecureBuffer gxe((Precomputed::base() * xe).serialize()); | |||
server.send_plaintext(gxe); | |||
client.recv_plaintext(gxe); | |||
Scalar ye(serverRng); | |||
server.send_plaintext(gy); | |||
client.recv_plaintext(gy); | |||
SecureBuffer gye = Precomputed::base() * ye; | |||
SecureBuffer gye((Precomputed::base() * ye).serialize()); | |||
server.send_plaintext(gye); | |||
Scalar schx(server.prng(Scalar::SER_BYTES)); | |||
@@ -247,12 +248,12 @@ static void spake2ee( | |||
Point hs = Point::from_hash(h1); | |||
hs = Point::from_hash(h1); // double-count | |||
SecureBuffer gx(Precomputed::base() * x + hc); | |||
SecureBuffer gx((Precomputed::base() * x + hc).serialize()); | |||
client.send_plaintext(gx); | |||
server.recv_plaintext(gx); | |||
Scalar y(serverRng); | |||
SecureBuffer gy(Precomputed::base() * y + hs); | |||
SecureBuffer gy((Precomputed::base() * y + hs).serialize()); | |||
server.send_plaintext(gy); | |||
client.recv_plaintext(gy); | |||
@@ -260,7 +261,7 @@ static void spake2ee( | |||
server.key((Point(gx) - hc)*y); | |||
if(aug) { | |||
/* This step isn't actually online but whatever, it's fastish */ | |||
SecureBuffer serverAug(Precomputed::base() * gs); | |||
SecureBuffer serverAug((Precomputed::base() * gs).serialize()); | |||
server.key(Point(serverAug)*y); | |||
} | |||
SecureBuffer tag = server.produce_auth(); | |||
@@ -280,7 +281,29 @@ static void spake2ee( | |||
static void macro() { | |||
printf("\nMacro-benchmarks for %s:\n", Group::name()); | |||
printf("Protocol benchmarks:\n"); | |||
printf("Crypto benchmarks:\n"); | |||
SpongeRng rng(Block("macro rng seed")); | |||
PublicKey<Group> p1((NOINIT())), p2((NOINIT())); | |||
PrivateKey<Group> s1((NOINIT())), s2((NOINIT())); | |||
SecureBuffer message = rng.read(12), sig; | |||
for (Benchmark b("Create private key",1); b.iter(); ) { | |||
s1 = PrivateKey<Group>(rng); | |||
SecureBuffer bb = s1.serialize(); | |||
} | |||
for (Benchmark b("Sign",1); b.iter(); ) { | |||
sig = s1.sign(message); | |||
} | |||
p1 = s1.pub(); | |||
for (Benchmark b("Verify",1); b.iter(); ) { | |||
message = rng.read(12); | |||
try { p1.verify(message, sig); } catch (CryptoException) {} | |||
} | |||
printf("\nProtocol benchmarks:\n"); | |||
SpongeRng clientRng(Block("client rng seed")); | |||
SpongeRng serverRng(Block("server rng seed")); | |||
SecureBuffer hashedPassword(Block("hello world")); | |||
@@ -293,9 +316,9 @@ static void macro() { | |||
} | |||
Scalar x(clientRng); | |||
SecureBuffer gx(Precomputed::base() * x); | |||
SecureBuffer gx((Precomputed::base() * x).serialize()); | |||
Scalar y(serverRng); | |||
SecureBuffer gy(Precomputed::base() * y); | |||
SecureBuffer gy((Precomputed::base() * y).serialize()); | |||
for (Benchmark b("FHMQV c+s",0.1); b.iter(); ) { | |||
fhmqv(clientRng, serverRng,x,gx,y,gy); | |||
@@ -320,7 +343,7 @@ static void micro() { | |||
for (Benchmark b("Point add", 100); b.iter(); ) { p += q; } | |||
for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); } | |||
for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; } | |||
for (Benchmark b("Point encode"); b.iter(); ) { ep = SecureBuffer(p); } | |||
for (Benchmark b("Point encode"); b.iter(); ) { ep = p.serialize(); } | |||
for (Benchmark b("Point decode"); b.iter(); ) { p = Point(ep); } | |||
for (Benchmark b("Point create/destroy"); b.iter(); ) { Point r; } | |||
for (Benchmark b("Point hash nonuniform"); b.iter(); ) { Point::from_hash(ep); } | |||
@@ -330,6 +353,10 @@ static void micro() { | |||
for (Benchmark b("Point steg"); b.iter(); ) { p.steg_encode(rng); } | |||
for (Benchmark b("Point double scalarmul"); b.iter(); ) { Point::double_scalarmul(p,s,q,t); } | |||
for (Benchmark b("Point precmp scalarmul"); b.iter(); ) { pBase * s; } | |||
for (Benchmark b("Point double scalarmul_v"); b.iter(); ) { | |||
t = Scalar(rng); | |||
p.non_secret_combo_with_base(s,t); | |||
} | |||
} | |||
}; /* template <typename group> struct Benches */ | |||
@@ -381,7 +408,7 @@ int main(int argc, char **argv) { | |||
for (Benchmark b("STROBEk256 1kiB", 10); b.iter(); ) { | |||
strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1); | |||
} | |||
/* TODO: scalarmul for verif, etc */ | |||
Benches<IsoEd25519>::micro(); | |||
Benches<Ed448Goldilocks>::micro(); | |||
} | |||