Loading...
Searching...
No Matches
secure_buffer.hxx
Go to the documentation of this file.
#ifndef __DECAF_SECURE_BUFFER_HXX__
#define __DECAF_SECURE_BUFFER_HXX__ 1
#include <string>
#include <sys/types.h>
#include <stdio.h>
#include <vector>
#include <stdexcept>
#include <cstddef>
#include <limits>
#if defined(_MSC_VER) // MSVC does not have built in posix_memalign
#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno)
#endif
#if __cplusplus >= 201103L
#define DECAF_NOEXCEPT noexcept
#define DECAF_DELETE = delete
#else
#define DECAF_NOEXCEPT throw()
#define DECAF_DELETE
#endif
namespace decaf {
static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); }
template<typename T, size_t alignment = 0> class SanitizingAllocator {
/* 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 std::ptrdiff_t difference_type;
template<typename U> struct rebind { typedef SanitizingAllocator<U> other; };
inline SanitizingAllocator() DECAF_NOEXCEPT {}
inline ~SanitizingAllocator() DECAF_NOEXCEPT {}
inline SanitizingAllocator(const SanitizingAllocator &) DECAF_NOEXCEPT {}
template<typename U, size_t a> inline SanitizingAllocator(const SanitizingAllocator<U, a> &) DECAF_NOEXCEPT {}
inline T* address(T& r) const DECAF_NOEXCEPT { return &r; }
inline const T* address(const T& r) const DECAF_NOEXCEPT { return &r; }
inline T* allocate (
size_type cnt,
typename std::allocator<void>::const_pointer = 0
) /*throw(std::bad_alloc)*/;
inline void deallocate(T* p, size_t size) DECAF_NOEXCEPT;
inline size_t max_size() const DECAF_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 DECAF_NOEXCEPT { return true; }
inline bool operator!=(SanitizingAllocator const&) const DECAF_NOEXCEPT { return false; }
};
typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer;
template<class T,class U, class V, class W>
inline bool memeq(const std::vector<T,U> &a, const std::vector<V,W> &b) {
if (a.size() != b.size()) return false;
return decaf_memeq(a.data(),b.data(),a.size());
}
template<class Base> class Serializable {
public:
inline size_t ser_size() const DECAF_NOEXCEPT { return static_cast<const Base*>(this)->ser_size(); }
inline void serialize_into(unsigned char *buf) const DECAF_NOEXCEPT {
static_cast<const Base*>(this)->serialize_into(buf);
}
inline SecureBuffer serialize() const /*throw(std::bad_alloc)*/ {
SecureBuffer out(ser_size());
serialize_into(out.data());
return out;
}
#if __cplusplus >= 201103L
explicit inline operator SecureBuffer() const /*throw(std::bad_alloc)*/ {
return serialize();
}
#endif
};
class Buffer;
class CryptoException : public std::exception {
public:
virtual const char * what() const DECAF_NOEXCEPT { return "CryptoException"; }
};
class LengthException : public std::exception {
public:
virtual const char * what() const DECAF_NOEXCEPT { return "LengthException"; }
};
struct NOINIT {};
class Rng {
protected:
Rng() {}
Rng(const Rng &) DECAF_DELETE;
Rng &operator=(const Rng &) DECAF_DELETE;
public:
virtual void read(Buffer buffer) DECAF_NOEXCEPT = 0;
inline SecureBuffer read(size_t length) /*throw(std::bad_alloc)*/;
};
class Block {
protected:
unsigned char *data_;
size_t size_;
const bool zero_on_destroy_;
public:
inline Block() : data_(NULL), size_(0), zero_on_destroy_(false) {}
inline Block(const char *data) DECAF_NOEXCEPT : data_((unsigned char *)data),
size_(strlen(data)), zero_on_destroy_(false) {}
inline Block(const unsigned char *data, size_t size, bool zero_on_destroy=false) DECAF_NOEXCEPT : data_((unsigned char *)data),
size_(size), zero_on_destroy_(zero_on_destroy) {}
inline Block(const std::string &s) : data_(
#if __cplusplus >= 201103L
((unsigned char *)(s.data()))
#else
((unsigned char *)&(s)[0])
#endif
), size_(s.size()), zero_on_destroy_(false) {}
template<class alloc> inline Block(const std::vector<unsigned char,alloc> &s)
: data_(
#if __cplusplus >= 201103L
((unsigned char *)(s.data()))
#else
((unsigned char *)&(s)[0])
#endif
), size_(s.size()), zero_on_destroy_(false) {}
inline const unsigned char *data() const DECAF_NOEXCEPT { return data_; }
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];
}
inline size_t size() const DECAF_NOEXCEPT { return size_; }
inline std::string get_string() const {
return std::string((const char *)data_,size_);
}
inline Block slice(size_t off, size_t length) const /*throw(LengthException)*/ {
if (off > size() || length > size() - off) throw LengthException();
return Block(data()+off, length);
}
inline decaf_bool_t contents_equal(const Block &b) const DECAF_NOEXCEPT {
if (b.size() != size()) return false;
return decaf_memeq(b.data(),data(),size());
}
inline operator SecureBuffer() const /*throw(std::bad_alloc)*/ {
return SecureBuffer(data_,data_+size_);
}
inline void zeroize() DECAF_NOEXCEPT { really_bzero(data_,size()); }
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:
inline decaf_bool_t operator>=(const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
inline decaf_bool_t operator<=(const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
inline decaf_bool_t operator> (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
inline decaf_bool_t operator< (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
inline void operator= (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
};
template<size_t Size> class FixedBlock : public Block {
public:
inline FixedBlock(const Block &b) /*throw(LengthException)*/ : Block(b.data(),Size) {
if (Size != b.size()) throw LengthException();
}
template<class alloc> inline FixedBlock(const std::vector<unsigned char,alloc> &s) : Block(s) {
if (Size != s.size()) throw LengthException();
}
inline explicit FixedBlock(const uint8_t data[Size]) DECAF_NOEXCEPT : Block(data,Size) {}
};
class Buffer : public Block {
public:
inline Buffer() DECAF_NOEXCEPT : Block() {}
inline Buffer(unsigned char *data, size_t size, bool zero_on_destroy=false) DECAF_NOEXCEPT : Block(data,size,zero_on_destroy) {}
template<class alloc> inline Buffer(std::vector<unsigned char,alloc> &s) : Block(s) {}
inline const unsigned char *data() const DECAF_NOEXCEPT { return data_; }
inline unsigned char* data() DECAF_NOEXCEPT { return data_; }
inline Buffer slice(size_t off, size_t length) /*throw(LengthException)*/;
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];
}
inline void assign(const Block b) /*throw(LengthException)*/ {
if (b.size() != size()) throw LengthException();
memmove(data(),b.data(),size());
}
private:
inline void operator= (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
};
template<size_t Size> class FixedBuffer : public Buffer {
public:
inline FixedBuffer(Buffer b) /*throw(LengthException)*/ : Buffer(b) {
if (Size != b.size()) throw LengthException();
}
inline FixedBuffer(SecureBuffer &b) /*throw(LengthException)*/ : Buffer(b) {
if (Size != b.size()) throw LengthException();
}
inline explicit FixedBuffer(uint8_t dat[Size],bool zero_on_destroy = false) DECAF_NOEXCEPT : Buffer(dat,Size,zero_on_destroy) {}
inline operator FixedBlock<Size>() const DECAF_NOEXCEPT {
return FixedBlock<Size>(data());
}
private:
inline void operator= (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
};
template<size_t Size> class FixedArrayBuffer : public FixedBuffer<Size> {
private:
uint8_t storage[Size];
public:
using Buffer::zeroize;
inline explicit FixedArrayBuffer() DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) { memset(storage,0,Size); }
inline explicit FixedArrayBuffer(const NOINIT &) DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) { }
inline explicit FixedArrayBuffer(Rng &r) DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) { r.read(*this); }
inline explicit FixedArrayBuffer(const FixedBlock<Size> &b) DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) {
memcpy(storage,b.data(),Size);
}
inline FixedArrayBuffer& operator=(const FixedBlock<Size> &b) DECAF_NOEXCEPT {
memcpy(storage,b.data(),Size); return *this;
}
inline FixedArrayBuffer& operator=(const FixedArrayBuffer<Size> &b) DECAF_NOEXCEPT {
memcpy(storage,b.data(),Size); return *this;
}
inline FixedArrayBuffer& operator=(const Block &b) /*throw(LengthException)*/ {
*this = FixedBlock<Size>(b);
}
inline explicit FixedArrayBuffer(const Block &b) /*throw(LengthException)*/ : FixedBuffer<Size>(storage,true) {
if (b.size() != Size) throw LengthException();
memcpy(storage,b.data(),Size);
}
inline explicit FixedArrayBuffer(const FixedArrayBuffer<Size> &b) DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) {
memcpy(storage,b.data(),Size);
}
~FixedArrayBuffer() DECAF_NOEXCEPT { zeroize(); }
};
Buffer Buffer::slice(size_t off, size_t length) /*throw(LengthException)*/ {
if (off > size() || length > size() - off) throw LengthException();
return Buffer(data()+off, length);
}
inline SecureBuffer Rng::read(size_t length) /*throw(std::bad_alloc)*/ {
SecureBuffer out(length); read(out); return out;
}
template <class T, class Wrapped>
class OwnedOrUnowned {
protected:
union {
Wrapped *mine;
const Wrapped *yours;
} ours;
bool is_mine;
inline void clear() DECAF_NOEXCEPT {
if (is_mine) {
really_bzero(ours.mine, T::size());
#ifdef _MSC_VER
_aligned_free(ours.mine);
#else
free(ours.mine);
#endif // _MSC_VER
ours.yours = T::default_value();
is_mine = false;
}
}
inline void alloc() /*throw(std::bad_alloc)*/ {
if (is_mine) return;
int ret = posix_memalign((void**)&ours.mine, T::alignment(), T::size());
if (ret || !ours.mine) {
is_mine = false;
throw std::bad_alloc();
}
is_mine = true;
}
inline const Wrapped *get() const DECAF_NOEXCEPT { return is_mine ? ours.mine : ours.yours; }
inline OwnedOrUnowned(
const Wrapped &yours = *T::default_value()
) DECAF_NOEXCEPT {
ours.yours = &yours;
is_mine = false;
}
inline T &operator=(const OwnedOrUnowned &it) /*throw(std::bad_alloc)*/ {
if (this == &it) return *(T*)this;
if (it.is_mine) {
alloc();
memcpy(ours.mine,it.ours.mine,T::size());
} else {
clear();
ours.yours = it.ours.yours;
}
is_mine = it.is_mine;
return *(T*)this;
}
#if __cplusplus >= 201103L
inline T &operator=(OwnedOrUnowned &&it) DECAF_NOEXCEPT {
if (this == &it) return *(T*)this;
clear();
ours = it.ours;
is_mine = it.is_mine;
it.is_mine = false;
it.ours.yours = T::default_value;
return *this;
}
#endif
};
/*******************************************/
/* Inline implementations below this point */
/*******************************************/
template<typename T, size_t alignment>
T* SanitizingAllocator<T,alignment>::allocate (
size_type cnt,
typename std::allocator<void>::const_pointer
) /*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);
}
template<typename T, size_t alignment>
void SanitizingAllocator<T,alignment>::deallocate(T* p, size_t size) DECAF_NOEXCEPT {
if (p==NULL) return;
really_bzero(reinterpret_cast<void*>(p), size);
#ifdef _MSC_VER
if (alignment)
_aligned_free(reinterpret_cast<void*>(p));
else
#endif // _MSC_VER
free(reinterpret_cast<void*>(p));
}
} /* namespace decaf */
#undef DECAF_NOEXCEPT
#undef DECAF_DELETE
#endif /* __DECAF_SECURE_BUFFER_HXX__ */
decaf::Block
A reference to a block of data, which (when accessed through this base class) is const.
Definition secure_buffer.hxx:159
decaf::Block::Block
Block(const std::vector< unsigned char, alloc > &s)
Block from std::vector.
Definition secure_buffer.hxx:189
decaf::Block::Block
Block(const unsigned char *data, size_t size, bool zero_on_destroy=false) DECAF_NOEXCEPT
Unowned init.
Definition secure_buffer.hxx:176
decaf::Block::data
const unsigned char * data() const DECAF_NOEXCEPT
Get const data.
Definition secure_buffer.hxx:199
decaf::Block::Block
Block(const char *data) DECAF_NOEXCEPT
Init from C string.
Definition secure_buffer.hxx:172
decaf::Block::Block
Block()
Null initialization.
Definition secure_buffer.hxx:169
decaf::Block::zeroize
void zeroize() DECAF_NOEXCEPT
Securely set the buffer to 0.
Definition secure_buffer.hxx:233
decaf::Block::contents_equal
decaf_bool_t contents_equal(const Block &b) const DECAF_NOEXCEPT
Content-wise comparison; constant-time if they are the same length.
Definition secure_buffer.hxx:222
decaf::Block::size
size_t size() const DECAF_NOEXCEPT
Get the size.
Definition secure_buffer.hxx:208
decaf::Block::Block
Block(const std::string &s)
Block from std::string.
Definition secure_buffer.hxx:180
decaf::Block::debug_print_hex
void debug_print_hex(const char *name=NULL)
Debugging print in hex.
Definition secure_buffer.hxx:236
decaf::Block::get_string
std::string get_string() const
Convert to C++ string.
Definition secure_buffer.hxx:211
decaf::Block::operator[]
const unsigned char & operator[](size_t off) const
Subscript.
Definition secure_buffer.hxx:202
decaf::Block::slice
Block slice(size_t off, size_t length) const
Slice the buffer.
Definition secure_buffer.hxx:216
decaf::Buffer
A reference to a writable block of data.
Definition secure_buffer.hxx:270
decaf::Buffer::operator[]
unsigned char & operator[](size_t off)
Subscript.
Definition secure_buffer.hxx:291
decaf::Buffer::data
unsigned char * data() DECAF_NOEXCEPT
Cast to unsigned char.
Definition secure_buffer.hxx:285
decaf::Buffer::data
const unsigned char * data() const DECAF_NOEXCEPT
Get const data.
Definition secure_buffer.hxx:282
decaf::Buffer::Buffer
Buffer() DECAF_NOEXCEPT
Null init.
Definition secure_buffer.hxx:273
decaf::Buffer::Buffer
Buffer(std::vector< unsigned char, alloc > &s)
Block from std::vector.
Definition secure_buffer.hxx:279
decaf::Buffer::slice
Buffer slice(size_t off, size_t length)
Slice the buffer.
decaf::Buffer::assign
void assign(const Block b)
Copy from another block.
Definition secure_buffer.hxx:297
decaf::Buffer::Buffer
Buffer(unsigned char *data, size_t size, bool zero_on_destroy=false) DECAF_NOEXCEPT
Unowned init.
Definition secure_buffer.hxx:276
decaf::CryptoException
An exception for when crypto (ie point decode) has failed.
Definition secure_buffer.hxx:119
decaf::CryptoException::what
virtual const char * what() const DECAF_NOEXCEPT
Definition secure_buffer.hxx:122
decaf::FixedArrayBuffer
A fixed-size stack-allocated buffer (for DECAF_NOEXCEPT semantics)
Definition secure_buffer.hxx:337
decaf::FixedArrayBuffer::FixedArrayBuffer
FixedArrayBuffer(Rng &r) DECAF_NOEXCEPT
New random buffer.
Definition secure_buffer.hxx:350
decaf::FixedArrayBuffer::FixedArrayBuffer
FixedArrayBuffer() DECAF_NOEXCEPT
New buffer initialized to zero.
Definition secure_buffer.hxx:344
decaf::FixedArrayBuffer::operator=
FixedArrayBuffer & operator=(const Block &b)
Copy operator.
Definition secure_buffer.hxx:368
decaf::FixedArrayBuffer::operator=
FixedArrayBuffer & operator=(const FixedBlock< Size > &b) DECAF_NOEXCEPT
Copy operator.
Definition secure_buffer.hxx:358
decaf::FixedArrayBuffer::FixedArrayBuffer
FixedArrayBuffer(const FixedBlock< Size > &b) DECAF_NOEXCEPT
Copy constructor.
Definition secure_buffer.hxx:353
decaf::FixedArrayBuffer::FixedArrayBuffer
FixedArrayBuffer(const NOINIT &) DECAF_NOEXCEPT
New uninitialized buffer.
Definition secure_buffer.hxx:347
decaf::FixedArrayBuffer::FixedArrayBuffer
FixedArrayBuffer(const Block &b)
Copy constructor.
Definition secure_buffer.hxx:373
decaf::FixedArrayBuffer::operator=
FixedArrayBuffer & operator=(const FixedArrayBuffer< Size > &b) DECAF_NOEXCEPT
Copy operator.
Definition secure_buffer.hxx:363
decaf::FixedArrayBuffer::FixedArrayBuffer
FixedArrayBuffer(const FixedArrayBuffer< Size > &b) DECAF_NOEXCEPT
Copy constructor.
Definition secure_buffer.hxx:379
decaf::FixedArrayBuffer::~FixedArrayBuffer
~FixedArrayBuffer() DECAF_NOEXCEPT
Destroy the buffer.
Definition secure_buffer.hxx:384
decaf::FixedBlock
A fixed-size block.
Definition secure_buffer.hxx:253
decaf::FixedBlock::FixedBlock
FixedBlock(const Block &b)
Check a block's length.
Definition secure_buffer.hxx:256
decaf::FixedBlock::FixedBlock
FixedBlock(const uint8_t data[Size]) DECAF_NOEXCEPT
Explicitly pass a C buffer.
Definition secure_buffer.hxx:266
decaf::FixedBlock::FixedBlock
FixedBlock(const std::vector< unsigned char, alloc > &s)
Block from std::vector.
Definition secure_buffer.hxx:261
decaf::FixedBuffer
A fixed-size block.
Definition secure_buffer.hxx:310
decaf::FixedBuffer::FixedBuffer
FixedBuffer(Buffer b)
Check a block's length.
Definition secure_buffer.hxx:313
decaf::FixedBuffer::FixedBuffer
FixedBuffer(uint8_t dat[Size], bool zero_on_destroy=false) DECAF_NOEXCEPT
Explicitly pass a C buffer.
Definition secure_buffer.hxx:323
decaf::FixedBuffer::FixedBuffer
FixedBuffer(SecureBuffer &b)
Check a block's length.
Definition secure_buffer.hxx:318
decaf::LengthException
An exception for when crypto (ie point decode) has failed.
Definition secure_buffer.hxx:126
decaf::LengthException::what
virtual const char * what() const DECAF_NOEXCEPT
Definition secure_buffer.hxx:129
decaf::Rng
Prototype of a random number generator.
Definition secure_buffer.hxx:138
decaf::Rng::read
SecureBuffer read(size_t length)
Read into a SecureBuffer.
decaf::Rng::Rng
Rng()
Empty initializer.
Definition secure_buffer.hxx:141
decaf::Rng::Rng
Rng(const Rng &) DECAF_DELETE
Not copyable.
decaf::Rng::operator=
Rng & operator=(const Rng &) DECAF_DELETE
Not copyable.
decaf::Rng::read
virtual void read(Buffer buffer) DECAF_NOEXCEPT=0
Read into a Buffer.
decaf::SanitizingAllocator
An allocator which zeros its memory on free.
Definition secure_buffer.hxx:44
decaf::Serializable
Base class of objects which support serialization.
Definition secure_buffer.hxx:89
decaf::Serializable::ser_size
size_t ser_size() const DECAF_NOEXCEPT
Return the number of bytes needed to serialize this object.
Definition secure_buffer.hxx:92
decaf::Serializable::serialize_into
void serialize_into(unsigned char *buf) const DECAF_NOEXCEPT
Serialize this object into a buffer.
Definition secure_buffer.hxx:95
decaf::Serializable::serialize
SecureBuffer serialize() const
Serialize this object into a SecureBuffer and return it.
Definition secure_buffer.hxx:100
decaf_bzero
void DECAF_API_VIS decaf_bzero(void *data, size_t size) DECAF_NONNULL
Overwrite data with zeros.
decaf_memeq
decaf_bool_t DECAF_API_VIS decaf_memeq(const void *data1, const void *data2, size_t size) DECAF_NONNULL DECAF_WARN_UNUSED
Compare two buffers, returning DECAF_TRUE if they are equal.
decaf
Namespace for all C++ decaf objects.
Definition decaf.hxx:22
decaf::memeq
bool memeq(const std::vector< T, U > &a, const std::vector< V, W > &b)
Constant-time compare two buffers.
Definition secure_buffer.hxx:83
decaf::SecureBuffer
std::vector< unsigned char, SanitizingAllocator< unsigned char, 0 > > SecureBuffer
A variant of std::vector which securely zerozes its state when destructed.
Definition secure_buffer.hxx:79
decaf::NOINIT
Passed to constructors to avoid (conservative) initialization.
Definition secure_buffer.hxx:133