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