@@ -57,7 +57,7 @@ public: | |||
inline explicit PublicKey(const PrivateKey<Group> &priv) NOEXCEPT; | |||
/** @brief Read a private key from a string*/ | |||
inline explicit PublicKey(const FixedBlock<Group::Point::SER_BYTES> b) NOEXCEPT : ser(b) {} | |||
inline explicit PublicKey(const FixedBlock<Group::Point::SER_BYTES> &b) NOEXCEPT : ser(b) {} | |||
/** @brief Return the corresponding EC point */ | |||
inline typename Group::Point point() const throw(CryptoException) { | |||
@@ -68,11 +68,10 @@ public: | |||
inline void verify_shake(const SHAKE<SHAKE_BITS> &ctx_, const FixedBlock<SIG_BYTES> &sig) throw(CryptoException) { | |||
SHAKE<SHAKE_BITS> ctx(ctx_); | |||
ctx << ser << sig.slice(0,Group::Point::SER_BYTES); | |||
FixedBuffer<CHALLENGE_BYTES> challenge(ctx.output(CHALLENGE_BYTES)); | |||
challenge.debug_print("ch ver "); | |||
SecureBuffer challenge(ctx.output(CHALLENGE_BYTES)); | |||
const typename Group::Point combo = point().non_secret_combo_with_base( | |||
challenge, | |||
typename Group::Scalar(challenge), | |||
sig.slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES) | |||
); | |||
if (combo != typename Group::Point(sig.slice(0,Group::Point::SER_BYTES))) | |||
@@ -128,9 +127,9 @@ public: | |||
/** @brief Uncompressed representation */ | |||
inline SecureBuffer ser_uncompressed() const throw(std::bad_alloc) { | |||
SecureBuffer b(SYM_BYTES + Group::Scalar::SER_BYTES + Group::Point::SER_BYTES); | |||
b.slice(0,SYM_BYTES).assign(sym); | |||
b.slice(SYM_BYTES,Group::Scalar::SER_BYTES).assign(scalar); | |||
b.slice(SYM_BYTES+Group::Scalar::SER_BYTES,Group::Point::SER_BYTES).assign(pub_.ser); | |||
Buffer(b).slice(0,SYM_BYTES).assign(sym); | |||
Buffer(b).slice(SYM_BYTES,Group::Scalar::SER_BYTES).assign(scalar); | |||
Buffer(b).slice(SYM_BYTES+Group::Scalar::SER_BYTES,Group::Point::SER_BYTES).assign(pub_.ser); | |||
return b; | |||
} | |||
@@ -143,13 +142,12 @@ public: | |||
ctx = ctx_; | |||
ctx << pub_.ser << g_nonce; | |||
FixedBuffer<PublicKey<Group>::CHALLENGE_BYTES> challenge(ctx.output(PublicKey<Group>::CHALLENGE_BYTES)); | |||
challenge.debug_print("ch sign"); | |||
SecureBuffer response(nonce - scalar * challenge); | |||
SecureBuffer challenge(ctx.output(PublicKey<Group>::CHALLENGE_BYTES)); | |||
SecureBuffer response((nonce - scalar * typename Group::Scalar(challenge)).encode()); | |||
SecureBuffer ret(PublicKey<Group>::SIG_BYTES); | |||
ret.slice(0,Group::Point::SER_BYTES).assign(g_nonce); | |||
ret.slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES).assign(response); | |||
Buffer(ret).slice(0,Group::Point::SER_BYTES).assign(g_nonce); | |||
Buffer(ret).slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES).assign(response); | |||
return ret; | |||
} | |||
@@ -130,7 +130,7 @@ public: | |||
static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
Scalar &sc, const FixedBlock<SER_BYTES> buffer | |||
) NOEXCEPT { | |||
return decaf_255_scalar_decode(sc.s,buffer); | |||
return decaf_255_scalar_decode(sc.s,buffer.data()); | |||
} | |||
/** @brief Encode to fixed-length string */ | |||
@@ -140,7 +140,12 @@ public: | |||
/** @brief Encode to fixed-length buffer */ | |||
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{ | |||
decaf_255_scalar_encode(buffer, s); | |||
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. */ | |||
@@ -293,15 +298,15 @@ public: | |||
if (s.size() < HASH_BYTES) { | |||
SecureBuffer b(HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
decaf_255_point_from_hash_nonuniform(p,b); | |||
decaf_255_point_from_hash_nonuniform(p,b.data()); | |||
} else if (s.size() == HASH_BYTES) { | |||
decaf_255_point_from_hash_nonuniform(p,s); | |||
decaf_255_point_from_hash_nonuniform(p,s.data()); | |||
} else if (s.size() < 2*HASH_BYTES) { | |||
SecureBuffer b(2*HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
decaf_255_point_from_hash_uniform(p,b); | |||
decaf_255_point_from_hash_uniform(p,b.data()); | |||
} else { | |||
decaf_255_point_from_hash_uniform(p,s); | |||
decaf_255_point_from_hash_uniform(p,s.data()); | |||
} | |||
} | |||
@@ -316,7 +321,12 @@ public: | |||
* @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, p); | |||
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 Point add. */ | |||
@@ -394,7 +404,7 @@ public: | |||
/** @brief Return a point equal to *this, whose internal data has a modified representation. */ | |||
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT { | |||
Point q; decaf_255_point_debugging_pscale(q.p,p,factor); return q; | |||
Point q; decaf_255_point_debugging_pscale(q.p,p,factor.data()); return q; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data has a randomized representation. */ | |||
@@ -407,11 +417,11 @@ public: | |||
* or leave buf unmodified and return false. | |||
*/ | |||
inline bool invert_elligator ( | |||
Buffer &buf, uint16_t hint | |||
Buffer buf, uint16_t hint | |||
) const NOEXCEPT { | |||
unsigned char buf2[2*HASH_BYTES]; | |||
memset(buf2,0,sizeof(buf2)); | |||
memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
memcpy(buf2,buf.data(),(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
decaf_bool_t ret; | |||
if (buf.size() > HASH_BYTES) { | |||
ret = decaf_255_invert_elligator_uniform(buf2, p, hint); | |||
@@ -423,7 +433,7 @@ public: | |||
} | |||
if (ret) { | |||
/* TODO: make this constant time?? */ | |||
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||
memcpy(buf.data(),buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||
} | |||
decaf_bzero(buf2,sizeof(buf2)); | |||
return !!ret; | |||
@@ -435,7 +445,7 @@ public: | |||
SecureBuffer out(STEG_BYTES); | |||
bool done; | |||
do { | |||
rng.read(out.slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1)); | |||
rng.read(Buffer(out).slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1)); | |||
done = invert_elligator(out, out[HASH_BYTES-1]); | |||
} while (!done); | |||
return out; | |||
@@ -553,7 +563,7 @@ inline SecureBuffer IsoEd25519::Scalar::direct_scalarmul ( | |||
decaf_bool_t short_circuit | |||
) const throw(CryptoException) { | |||
SecureBuffer out(IsoEd25519::Point::SER_BYTES); | |||
if (!decaf_255_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit)) | |||
if (!decaf_255_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit)) | |||
throw CryptoException(); | |||
return out; | |||
} | |||
@@ -130,17 +130,17 @@ public: | |||
static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( | |||
Scalar &sc, const FixedBlock<SER_BYTES> buffer | |||
) NOEXCEPT { | |||
return decaf_448_scalar_decode(sc.s,buffer); | |||
return decaf_448_scalar_decode(sc.s,buffer.data()); | |||
} | |||
/** @brief Encode to fixed-length string */ | |||
inline operator SecureBuffer() const NOEXCEPT { | |||
SecureBuffer buf(SER_BYTES); decaf_448_scalar_encode(buf,s); return buf; | |||
/** @brief Encode to fixed-length buffer */ | |||
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{ | |||
decaf_448_scalar_encode(buffer.data(), s); | |||
} | |||
/** @brief Encode to fixed-length buffer */ | |||
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{ | |||
decaf_448_scalar_encode(buffer, s); | |||
inline SecureBuffer encode() const throw(std::bad_alloc) { | |||
SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer; | |||
} | |||
/** Add. */ | |||
@@ -192,7 +192,7 @@ public: | |||
decaf_bool_t short_circuit=DECAF_TRUE | |||
) const throw(CryptoException) { | |||
SecureBuffer out(/*FIXME Point::*/SER_BYTES); | |||
if (!decaf_448_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit)) | |||
if (!decaf_448_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit)) | |||
throw CryptoException(); | |||
return out; | |||
} | |||
@@ -296,15 +296,15 @@ public: | |||
if (s.size() < HASH_BYTES) { | |||
SecureBuffer b(HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
decaf_448_point_from_hash_nonuniform(p,b); | |||
decaf_448_point_from_hash_nonuniform(p,b.data()); | |||
} else if (s.size() == HASH_BYTES) { | |||
decaf_448_point_from_hash_nonuniform(p,s); | |||
decaf_448_point_from_hash_nonuniform(p,s.data()); | |||
} else if (s.size() < 2*HASH_BYTES) { | |||
SecureBuffer b(2*HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
decaf_448_point_from_hash_uniform(p,b); | |||
decaf_448_point_from_hash_uniform(p,b.data()); | |||
} else { | |||
decaf_448_point_from_hash_uniform(p,s); | |||
decaf_448_point_from_hash_uniform(p,s.data()); | |||
} | |||
} | |||
@@ -313,7 +313,7 @@ public: | |||
*/ | |||
inline operator SecureBuffer() const NOEXCEPT { | |||
SecureBuffer buffer(SER_BYTES); | |||
decaf_448_point_encode(buffer, p); | |||
decaf_448_point_encode(buffer.data(), p); | |||
return buffer; | |||
} | |||
@@ -321,7 +321,12 @@ public: | |||
* @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, p); | |||
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 Point add. */ | |||
@@ -402,7 +407,7 @@ public: | |||
/** @brief Return a point equal to *this, whose internal data has a modified representation. */ | |||
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT { | |||
Point q; | |||
decaf_448_point_debugging_pscale(q.p,p,factor); | |||
decaf_448_point_debugging_pscale(q.p,p,factor.data()); | |||
return q; | |||
} | |||
@@ -417,11 +422,11 @@ public: | |||
* or leave buf unmodified and return false. | |||
*/ | |||
inline bool invert_elligator ( | |||
Buffer &buf, uint16_t hint | |||
Buffer buf, uint16_t hint | |||
) const NOEXCEPT { | |||
unsigned char buf2[2*HASH_BYTES]; | |||
memset(buf2,0,sizeof(buf2)); | |||
memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
memcpy(buf2,buf.data(),(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
decaf_bool_t ret; | |||
if (buf.size() > HASH_BYTES) { | |||
ret = decaf_448_invert_elligator_uniform(buf2, p, hint); | |||
@@ -433,7 +438,7 @@ public: | |||
} | |||
if (ret) { | |||
/* TODO: make this constant time?? */ | |||
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||
memcpy(buf.data(),buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||
} | |||
decaf_bzero(buf2,sizeof(buf2)); | |||
return !!ret; | |||
@@ -444,7 +449,7 @@ public: | |||
SecureBuffer out(STEG_BYTES); | |||
bool done; | |||
do { | |||
rng.read(out.slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1)); | |||
rng.read(Buffer(out).slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1)); | |||
done = invert_elligator(out, out[HASH_BYTES-1]); | |||
} while (!done); | |||
return out; | |||
@@ -14,6 +14,7 @@ | |||
#include <string> | |||
#include <sys/types.h> | |||
#include <stdio.h> | |||
#include <vector> | |||
/** @cond internal */ | |||
#if __cplusplus >= 201103L | |||
@@ -27,11 +28,67 @@ | |||
namespace decaf { | |||
/** | |||
* Securely zeroize contents of memory. | |||
*/ | |||
static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); } | |||
/** @brief An allocator which zeros its memory on free */ | |||
template<typename T, size_t alignment = 0> class SanitizingAllocator { | |||
/** @cond internal */ | |||
/* Based on http://www.codeproject.com/Articles/4795/C-Standard-Allocator-An-Introduction-and-Implement */ | |||
public: | |||
typedef T value_type; | |||
typedef T* pointer; | |||
typedef const T* const_pointer; | |||
typedef T& reference; | |||
typedef const T& const_reference; | |||
typedef size_t size_type; | |||
typedef ptrdiff_t difference_type; | |||
template<typename U> struct rebind { typedef SanitizingAllocator<U> other; }; | |||
inline SanitizingAllocator() NOEXCEPT {} | |||
inline ~SanitizingAllocator() NOEXCEPT {} | |||
inline SanitizingAllocator(const SanitizingAllocator &) NOEXCEPT {} | |||
template<typename U, size_t a> inline SanitizingAllocator(const SanitizingAllocator<U, a> &) NOEXCEPT {} | |||
inline T* address(T& r) const NOEXCEPT { return &r; } | |||
inline const T* address(const T& r) const NOEXCEPT { return &r; } | |||
inline T* allocate ( | |||
size_type cnt, | |||
typename std::allocator<void>::const_pointer = 0 | |||
) throw(std::bad_alloc) { | |||
void *v; | |||
int ret = 0; | |||
if (alignment) ret = posix_memalign(&v, alignment, cnt * sizeof(T)); | |||
else v = malloc(cnt * sizeof(T)); | |||
if (ret || v==NULL) throw(std::bad_alloc()); | |||
return reinterpret_cast<T*>(v); | |||
} | |||
inline void deallocate(T* p, size_t size) NOEXCEPT { | |||
if (p==NULL) return; | |||
really_bzero(reinterpret_cast<void*>(p), size); | |||
free(reinterpret_cast<void*>(p)); | |||
} | |||
inline size_t max_size() const NOEXCEPT { return std::numeric_limits<size_t>::max() / sizeof(T); } | |||
inline void construct(T* p, const T& t) { new(p) T(t); } | |||
inline void destroy(T* p) { p->~T(); } | |||
inline bool operator==(SanitizingAllocator const&) const NOEXCEPT { return true; } | |||
inline bool operator!=(SanitizingAllocator const&) const NOEXCEPT { return false; } | |||
/** @endcond */ | |||
}; | |||
typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer; | |||
/**@cond internal*/ | |||
/** Forward-declare sponge RNG object */ | |||
class Buffer; | |||
class TmpBuffer; | |||
class SecureBuffer; | |||
/**@endcond*/ | |||
/** @brief An exception for when crypto (ie point decode) has failed. */ | |||
@@ -67,19 +124,12 @@ protected: | |||
public: | |||
/** @brief Read into a Buffer */ | |||
virtual void read(Buffer &buffer) NOEXCEPT = 0; | |||
/** @brief Read into a value-passed (eg temporary) TmpBuffer. */ | |||
inline void read(TmpBuffer buffer) NOEXCEPT; | |||
virtual void read(Buffer buffer) NOEXCEPT = 0; | |||
/** @brief Read into a SecureBuffer. */ | |||
inline SecureBuffer read(size_t length) throw(std::bad_alloc); | |||
}; | |||
/** | |||
* Securely zeroize contents of memory. | |||
*/ | |||
static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); } | |||
/** A reference to a block of data, which (when accessed through this base class) is const. */ | |||
class Block { | |||
@@ -105,16 +155,23 @@ public: | |||
((unsigned char *)(s.data())) | |||
#endif | |||
), size_(s.size()) {} | |||
/** Block from std::vector */ | |||
template<class alloc> inline Block(const std::vector<unsigned char,alloc> &s) | |||
: data_(((unsigned char *)&(s)[0])), size_(s.size()) {} | |||
/** Get const data */ | |||
inline const unsigned char *data() const NOEXCEPT { return data_; } | |||
/** Subscript */ | |||
inline const unsigned char &operator[](size_t off) const throw(std::out_of_range) { | |||
if (off >= size()) throw(std::out_of_range("decaf::Block")); | |||
return data_[off]; | |||
} | |||
/** Get the size */ | |||
inline size_t size() const NOEXCEPT { return size_; } | |||
/** Autocast to const unsigned char * */ | |||
inline operator const unsigned char*() const NOEXCEPT { return data_; } | |||
/** Convert to C++ string */ | |||
inline std::string get_string() const { | |||
return std::string((const char *)data_,size_); | |||
@@ -122,48 +179,48 @@ public: | |||
/** Slice the buffer*/ | |||
inline Block slice(size_t off, size_t length) const throw(LengthException) { | |||
if (off > size() || length > size() - off) | |||
throw LengthException(); | |||
if (off > size() || length > size() - off) throw LengthException(); | |||
return Block(data()+off, length); | |||
} | |||
/** @cond internal */ | |||
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; | |||
/** @endcond */ | |||
/* Content-wise comparison; constant-time if they are the same length. */ | |||
inline decaf_bool_t operator!=(const Block &b) const NOEXCEPT { | |||
if (b.size() != size()) return true; | |||
return ~decaf_memeq(b,*this,size()); | |||
} | |||
/* Content-wise comparison; constant-time if they are the same length. */ | |||
inline decaf_bool_t operator==(const Block &b) const NOEXCEPT { | |||
return ~(*this != b); | |||
inline decaf_bool_t contents_equal(const Block &b) const NOEXCEPT { | |||
if (b.size() != size()) return false; | |||
return decaf_memeq(b.data(),data(),size()); | |||
} | |||
/** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */ | |||
inline virtual ~Block() {}; | |||
/** Debugging print in hex */ | |||
inline void debug_print(const char *name = NULL) { | |||
inline void debug_print_hex(const char *name = NULL) { | |||
if (name) printf("%s = ", name); | |||
for (size_t s = 0; s < size(); s++) printf("%02x", data_[s]); | |||
printf("\n"); | |||
} | |||
private: | |||
/** @cond internal */ | |||
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; | |||
/** @endcond */ | |||
}; | |||
/** A fixed-size block */ | |||
template<size_t Size> class FixedBlock : public Block { | |||
public: | |||
/** Check a block's length. */ | |||
inline FixedBlock(const Block &b) throw(LengthException) : Block(b,Size) { | |||
inline FixedBlock(const Block &b) throw(LengthException) : Block(b.data(),Size) { | |||
if (Size != b.size()) throw LengthException(); | |||
} | |||
/** Block from std::vector */ | |||
template<class alloc> inline FixedBlock(const std::vector<unsigned char,alloc> &s) : Block(s) { | |||
if (Size != s.size()) throw LengthException(); | |||
} | |||
/** Explicitly pass a C buffer. */ | |||
inline explicit FixedBlock(const uint8_t data[Size]) NOEXCEPT : Block(data,Size) {} | |||
}; | |||
@@ -176,26 +233,29 @@ public: | |||
/** Unowned init */ | |||
inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {} | |||
/** Get unconst data */ | |||
inline unsigned char *data() NOEXCEPT { return data_; } | |||
/** Block from std::vector */ | |||
template<class alloc> inline Buffer(std::vector<unsigned char,alloc> &s) : Block(s) {} | |||
/** Get const data */ | |||
inline const unsigned char *data() const NOEXCEPT { return data_; } | |||
/** Autocast to const unsigned char * */ | |||
inline operator const unsigned char*() const NOEXCEPT { return data_; } | |||
/** Autocast to unsigned char */ | |||
inline operator unsigned char*() NOEXCEPT { return data_; } | |||
/** Cast to unsigned char */ | |||
inline unsigned char* data() NOEXCEPT { return data_; } | |||
/** Slice the buffer*/ | |||
inline TmpBuffer slice(size_t off, size_t length) throw(LengthException); | |||
inline Buffer slice(size_t off, size_t length) throw(LengthException); | |||
/** Subscript */ | |||
inline unsigned char &operator[](size_t off) throw(std::out_of_range) { | |||
if (off >= size()) throw(std::out_of_range("decaf::Buffer")); | |||
return data_[off]; | |||
} | |||
/** Copy from another block */ | |||
inline void assign(const Block b) throw(LengthException) { | |||
if (b.size() != size()) throw LengthException(); | |||
memmove(*this,b,size()); | |||
memmove(data(),b.data(),size()); | |||
} | |||
/** Securely set the buffer to 0. */ | |||
@@ -207,7 +267,12 @@ public: | |||
template<size_t Size> class FixedBuffer : public Buffer { | |||
public: | |||
/** Check a block's length. */ | |||
inline FixedBuffer(Buffer &b) throw(LengthException) : Buffer(b,Size) { | |||
inline FixedBuffer(Buffer b) throw(LengthException) : Buffer(b) { | |||
if (Size != b.size()) throw LengthException(); | |||
} | |||
/** Check a block's length. */ | |||
inline FixedBuffer(SecureBuffer &b) throw(LengthException) : Buffer(b) { | |||
if (Size != b.size()) throw LengthException(); | |||
} | |||
@@ -220,13 +285,6 @@ public: | |||
} | |||
}; | |||
/** A temporary reference to a writeable buffer, for converting C to C++. */ | |||
class TmpBuffer : public Buffer { | |||
public: | |||
/** Unowned init */ | |||
inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {} | |||
}; | |||
/** A fixed-size stack-allocated buffer (for NOEXCEPT semantics) */ | |||
template<size_t Size> class FixedArrayBuffer : public FixedBuffer<Size> { | |||
private: | |||
@@ -245,18 +303,18 @@ public: | |||
/** Copy constructor */ | |||
inline explicit FixedArrayBuffer(const FixedBlock<Size> &b) NOEXCEPT : FixedBuffer<Size>(storage) { | |||
memcpy(storage,b,Size); | |||
memcpy(storage,b.data(),Size); | |||
} | |||
/** Copy constructor */ | |||
inline explicit FixedArrayBuffer(const Block &b) throw(LengthException) : FixedBuffer<Size>(storage) { | |||
if (b.size() != Size) throw LengthException(); | |||
memcpy(storage,b,Size); | |||
memcpy(storage,b.data(),Size); | |||
} | |||
/** Copy constructor */ | |||
inline explicit FixedArrayBuffer(const FixedArrayBuffer<Size> &b) NOEXCEPT : FixedBuffer<Size>(storage) { | |||
memcpy(storage,b,Size); | |||
memcpy(storage,b.data(),Size); | |||
} | |||
/** Destroy the buffer */ | |||
@@ -264,90 +322,9 @@ public: | |||
}; | |||
/** @cond internal */ | |||
inline void Rng::read(TmpBuffer buffer) NOEXCEPT { read((Buffer &)buffer); } | |||
/** @endcond */ | |||
/** A self-erasing block of data */ | |||
class SecureBuffer : public Buffer { | |||
public: | |||
/** Null secure block */ | |||
inline SecureBuffer() NOEXCEPT : Buffer() {} | |||
/** Construct empty from size */ | |||
inline SecureBuffer(size_t size) throw(std::bad_alloc) { | |||
data_ = new unsigned char[size_ = size]; | |||
memset(data_,0,size); | |||
} | |||
/** Construct from data */ | |||
inline SecureBuffer(const unsigned char *data, size_t size) throw(std::bad_alloc) { | |||
data_ = new unsigned char[size_ = size]; | |||
memcpy(data_, data, size); | |||
} | |||
/** Construct from random */ | |||
inline SecureBuffer(Rng &r, size_t size) NOEXCEPT { | |||
data_ = new unsigned char[size_ = size]; | |||
r.read(*this); | |||
} | |||
/** Copy constructor */ | |||
inline SecureBuffer(const Block ©) throw(std::bad_alloc) : Buffer() { *this = copy; } | |||
/** Copy-assign constructor */ | |||
inline SecureBuffer& operator=(const Block ©) throw(std::bad_alloc) { | |||
if (© == this) return *this; | |||
clear(); | |||
data_ = new unsigned char[size_ = copy.size()]; | |||
memcpy(data_,copy.data(),size_); | |||
return *this; | |||
} | |||
/** Copy-assign constructor */ | |||
inline SecureBuffer& operator=(const SecureBuffer ©) throw(std::bad_alloc) { | |||
if (© == this) return *this; | |||
clear(); | |||
data_ = new unsigned char[size_ = copy.size()]; | |||
memcpy(data_,copy.data(),size_); | |||
return *this; | |||
} | |||
/** Destructor zeroizes data */ | |||
~SecureBuffer() NOEXCEPT { clear(); } | |||
/** Clear data */ | |||
inline void clear() NOEXCEPT { | |||
if (data_ == NULL) return; | |||
zeroize(); | |||
delete[] data_; | |||
data_ = NULL; | |||
size_ = 0; | |||
} | |||
#if __cplusplus >= 201103L | |||
/** Move constructor */ | |||
inline SecureBuffer(SecureBuffer &&move) { *this = move; } | |||
/** Move non-constructor */ | |||
inline SecureBuffer(Block &&move) { *this = (Block &)move; } | |||
/** Move-assign constructor. TODO: check that this actually gets used.*/ | |||
inline SecureBuffer& operator=(SecureBuffer &&move) { | |||
clear(); | |||
data_ = move.data_; move.data_ = NULL; | |||
size_ = move.size_; move.size_ = 0; | |||
return *this; | |||
} | |||
/** C++11-only explicit cast */ | |||
inline explicit operator std::string() const { return get_string(); } | |||
#endif | |||
}; | |||
/** @cond internal */ | |||
TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) { | |||
Buffer Buffer::slice(size_t off, size_t length) throw(LengthException) { | |||
if (off > size() || length > size() - off) throw LengthException(); | |||
return TmpBuffer(data()+off, length); | |||
return Buffer(data()+off, length); | |||
} | |||
inline SecureBuffer Rng::read(size_t length) throw(std::bad_alloc) { | |||
@@ -71,7 +71,7 @@ public: | |||
* @brief Output bytes from the sponge. | |||
* @todo make this throw exceptions. | |||
*/ | |||
inline void output(TmpBuffer b) { sha3_output(sp,b.data(),b.size()); } | |||
inline void output(Buffer b) { sha3_output(sp,b.data(),b.size()); } | |||
/** | |||
* @brief Output bytes from the sponge. | |||
@@ -82,7 +82,7 @@ public: | |||
/** @brief Output bytes from the sponge. */ | |||
inline SecureBuffer output(size_t len) { | |||
SecureBuffer buffer(len); | |||
sha3_output(sp,buffer,len); | |||
sha3_output(sp,buffer.data(),len); | |||
return buffer; | |||
} | |||
@@ -182,7 +182,7 @@ public: | |||
using Rng::read; | |||
/** Read data to a buffer. */ | |||
virtual inline void read(Buffer &buffer) NOEXCEPT | |||
virtual inline void read(Buffer buffer) NOEXCEPT | |||
#if __cplusplus >= 201103L | |||
final | |||
#endif | |||
@@ -211,43 +211,37 @@ public: | |||
inline void key ( | |||
const Block &data, bool more = false | |||
) throw(ProtocolException) { | |||
if (!strobe_key(sp, data, data.size(), more)) throw ProtocolException(); | |||
if (!strobe_key(sp, data.data(), data.size(), more)) throw ProtocolException(); | |||
} | |||
inline void nonce(const Block &data, bool more = false | |||
) throw(ProtocolException) { | |||
if (!strobe_nonce(sp, data, data.size(), more)) 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) { | |||
if (!strobe_plaintext(sp, data, data.size(), true, more)) | |||
if (!strobe_plaintext(sp, data.data(), data.size(), true, more)) | |||
throw(ProtocolException()); | |||
} | |||
inline void recv_plaintext(const Block &data, bool more = false | |||
) throw(ProtocolException) { | |||
if (!strobe_plaintext(sp, data, data.size(), false, more)) | |||
if (!strobe_plaintext(sp, data.data(), data.size(), false, more)) | |||
throw(ProtocolException()); | |||
} | |||
inline void ad(const Block &data, bool more = false | |||
) throw(ProtocolException) { | |||
if (!strobe_ad(sp, data, data.size(), more)) | |||
if (!strobe_ad(sp, data.data(), data.size(), more)) | |||
throw(ProtocolException()); | |||
} | |||
inline void encrypt_no_auth( | |||
Buffer &out, const Block &data, bool more = false | |||
Buffer out, const Block &data, bool more = false | |||
) throw(LengthException,ProtocolException) { | |||
if (out.size() != data.size()) throw LengthException(); | |||
if (!strobe_encrypt(sp, out, data, data.size(), more)) throw(ProtocolException()); | |||
} | |||
inline void encrypt_no_auth( | |||
TmpBuffer out, const Block &data, bool more = false | |||
) throw(LengthException,ProtocolException) { | |||
encrypt_no_auth((Buffer &)out, data, more); | |||
if (!strobe_encrypt(sp, out.data(), data.data(), data.size(), more)) throw(ProtocolException()); | |||
} | |||
inline SecureBuffer encrypt_no_auth(const Block &data, bool more = false | |||
@@ -256,16 +250,10 @@ public: | |||
} | |||
inline void decrypt_no_auth( | |||
Buffer &out, const Block &data, bool more = false | |||
Buffer out, const Block &data, bool more = false | |||
) throw(LengthException,ProtocolException) { | |||
if (out.size() != data.size()) throw LengthException(); | |||
if (!strobe_decrypt(sp, out, data, data.size(), more)) throw ProtocolException(); | |||
} | |||
inline void decrypt_no_auth( | |||
TmpBuffer out, const Block &data, bool more = false | |||
) throw(LengthException,ProtocolException) { | |||
decrypt_no_auth((Buffer &)out, data, more); | |||
if (!strobe_decrypt(sp, out.data(), data.data(), data.size(), more)) throw ProtocolException(); | |||
} | |||
inline SecureBuffer decrypt_no_auth(const Block &data, bool more = false | |||
@@ -273,13 +261,9 @@ public: | |||
SecureBuffer out(data.size()); decrypt_no_auth(out, data, more); return out; | |||
} | |||
inline void produce_auth(Buffer &out) throw(LengthException,ProtocolException) { | |||
inline void produce_auth(Buffer out) throw(LengthException,ProtocolException) { | |||
if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); | |||
if (!strobe_produce_auth(sp, out, out.size())) throw ProtocolException(); | |||
} | |||
inline void produce_auth(TmpBuffer out) throw(LengthException,ProtocolException) { | |||
produce_auth((Buffer &)out); | |||
if (!strobe_produce_auth(sp, out.data(), out.size())) throw ProtocolException(); | |||
} | |||
inline SecureBuffer produce_auth( | |||
@@ -289,19 +273,13 @@ public: | |||
} | |||
inline void encrypt( | |||
Buffer &out, const Block &data, uint8_t auth = 8 | |||
Buffer out, const Block &data, uint8_t auth = 8 | |||
) throw(LengthException,ProtocolException) { | |||
if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException(); | |||
encrypt_no_auth(out.slice(0,data.size()), data); | |||
produce_auth(out.slice(data.size(),auth)); | |||
} | |||
inline void encrypt ( | |||
TmpBuffer out, const Block &data, uint8_t auth = 8 | |||
) throw(LengthException,ProtocolException) { | |||
encrypt((Buffer &)out, data, auth); | |||
} | |||
inline SecureBuffer encrypt ( | |||
const Block &data, uint8_t auth = 8 | |||
) throw(LengthException,ProtocolException,std::bad_alloc ){ | |||
@@ -309,19 +287,13 @@ public: | |||
} | |||
inline void decrypt ( | |||
Buffer &out, const Block &data, uint8_t bytes = 8 | |||
Buffer out, const Block &data, uint8_t bytes = 8 | |||
) throw(LengthException, CryptoException, ProtocolException) { | |||
if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException(); | |||
decrypt_no_auth(out, data.slice(0,out.size())); | |||
verify_auth(data.slice(out.size(),bytes)); | |||
} | |||
inline void decrypt ( | |||
TmpBuffer out, const Block &data, uint8_t bytes = 8 | |||
) throw(LengthException,CryptoException,ProtocolException) { | |||
decrypt((Buffer &)out, data, bytes); | |||
} | |||
inline SecureBuffer decrypt ( | |||
const Block &data, uint8_t bytes = 8 | |||
) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { | |||
@@ -331,15 +303,11 @@ public: | |||
inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) { | |||
if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); | |||
if (!strobe_verify_auth(sp, auth, auth.size())) throw CryptoException(); | |||
} | |||
inline void prng(Buffer &out, bool more = false) NOEXCEPT { | |||
(void)strobe_prng(sp, out, out.size(), more); | |||
if (!strobe_verify_auth(sp, auth.data(), auth.size())) throw CryptoException(); | |||
} | |||
inline void prng(TmpBuffer out, bool more = false) NOEXCEPT { | |||
prng((Buffer &)out, more); | |||
inline void prng(Buffer out, bool more = false) NOEXCEPT { | |||
(void)strobe_prng(sp, out.data(), out.size(), more); | |||
} | |||
inline SecureBuffer prng(size_t bytes, bool more = false) { | |||
@@ -361,25 +361,25 @@ int main(int argc, char **argv) { | |||
SHA3<512> sha5; | |||
Strobe strobe(Strobe::CLIENT); | |||
unsigned char b1024[1024] = {1}; | |||
for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += TmpBuffer(b1024,1024); } | |||
for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += TmpBuffer(b1024,1024); } | |||
for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += TmpBuffer(b1024,1024); } | |||
strobe.key(TmpBuffer(b1024,1024)); | |||
for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += Buffer(b1024,1024); } | |||
for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += Buffer(b1024,1024); } | |||
for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += Buffer(b1024,1024); } | |||
strobe.key(Buffer(b1024,1024)); | |||
strobe.respec(STROBE_128); | |||
for (Benchmark b("STROBE128 1kiB", 10); b.iter(); ) { | |||
strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1); | |||
strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1); | |||
} | |||
strobe.respec(STROBE_256); | |||
for (Benchmark b("STROBE256 1kiB", 10); b.iter(); ) { | |||
strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1); | |||
strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1); | |||
} | |||
strobe.respec(STROBE_KEYED_128); | |||
for (Benchmark b("STROBEk128 1kiB", 10); b.iter(); ) { | |||
strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1); | |||
strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1); | |||
} | |||
strobe.respec(STROBE_KEYED_256); | |||
for (Benchmark b("STROBEk256 1kiB", 10); b.iter(); ) { | |||
strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(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(); | |||
@@ -303,8 +303,8 @@ static void test_ec() { | |||
point_check(test,base,q,r,x,y,x*base+y*q,q.non_secret_combo_with_base(y,x),"ds vt mul"); | |||
point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul"); | |||
point_check(test,p,q,r,0,0,r, | |||
Point::from_hash(buffer.slice(0,Point::HASH_BYTES)) | |||
+ Point::from_hash(buffer.slice(Point::HASH_BYTES,Point::HASH_BYTES)), | |||
Point::from_hash(Buffer(buffer).slice(0,Point::HASH_BYTES)) | |||
+ Point::from_hash(Buffer(buffer).slice(Point::HASH_BYTES,Point::HASH_BYTES)), | |||
"unih = hash+add" | |||
); | |||
@@ -320,8 +320,8 @@ static void test_crypto() { | |||
PrivateKey<Group> priv1(rng), priv2(rng); | |||
PublicKey<Group> pub1(priv1), pub2(priv2); | |||
SecureBuffer message(rng, i); | |||
FixedArrayBuffer<PublicKey<Group>::SIG_BYTES> sig(priv1.sign(message)); | |||
SecureBuffer message = rng.read(i); | |||
SecureBuffer sig(priv1.sign(message)); | |||
pub1.verify(message, sig); | |||
} | |||
} | |||
@@ -341,8 +341,8 @@ static void test_decaf() { | |||
const char *message = "Hello, world!"; | |||
for (int i=0; i<NTESTS && test.passing_now; i++) { | |||
rng.read(TmpBuffer(proto1,sizeof(proto1))); | |||
rng.read(TmpBuffer(proto2,sizeof(proto2))); | |||
rng.read(Buffer(proto1,sizeof(proto1))); | |||
rng.read(Buffer(proto2,sizeof(proto2))); | |||
decaf_255_derive_private_key(s1,proto1); | |||
decaf_255_private_to_public(p1,s1); | |||
decaf_255_derive_private_key(s2,proto2); | |||