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