libdecaf
secure_buffer.hxx
Go to the documentation of this file.
1 
11 #ifndef __DECAF_SECURE_BUFFER_HXX__
12 #define __DECAF_SECURE_BUFFER_HXX__ 1
13 
14 #include <string>
15 #include <sys/types.h>
16 #include <stdio.h>
17 #include <vector>
18 #include <stdexcept>
19 #include <cstddef>
20 #include <limits>
21 
22 #if defined(_MSC_VER) // MSVC does not have built in posix_memalign
23 #define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno)
24 #endif
25 
27 #if __cplusplus >= 201103L
28 #define DECAF_NOEXCEPT noexcept
29 #define DECAF_DELETE = delete
30 #else
31 #define DECAF_NOEXCEPT throw()
32 #define DECAF_DELETE
33 #endif
36 namespace decaf {
37 
41 static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); }
42 
44 template<typename T, size_t alignment = 0> class SanitizingAllocator {
46 /* Based on http://www.codeproject.com/Articles/4795/C-Standard-Allocator-An-Introduction-and-Implement */
47 public:
48  typedef T value_type;
49  typedef T* pointer;
50  typedef const T* const_pointer;
51  typedef T& reference;
52  typedef const T& const_reference;
53  typedef size_t size_type;
54  typedef std::ptrdiff_t difference_type;
55 
56  template<typename U> struct rebind { typedef SanitizingAllocator<U> other; };
57  inline SanitizingAllocator() DECAF_NOEXCEPT {}
58  inline ~SanitizingAllocator() DECAF_NOEXCEPT {}
59  inline SanitizingAllocator(const SanitizingAllocator &) DECAF_NOEXCEPT {}
60  template<typename U, size_t a> inline SanitizingAllocator(const SanitizingAllocator<U, a> &) DECAF_NOEXCEPT {}
61 
62  inline T* address(T& r) const DECAF_NOEXCEPT { return &r; }
63  inline const T* address(const T& r) const DECAF_NOEXCEPT { return &r; }
64  inline T* allocate (
65  size_type cnt,
66  typename std::allocator<void>::const_pointer = 0
67  ) /*throw(std::bad_alloc)*/;
68  inline void deallocate(T* p, size_t size) DECAF_NOEXCEPT;
69  inline size_t max_size() const DECAF_NOEXCEPT { return std::numeric_limits<size_t>::max() / sizeof(T); }
70  inline void construct(T* p, const T& t) { new(p) T(t); }
71  inline void destroy(T* p) { p->~T(); }
72 
73  inline bool operator==(SanitizingAllocator const&) const DECAF_NOEXCEPT { return true; }
74  inline bool operator!=(SanitizingAllocator const&) const DECAF_NOEXCEPT { return false; }
76 };
77 
79 typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer;
80 
82 template<class T,class U, class V, class W>
83 inline bool memeq(const std::vector<T,U> &a, const std::vector<V,W> &b) {
84  if (a.size() != b.size()) return false;
85  return decaf_memeq(a.data(),b.data(),a.size());
86 }
87 
89 template<class Base> class Serializable {
90 public:
92  inline size_t ser_size() const DECAF_NOEXCEPT { return static_cast<const Base*>(this)->ser_size(); }
93 
95  inline void serialize_into(unsigned char *buf) const DECAF_NOEXCEPT {
96  static_cast<const Base*>(this)->serialize_into(buf);
97  }
98 
100  inline SecureBuffer serialize() const /*throw(std::bad_alloc)*/ {
101  SecureBuffer out(ser_size());
102  serialize_into(out.data());
103  return out;
104  }
105 
107 #if __cplusplus >= 201103L
108  explicit inline operator SecureBuffer() const /*throw(std::bad_alloc)*/ {
109  return serialize();
110  }
111 #endif
112 };
113 
115 class Buffer;
119 class CryptoException : public std::exception {
120 public:
122  virtual const char * what() const DECAF_NOEXCEPT { return "CryptoException"; }
123 };
124 
126 class LengthException : public std::exception {
127 public:
129  virtual const char * what() const DECAF_NOEXCEPT { return "LengthException"; }
130 };
131 
133 struct NOINIT {};
134 
138 class Rng {
139 protected:
141  Rng() {}
142 
144  Rng(const Rng &) DECAF_DELETE;
145 
147  Rng &operator=(const Rng &) DECAF_DELETE;
148 
149 public:
151  virtual void read(Buffer buffer) DECAF_NOEXCEPT = 0;
152 
154  inline SecureBuffer read(size_t length) /*throw(std::bad_alloc)*/;
155 };
156 
157 
159 class Block {
160 protected:
162  unsigned char *data_;
163  size_t size_;
164  const bool zero_on_destroy_;
167 public:
169  inline Block() : data_(NULL), size_(0), zero_on_destroy_(false) {}
170 
172  inline Block(const char *data) DECAF_NOEXCEPT : data_((unsigned char *)data),
173  size_(strlen(data)), zero_on_destroy_(false) {}
174 
176  inline Block(const unsigned char *data, size_t size, bool zero_on_destroy=false) DECAF_NOEXCEPT : data_((unsigned char *)data),
177  size_(size), zero_on_destroy_(zero_on_destroy) {}
178 
180  inline Block(const std::string &s) : data_(
181  #if __cplusplus >= 201103L
182  ((unsigned char *)&(s)[0])
183  #else
184  ((unsigned char *)(s.data()))
185  #endif
186  ), size_(s.size()), zero_on_destroy_(false) {}
187 
189  template<class alloc> inline Block(const std::vector<unsigned char,alloc> &s)
190  : data_(((unsigned char *)&(s)[0])), size_(s.size()), zero_on_destroy_(false) {}
191 
193  inline const unsigned char *data() const DECAF_NOEXCEPT { return data_; }
194 
196  inline const unsigned char &operator[](size_t off) const /*throw(std::out_of_range)*/ {
197  if (off >= size()) throw(std::out_of_range("decaf::Block"));
198  return data_[off];
199  }
200 
202  inline size_t size() const DECAF_NOEXCEPT { return size_; }
203 
205  inline std::string get_string() const {
206  return std::string((const char *)data_,size_);
207  }
208 
210  inline Block slice(size_t off, size_t length) const /*throw(LengthException)*/ {
211  if (off > size() || length > size() - off) throw LengthException();
212  return Block(data()+off, length);
213  }
214 
216  inline decaf_bool_t contents_equal(const Block &b) const DECAF_NOEXCEPT {
217  if (b.size() != size()) return false;
218  return decaf_memeq(b.data(),data(),size());
219  }
220 
222  inline operator SecureBuffer() const /*throw(std::bad_alloc)*/ {
223  return SecureBuffer(data_,data_+size_);
224  }
225 
227  inline void zeroize() DECAF_NOEXCEPT { really_bzero(data_,size()); }
228 
230  inline void debug_print_hex(const char *name = NULL) {
231  if (name) printf("%s = ", name);
232  for (size_t s = 0; s < size(); s++) printf("%02x", data_[s]);
233  printf("\n");
234  }
235 
236 private:
238  inline decaf_bool_t operator>=(const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
239  inline decaf_bool_t operator<=(const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
240  inline decaf_bool_t operator> (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
241  inline decaf_bool_t operator< (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
242  inline void operator= (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
244 };
245 
247 template<size_t Size> class FixedBlock : public Block {
248 public:
250  inline FixedBlock(const Block &b) /*throw(LengthException)*/ : Block(b.data(),Size) {
251  if (Size != b.size()) throw LengthException();
252  }
253 
255  template<class alloc> inline FixedBlock(const std::vector<unsigned char,alloc> &s) : Block(s) {
256  if (Size != s.size()) throw LengthException();
257  }
258 
260  inline explicit FixedBlock(const uint8_t data[Size]) DECAF_NOEXCEPT : Block(data,Size) {}
261 };
262 
264 class Buffer : public Block {
265 public:
267  inline Buffer() DECAF_NOEXCEPT : Block() {}
268 
270  inline Buffer(unsigned char *data, size_t size, bool zero_on_destroy=false) DECAF_NOEXCEPT : Block(data,size,zero_on_destroy) {}
271 
273  template<class alloc> inline Buffer(std::vector<unsigned char,alloc> &s) : Block(s) {}
274 
276  inline const unsigned char *data() const DECAF_NOEXCEPT { return data_; }
277 
279  inline unsigned char* data() DECAF_NOEXCEPT { return data_; }
280 
282  inline Buffer slice(size_t off, size_t length) /*throw(LengthException)*/;
283 
285  inline unsigned char &operator[](size_t off) /*throw(std::out_of_range)*/ {
286  if (off >= size()) throw(std::out_of_range("decaf::Buffer"));
287  return data_[off];
288  }
289 
291  inline void assign(const Block b) /*throw(LengthException)*/ {
292  if (b.size() != size()) throw LengthException();
293  memmove(data(),b.data(),size());
294  }
295 
296 private:
298  inline void operator= (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
300 };
301 
302 
304 template<size_t Size> class FixedBuffer : public Buffer {
305 public:
307  inline FixedBuffer(Buffer b) /*throw(LengthException)*/ : Buffer(b) {
308  if (Size != b.size()) throw LengthException();
309  }
310 
312  inline FixedBuffer(SecureBuffer &b) /*throw(LengthException)*/ : Buffer(b) {
313  if (Size != b.size()) throw LengthException();
314  }
315 
317  inline explicit FixedBuffer(uint8_t dat[Size],bool zero_on_destroy = false) DECAF_NOEXCEPT : Buffer(dat,Size,zero_on_destroy) {}
318 
320  inline operator FixedBlock<Size>() const DECAF_NOEXCEPT {
321  return FixedBlock<Size>(data());
322  }
323 
324 private:
326  inline void operator= (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
328 };
329 
331 template<size_t Size> class FixedArrayBuffer : public FixedBuffer<Size> {
332 private:
333  uint8_t storage[Size];
334 public:
335  using Buffer::zeroize;
336 
338  inline explicit FixedArrayBuffer() DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) { memset(storage,0,Size); }
339 
341  inline explicit FixedArrayBuffer(const NOINIT &) DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) { }
342 
344  inline explicit FixedArrayBuffer(Rng &r) DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) { r.read(*this); }
345 
347  inline explicit FixedArrayBuffer(const FixedBlock<Size> &b) DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) {
348  memcpy(storage,b.data(),Size);
349  }
350 
352  inline FixedArrayBuffer& operator=(const FixedBlock<Size> &b) DECAF_NOEXCEPT {
353  memcpy(storage,b.data(),Size); return *this;
354  }
355 
357  inline FixedArrayBuffer& operator=(const FixedArrayBuffer<Size> &b) DECAF_NOEXCEPT {
358  memcpy(storage,b.data(),Size); return *this;
359  }
360 
362  inline FixedArrayBuffer& operator=(const Block &b) /*throw(LengthException)*/ {
363  *this = FixedBlock<Size>(b);
364  }
365 
367  inline explicit FixedArrayBuffer(const Block &b) /*throw(LengthException)*/ : FixedBuffer<Size>(storage,true) {
368  if (b.size() != Size) throw LengthException();
369  memcpy(storage,b.data(),Size);
370  }
371 
373  inline explicit FixedArrayBuffer(const FixedArrayBuffer<Size> &b) DECAF_NOEXCEPT : FixedBuffer<Size>(storage,true) {
374  memcpy(storage,b.data(),Size);
375  }
376 
378  ~FixedArrayBuffer() DECAF_NOEXCEPT { zeroize(); }
379 };
380 
382 Buffer Buffer::slice(size_t off, size_t length) /*throw(LengthException)*/ {
383  if (off > size() || length > size() - off) throw LengthException();
384  return Buffer(data()+off, length);
385 }
386 
387 inline SecureBuffer Rng::read(size_t length) /*throw(std::bad_alloc)*/ {
388  SecureBuffer out(length); read(out); return out;
389 }
396 template <class T, class Wrapped>
397 class OwnedOrUnowned {
398 protected:
399  union {
400  Wrapped *mine;
401  const Wrapped *yours;
402  } ours;
403  bool is_mine;
404 
405  inline void clear() DECAF_NOEXCEPT {
406  if (is_mine) {
407  really_bzero(ours.mine, T::size());
408  free(ours.mine);
409  ours.yours = T::default_value();
410  is_mine = false;
411  }
412  }
413  inline void alloc() /*throw(std::bad_alloc)*/ {
414  if (is_mine) return;
415  int ret = posix_memalign((void**)&ours.mine, T::alignment(), T::size());
416  if (ret || !ours.mine) {
417  is_mine = false;
418  throw std::bad_alloc();
419  }
420  is_mine = true;
421  }
422  inline const Wrapped *get() const DECAF_NOEXCEPT { return is_mine ? ours.mine : ours.yours; }
423 
424  inline OwnedOrUnowned(
425  const Wrapped &yours = *T::default_value()
426  ) DECAF_NOEXCEPT {
427  ours.yours = &yours;
428  is_mine = false;
429  }
430 
434  inline T &operator=(const OwnedOrUnowned &it) /*throw(std::bad_alloc)*/ {
435  if (this == &it) return *(T*)this;
436  if (it.is_mine) {
437  alloc();
438  memcpy(ours.mine,it.ours.mine,T::size());
439  } else {
440  clear();
441  ours.yours = it.ours.yours;
442  }
443  is_mine = it.is_mine;
444  return *(T*)this;
445  }
446 
447 #if __cplusplus >= 201103L
448  inline T &operator=(OwnedOrUnowned &&it) DECAF_NOEXCEPT {
449  if (this == &it) return *(T*)this;
450  clear();
451  ours = it.ours;
452  is_mine = it.is_mine;
453  it.is_mine = false;
454  it.ours.yours = T::default_value;
455  return *this;
456  }
457 #endif
458 };
461 /*******************************************/
462 /* Inline implementations below this point */
463 /*******************************************/
464 
466 template<typename T, size_t alignment>
467 T* SanitizingAllocator<T,alignment>::allocate (
468  size_type cnt,
469  typename std::allocator<void>::const_pointer
470 ) /*throw(std::bad_alloc)*/ {
471  void *v;
472  int ret = 0;
473 
474  if (alignment) ret = posix_memalign(&v, alignment, cnt * sizeof(T));
475  else v = malloc(cnt * sizeof(T));
476 
477  if (ret || v==NULL) throw(std::bad_alloc());
478  return reinterpret_cast<T*>(v);
479 }
480 
481 template<typename T, size_t alignment>
482 void SanitizingAllocator<T,alignment>::deallocate(T* p, size_t size) DECAF_NOEXCEPT {
483  if (p==NULL) return;
484  really_bzero(reinterpret_cast<void*>(p), size);
485  free(reinterpret_cast<void*>(p));
486 }
487 
490 } /* namespace decaf */
491 
492 
493 #undef DECAF_NOEXCEPT
494 #undef DECAF_DELETE
495 
496 #endif /* __DECAF_SECURE_BUFFER_HXX__ */
A reference to a block of data, which (when accessed through this base class) is const.
Definition: secure_buffer.hxx:159
Block(const std::vector< unsigned char, alloc > &s)
Block from std::vector.
Definition: secure_buffer.hxx:189
Block(const unsigned char *data, size_t size, bool zero_on_destroy=false) DECAF_NOEXCEPT
Unowned init.
Definition: secure_buffer.hxx:176
Block(const char *data) DECAF_NOEXCEPT
Init from C string.
Definition: secure_buffer.hxx:172
Block()
Null initialization.
Definition: secure_buffer.hxx:169
void zeroize() DECAF_NOEXCEPT
Securely set the buffer to 0.
Definition: secure_buffer.hxx:227
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:216
size_t size() const DECAF_NOEXCEPT
Get the size.
Definition: secure_buffer.hxx:202
Block(const std::string &s)
Block from std::string.
Definition: secure_buffer.hxx:180
void debug_print_hex(const char *name=NULL)
Debugging print in hex.
Definition: secure_buffer.hxx:230
std::string get_string() const
Convert to C++ string.
Definition: secure_buffer.hxx:205
const unsigned char * data() const DECAF_NOEXCEPT
Get const data.
Definition: secure_buffer.hxx:193
const unsigned char & operator[](size_t off) const
Subscript.
Definition: secure_buffer.hxx:196
Block slice(size_t off, size_t length) const
Slice the buffer.
Definition: secure_buffer.hxx:210
A reference to a writable block of data.
Definition: secure_buffer.hxx:264
const unsigned char * data() const DECAF_NOEXCEPT
Get const data.
Definition: secure_buffer.hxx:276
unsigned char * data() DECAF_NOEXCEPT
Cast to unsigned char.
Definition: secure_buffer.hxx:279
unsigned char & operator[](size_t off)
Subscript.
Definition: secure_buffer.hxx:285
Buffer() DECAF_NOEXCEPT
Null init.
Definition: secure_buffer.hxx:267
Buffer(std::vector< unsigned char, alloc > &s)
Block from std::vector.
Definition: secure_buffer.hxx:273
Buffer slice(size_t off, size_t length)
Slice the buffer.
void assign(const Block b)
Copy from another block.
Definition: secure_buffer.hxx:291
Buffer(unsigned char *data, size_t size, bool zero_on_destroy=false) DECAF_NOEXCEPT
Unowned init.
Definition: secure_buffer.hxx:270
An exception for when crypto (ie point decode) has failed.
Definition: secure_buffer.hxx:119
virtual const char * what() const DECAF_NOEXCEPT
Definition: secure_buffer.hxx:122
A fixed-size stack-allocated buffer (for DECAF_NOEXCEPT semantics)
Definition: secure_buffer.hxx:331
FixedArrayBuffer(Rng &r) DECAF_NOEXCEPT
New random buffer.
Definition: secure_buffer.hxx:344
FixedArrayBuffer() DECAF_NOEXCEPT
New buffer initialized to zero.
Definition: secure_buffer.hxx:338
FixedArrayBuffer & operator=(const FixedArrayBuffer< Size > &b) DECAF_NOEXCEPT
Copy operator.
Definition: secure_buffer.hxx:357
FixedArrayBuffer & operator=(const FixedBlock< Size > &b) DECAF_NOEXCEPT
Copy operator.
Definition: secure_buffer.hxx:352
FixedArrayBuffer(const FixedBlock< Size > &b) DECAF_NOEXCEPT
Copy constructor.
Definition: secure_buffer.hxx:347
FixedArrayBuffer(const NOINIT &) DECAF_NOEXCEPT
New uninitialized buffer.
Definition: secure_buffer.hxx:341
FixedArrayBuffer(const Block &b)
Copy constructor.
Definition: secure_buffer.hxx:367
FixedArrayBuffer & operator=(const Block &b)
Copy operator.
Definition: secure_buffer.hxx:362
FixedArrayBuffer(const FixedArrayBuffer< Size > &b) DECAF_NOEXCEPT
Copy constructor.
Definition: secure_buffer.hxx:373
~FixedArrayBuffer() DECAF_NOEXCEPT
Destroy the buffer.
Definition: secure_buffer.hxx:378
A fixed-size block.
Definition: secure_buffer.hxx:247
FixedBlock(const Block &b)
Check a block's length.
Definition: secure_buffer.hxx:250
FixedBlock(const uint8_t data[Size]) DECAF_NOEXCEPT
Explicitly pass a C buffer.
Definition: secure_buffer.hxx:260
FixedBlock(const std::vector< unsigned char, alloc > &s)
Block from std::vector.
Definition: secure_buffer.hxx:255
A fixed-size block.
Definition: secure_buffer.hxx:304
FixedBuffer(Buffer b)
Check a block's length.
Definition: secure_buffer.hxx:307
FixedBuffer(uint8_t dat[Size], bool zero_on_destroy=false) DECAF_NOEXCEPT
Explicitly pass a C buffer.
Definition: secure_buffer.hxx:317
FixedBuffer(SecureBuffer &b)
Check a block's length.
Definition: secure_buffer.hxx:312
An exception for when crypto (ie point decode) has failed.
Definition: secure_buffer.hxx:126
virtual const char * what() const DECAF_NOEXCEPT
Definition: secure_buffer.hxx:129
Prototype of a random number generator.
Definition: secure_buffer.hxx:138
SecureBuffer read(size_t length)
Read into a SecureBuffer.
Rng()
Empty initializer.
Definition: secure_buffer.hxx:141
Rng & operator=(const Rng &) DECAF_DELETE
Not copyable.
Rng(const Rng &) DECAF_DELETE
Not copyable.
virtual void read(Buffer buffer) DECAF_NOEXCEPT=0
Read into a Buffer.
An allocator which zeros its memory on free.
Definition: secure_buffer.hxx:44
Base class of objects which support serialization.
Definition: secure_buffer.hxx:89
size_t ser_size() const DECAF_NOEXCEPT
Return the number of bytes needed to serialize this object.
Definition: secure_buffer.hxx:92
void serialize_into(unsigned char *buf) const DECAF_NOEXCEPT
Serialize this object into a buffer.
Definition: secure_buffer.hxx:95
SecureBuffer serialize() const
Serialize this object into a SecureBuffer and return it.
Definition: secure_buffer.hxx:100
void DECAF_API_VIS decaf_bzero(void *data, size_t size) DECAF_NONNULL
Overwrite data with zeros.
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.
uint32_t decaf_bool_t
"Boolean" type, will be set to all-zero or all-one (i.e.
Definition: common.h:89
Namespace for all libdecaf C++ objects.
Definition: ed255.hxx:41
bool memeq(const std::vector< T, U > &a, const std::vector< V, W > &b)
Constant-time compare two buffers.
Definition: secure_buffer.hxx:83
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
Passed to constructors to avoid (conservative) initialization.
Definition: secure_buffer.hxx:133