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
36namespace decaf {
37
41static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); }
42
44template<typename T, size_t alignment = 0> class SanitizingAllocator {
46/* Based on http://www.codeproject.com/Articles/4795/C-Standard-Allocator-An-Introduction-and-Implement */
47public:
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
79typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer;
80
82template<class T,class U, class V, class W>
83inline 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
89template<class Base> class Serializable {
90public:
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
115class Buffer;
119class CryptoException : public std::exception {
120public:
122 virtual const char * what() const DECAF_NOEXCEPT { return "CryptoException"; }
123};
124
126class LengthException : public std::exception {
127public:
129 virtual const char * what() const DECAF_NOEXCEPT { return "LengthException"; }
130};
131
133struct NOINIT {};
134
138class Rng {
139protected:
141 Rng() {}
142
144 Rng(const Rng &) DECAF_DELETE;
145
147 Rng &operator=(const Rng &) DECAF_DELETE;
148
149public:
151 virtual void read(Buffer buffer) DECAF_NOEXCEPT = 0;
152
154 inline SecureBuffer read(size_t length) /*throw(std::bad_alloc)*/;
155};
156
157
159class Block {
160protected:
162 unsigned char *data_;
163 size_t size_;
164 const bool zero_on_destroy_;
167public:
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
236private:
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
247template<size_t Size> class FixedBlock : public Block {
248public:
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
264class Buffer : public Block {
265public:
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
296private:
298 inline void operator= (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
300};
301
302
304template<size_t Size> class FixedBuffer : public Buffer {
305public:
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
324private:
326 inline void operator= (const Block &b) const DECAF_NOEXCEPT DECAF_DELETE;
328};
329
331template<size_t Size> class FixedArrayBuffer : public FixedBuffer<Size> {
332private:
333 uint8_t storage[Size];
334public:
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
382Buffer 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
387inline SecureBuffer Rng::read(size_t length) /*throw(std::bad_alloc)*/ {
388 SecureBuffer out(length); read(out); return out;
389}
396template <class T, class Wrapped>
397class OwnedOrUnowned {
398protected:
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
466template<typename T, size_t alignment>
467T* 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
481template<typename T, size_t alignment>
482void 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
const unsigned char * data() const DECAF_NOEXCEPT
Get const data.
Definition: secure_buffer.hxx:193
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 & 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
unsigned char & operator[](size_t off)
Subscript.
Definition: secure_buffer.hxx:285
unsigned char * data() DECAF_NOEXCEPT
Cast to unsigned char.
Definition: secure_buffer.hxx:279
const unsigned char * data() const DECAF_NOEXCEPT
Get const data.
Definition: secure_buffer.hxx:276
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 Block &b)
Copy operator.
Definition: secure_buffer.hxx:362
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 FixedArrayBuffer< Size > &b) DECAF_NOEXCEPT
Copy operator.
Definition: secure_buffer.hxx:357
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(const Rng &) DECAF_DELETE
Not copyable.
Rng & operator=(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 C++ decaf objects.
Definition: decaf.hxx:22
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