Crypto++
secblock.h
1 // secblock.h - written and placed in the public domain by Wei Dai
2 
3 #ifndef CRYPTOPP_SECBLOCK_H
4 #define CRYPTOPP_SECBLOCK_H
5 
6 #include "config.h"
7 #include "misc.h"
8 #include <assert.h>
9 
10 NAMESPACE_BEGIN(CryptoPP)
11 
12 // ************** secure memory allocation ***************
13 
14 template<class T>
16 {
17 public:
18  typedef T value_type;
19  typedef size_t size_type;
20 #ifdef CRYPTOPP_MSVCRT6
21  typedef ptrdiff_t difference_type;
22 #else
23  typedef std::ptrdiff_t difference_type;
24 #endif
25  typedef T * pointer;
26  typedef const T * const_pointer;
27  typedef T & reference;
28  typedef const T & const_reference;
29 
30  pointer address(reference r) const {return (&r);}
31  const_pointer address(const_reference r) const {return (&r); }
32  void construct(pointer p, const T& val) {new (p) T(val);}
33  void destroy(pointer p) {p->~T();}
34  size_type max_size() const {return ~size_type(0)/sizeof(T);} // switch to std::numeric_limits<T>::max later
35 
36 protected:
37  static void CheckSize(size_t n)
38  {
39  if (n > ~size_t(0) / sizeof(T))
40  throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
41  }
42 };
43 
44 #define CRYPTOPP_INHERIT_ALLOCATOR_TYPES \
45 typedef typename AllocatorBase<T>::value_type value_type;\
46 typedef typename AllocatorBase<T>::size_type size_type;\
47 typedef typename AllocatorBase<T>::difference_type difference_type;\
48 typedef typename AllocatorBase<T>::pointer pointer;\
49 typedef typename AllocatorBase<T>::const_pointer const_pointer;\
50 typedef typename AllocatorBase<T>::reference reference;\
51 typedef typename AllocatorBase<T>::const_reference const_reference;
52 
53 #if defined(_MSC_VER) && (_MSC_VER < 1300)
54 // this pragma causes an internal compiler error if placed immediately before std::swap(a, b)
55 #pragma warning(push)
56 #pragma warning(disable: 4700) // VC60 workaround: don't know how to get rid of this warning
57 #endif
58 
59 template <class T, class A>
60 typename A::pointer StandardReallocate(A& a, T *p, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
61 {
62  if (oldSize == newSize)
63  return p;
64 
65  if (preserve)
66  {
67  typename A::pointer newPointer = a.allocate(newSize, NULL);
68  memcpy_s(newPointer, sizeof(T)*newSize, p, sizeof(T)*STDMIN(oldSize, newSize));
69  a.deallocate(p, oldSize);
70  return newPointer;
71  }
72  else
73  {
74  a.deallocate(p, oldSize);
75  return a.allocate(newSize, NULL);
76  }
77 }
78 
79 #if defined(_MSC_VER) && (_MSC_VER < 1300)
80 #pragma warning(pop)
81 #endif
82 
83 template <class T, bool T_Align16 = false>
85 {
86 public:
87  CRYPTOPP_INHERIT_ALLOCATOR_TYPES
88 
89  pointer allocate(size_type n, const void * = NULL)
90  {
91  this->CheckSize(n);
92  if (n == 0)
93  return NULL;
94 
95 #if CRYPTOPP_BOOL_ALIGN16_ENABLED
96  if (T_Align16 && n*sizeof(T) >= 16)
97  return (pointer)AlignedAllocate(n*sizeof(T));
98 #endif
99 
100  return (pointer)UnalignedAllocate(n*sizeof(T));
101  }
102 
103  void deallocate(void *p, size_type n)
104  {
105  SecureWipeArray((pointer)p, n);
106 
107 #if CRYPTOPP_BOOL_ALIGN16_ENABLED
108  if (T_Align16 && n*sizeof(T) >= 16)
109  return AlignedDeallocate(p);
110 #endif
111 
112  UnalignedDeallocate(p);
113  }
114 
115  pointer reallocate(T *p, size_type oldSize, size_type newSize, bool preserve)
116  {
117  return StandardReallocate(*this, p, oldSize, newSize, preserve);
118  }
119 
120  // VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a
121  // template class member called rebind".
122  template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; };
123 #if _MSC_VER >= 1500
125  template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {}
126 #endif
127 };
128 
129 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
130 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
131 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
132 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
133 #if CRYPTOPP_BOOL_X86
134 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>; // for Integer
135 #endif
136 
137 template <class T>
138 class NullAllocator : public AllocatorBase<T>
139 {
140 public:
141  CRYPTOPP_INHERIT_ALLOCATOR_TYPES
142 
143  pointer allocate(size_type n, const void * = NULL)
144  {
145  assert(false);
146  return NULL;
147  }
148 
149  void deallocate(void *p, size_type n)
150  {
151  assert(false);
152  }
153 
154  size_type max_size() const {return 0;}
155 };
156 
157 // This allocator can't be used with standard collections because
158 // they require that all objects of the same allocator type are equivalent.
159 // So this is for use with SecBlock only.
160 template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
162 {
163 public:
164  CRYPTOPP_INHERIT_ALLOCATOR_TYPES
165 
166  FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
167 
168  pointer allocate(size_type n)
169  {
170  assert(IsAlignedOn(m_array, 8));
171 
172  if (n <= S && !m_allocated)
173  {
174  m_allocated = true;
175  return GetAlignedArray();
176  }
177  else
178  return m_fallbackAllocator.allocate(n);
179  }
180 
181  pointer allocate(size_type n, const void *hint)
182  {
183  if (n <= S && !m_allocated)
184  {
185  m_allocated = true;
186  return GetAlignedArray();
187  }
188  else
189  return m_fallbackAllocator.allocate(n, hint);
190  }
191 
192  void deallocate(void *p, size_type n)
193  {
194  if (p == GetAlignedArray())
195  {
196  assert(n <= S);
197  assert(m_allocated);
198  m_allocated = false;
199  SecureWipeArray((pointer)p, n);
200  }
201  else
202  m_fallbackAllocator.deallocate(p, n);
203  }
204 
205  pointer reallocate(pointer p, size_type oldSize, size_type newSize, bool preserve)
206  {
207  if (p == GetAlignedArray() && newSize <= S)
208  {
209  assert(oldSize <= S);
210  if (oldSize > newSize)
211  SecureWipeArray(p+newSize, oldSize-newSize);
212  return p;
213  }
214 
215  pointer newPointer = allocate(newSize, NULL);
216  if (preserve)
217  memcpy(newPointer, p, sizeof(T)*STDMIN(oldSize, newSize));
218  deallocate(p, oldSize);
219  return newPointer;
220  }
221 
222  size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);}
223 
224 private:
225 #ifdef __BORLANDC__
226  T* GetAlignedArray() {return m_array;}
227  T m_array[S];
228 #else
229  T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
230  CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? S+8/sizeof(T) : S];
231 #endif
232  A m_fallbackAllocator;
233  bool m_allocated;
234 };
235 
236 //! a block of memory allocated using A
237 template <class T, class A = AllocatorWithCleanup<T> >
238 class SecBlock
239 {
240 public:
241  typedef typename A::value_type value_type;
242  typedef typename A::pointer iterator;
243  typedef typename A::const_pointer const_iterator;
244  typedef typename A::size_type size_type;
245 
246  explicit SecBlock(size_type size=0)
247  : m_size(size) {m_ptr = m_alloc.allocate(size, NULL);}
248  SecBlock(const SecBlock<T, A> &t)
249  : m_size(t.m_size) {m_ptr = m_alloc.allocate(m_size, NULL); memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));}
250  SecBlock(const T *t, size_type len)
251  : m_size(len)
252  {
253  m_ptr = m_alloc.allocate(len, NULL);
254  if (t == NULL)
255  memset_z(m_ptr, 0, len*sizeof(T));
256  else
257  memcpy(m_ptr, t, len*sizeof(T));
258  }
259 
260  ~SecBlock()
261  {m_alloc.deallocate(m_ptr, m_size);}
262 
263 #ifdef __BORLANDC__
264  operator T *() const
265  {return (T*)m_ptr;}
266 #else
267  operator const void *() const
268  {return m_ptr;}
269  operator void *()
270  {return m_ptr;}
271 
272  operator const T *() const
273  {return m_ptr;}
274  operator T *()
275  {return m_ptr;}
276 #endif
277 
278 // T *operator +(size_type offset)
279 // {return m_ptr+offset;}
280 
281 // const T *operator +(size_type offset) const
282 // {return m_ptr+offset;}
283 
284 // T& operator[](size_type index)
285 // {assert(index >= 0 && index < m_size); return m_ptr[index];}
286 
287 // const T& operator[](size_type index) const
288 // {assert(index >= 0 && index < m_size); return m_ptr[index];}
289 
290  iterator begin()
291  {return m_ptr;}
292  const_iterator begin() const
293  {return m_ptr;}
294  iterator end()
295  {return m_ptr+m_size;}
296  const_iterator end() const
297  {return m_ptr+m_size;}
298 
299  typename A::pointer data() {return m_ptr;}
300  typename A::const_pointer data() const {return m_ptr;}
301 
302  size_type size() const {return m_size;}
303  bool empty() const {return m_size == 0;}
304 
305  byte * BytePtr() {return (byte *)m_ptr;}
306  const byte * BytePtr() const {return (const byte *)m_ptr;}
307  size_type SizeInBytes() const {return m_size*sizeof(T);}
308 
309  //! set contents and size
310  void Assign(const T *t, size_type len)
311  {
312  New(len);
313  memcpy_s(m_ptr, m_size*sizeof(T), t, len*sizeof(T));
314  }
315 
316  //! copy contents and size from another SecBlock
317  void Assign(const SecBlock<T, A> &t)
318  {
319  if (this != &t)
320  {
321  New(t.m_size);
322  memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));
323  }
324  }
325 
326  SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
327  {
328  Assign(t);
329  return *this;
330  }
331 
332  // append to this object
333  SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
334  {
335  size_type oldSize = m_size;
336  Grow(m_size+t.m_size);
337  memcpy_s(m_ptr+oldSize, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
338  return *this;
339  }
340 
341  // append operator
342  SecBlock<T, A> operator+(const SecBlock<T, A> &t)
343  {
344  SecBlock<T, A> result(m_size+t.m_size);
345  memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
346  memcpy_s(result.m_ptr+m_size, t.m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
347  return result;
348  }
349 
350  bool operator==(const SecBlock<T, A> &t) const
351  {
352  return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
353  }
354 
355  bool operator!=(const SecBlock<T, A> &t) const
356  {
357  return !operator==(t);
358  }
359 
360  //! change size, without preserving contents
361  void New(size_type newSize)
362  {
363  m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
364  m_size = newSize;
365  }
366 
367  //! change size and set contents to 0
368  void CleanNew(size_type newSize)
369  {
370  New(newSize);
371  memset_z(m_ptr, 0, m_size*sizeof(T));
372  }
373 
374  //! change size only if newSize > current size. contents are preserved
375  void Grow(size_type newSize)
376  {
377  if (newSize > m_size)
378  {
379  m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
380  m_size = newSize;
381  }
382  }
383 
384  //! change size only if newSize > current size. contents are preserved and additional area is set to 0
385  void CleanGrow(size_type newSize)
386  {
387  if (newSize > m_size)
388  {
389  m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
390  memset(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
391  m_size = newSize;
392  }
393  }
394 
395  //! change size and preserve contents
396  void resize(size_type newSize)
397  {
398  m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
399  m_size = newSize;
400  }
401 
402  //! swap contents and size with another SecBlock
404  {
405  std::swap(m_alloc, b.m_alloc);
406  std::swap(m_size, b.m_size);
407  std::swap(m_ptr, b.m_ptr);
408  }
409 
410 //private:
411  A m_alloc;
412  size_type m_size;
413  T *m_ptr;
414 };
415 
419 
420 //! a SecBlock with fixed size, allocated statically
421 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
422 class FixedSizeSecBlock : public SecBlock<T, A>
423 {
424 public:
425  explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
426 };
427 
428 template <class T, unsigned int S, bool T_Align16 = true>
429 class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
430 {
431 };
432 
433 //! a SecBlock that preallocates size S statically, and uses the heap when this size is exceeded
434 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
435 class SecBlockWithHint : public SecBlock<T, A>
436 {
437 public:
438  explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
439 };
440 
441 template<class T, bool A, class U, bool B>
442 inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);}
443 template<class T, bool A, class U, bool B>
444 inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);}
445 
446 NAMESPACE_END
447 
448 NAMESPACE_BEGIN(std)
449 template <class T, class A>
450 inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
451 {
452  a.swap(b);
453 }
454 
455 #if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
456 // working for STLport 5.1.3 and MSVC 6 SP5
457 template <class _Tp1, class _Tp2>
458 inline CryptoPP::AllocatorWithCleanup<_Tp2>&
459 __stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
460 {
461  return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);
462 }
463 #endif
464 
465 NAMESPACE_END
466 
467 #endif
exception thrown when an invalid argument is detected
Definition: cryptlib.h:144
void swap(SecBlock< T, A > &b)
swap contents and size with another SecBlock
Definition: secblock.h:403
a SecBlock that preallocates size S statically, and uses the heap when this size is exceeded ...
Definition: secblock.h:435
void CleanNew(size_type newSize)
change size and set contents to 0
Definition: secblock.h:368
void resize(size_type newSize)
change size and preserve contents
Definition: secblock.h:396
void CleanGrow(size_type newSize)
change size only if newSize > current size. contents are preserved and additional area is set to 0 ...
Definition: secblock.h:385
void Assign(const SecBlock< T, A > &t)
copy contents and size from another SecBlock
Definition: secblock.h:317
a block of memory allocated using A
Definition: secblock.h:238
void New(size_type newSize)
change size, without preserving contents
Definition: secblock.h:361
void Assign(const T *t, size_type len)
set contents and size
Definition: secblock.h:310
a SecBlock with fixed size, allocated statically
Definition: secblock.h:422
void Grow(size_type newSize)
change size only if newSize > current size. contents are preserved
Definition: secblock.h:375