1 // secblock.h - originally written and placed in the public domain by Wei Dai
2
3 /// \file secblock.h
4 /// \brief Classes and functions for secure memory allocations.
5
6 #ifndef CRYPTOPP_SECBLOCK_H
7 #define CRYPTOPP_SECBLOCK_H
8
9 #include "config.h"
10 #include "allocate.h"
11 #include "misc.h"
12 #include "stdcpp.h"
13
14 #if CRYPTOPP_MSC_VERSION
15 # pragma warning(push)
16 # pragma warning(disable: 4231 4275 4700)
17 # if (CRYPTOPP_MSC_VERSION >= 1400)
18 # pragma warning(disable: 6011 6386 28193)
19 # endif
20 #endif
21
NAMESPACE_BEGIN(CryptoPP)22 NAMESPACE_BEGIN(CryptoPP)
23
24 // ************** secure memory allocation ***************
25
26 /// \brief Base class for all allocators used by SecBlock
27 /// \tparam T the class or type
28 template<class T>
29 class AllocatorBase
30 {
31 public:
32 typedef T value_type;
33 typedef size_t size_type;
34 typedef std::ptrdiff_t difference_type;
35 typedef T * pointer;
36 typedef const T * const_pointer;
37 typedef T & reference;
38 typedef const T & const_reference;
39
40 pointer address(reference r) const {return (&r);}
41 const_pointer address(const_reference r) const {return (&r); }
42 void construct(pointer p, const T& val) {new (p) T(val);}
43 void destroy(pointer p) {CRYPTOPP_UNUSED(p); p->~T();}
44
45 /// \brief Returns the maximum number of elements the allocator can provide
46 /// \details <tt>ELEMS_MAX</tt> is the maximum number of elements the
47 /// <tt>Allocator</tt> can provide. The value of <tt>ELEMS_MAX</tt> is
48 /// <tt>SIZE_MAX/sizeof(T)</tt>. <tt>std::numeric_limits</tt> was avoided
49 /// due to lack of <tt>constexpr</tt>-ness in C++03 and below.
50 /// \note In C++03 and below <tt>ELEMS_MAX</tt> is a static data member of type
51 /// <tt>size_type</tt>. In C++11 and above <tt>ELEMS_MAX</tt> is an <tt>enum</tt>
52 /// inheriting from <tt>size_type</tt>. In both cases <tt>ELEMS_MAX</tt> can be
53 /// used before objects are fully constructed, and it does not suffer the
54 /// limitations of class methods like <tt>max_size</tt>.
55 /// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/346">Issue 346/CVE-2016-9939</A>
56 /// \since Crypto++ 6.0
57 #if defined(CRYPTOPP_DOXYGEN_PROCESSING)
58 static const size_type ELEMS_MAX = ...;
59 #elif defined(_MSC_VER) && (_MSC_VER <= 1400)
60 static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T);
61 #elif defined(CRYPTOPP_CXX11_STRONG_ENUM)
62 enum : size_type {ELEMS_MAX = SIZE_MAX/sizeof(T)};
63 #else
64 static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T);
65 #endif
66
67 /// \brief Returns the maximum number of elements the allocator can provide
68 /// \return the maximum number of elements the allocator can provide
69 /// \details Internally, preprocessor macros are used rather than std::numeric_limits
70 /// because the latter is not a constexpr. Some compilers, like Clang, do not
71 /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear
72 /// to optimize it well in either form.
73 CRYPTOPP_CONSTEXPR size_type max_size() const {return ELEMS_MAX;}
74
75 #if defined(__SUNPRO_CC)
76 // https://github.com/weidai11/cryptopp/issues/770
77 // and https://stackoverflow.com/q/53999461/608639
78 CRYPTOPP_CONSTEXPR size_type max_size(size_type n) const {return SIZE_MAX/n;}
79 #endif
80
81 #if defined(CRYPTOPP_CXX11_VARIADIC_TEMPLATES) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
82
83 /// \brief Constructs a new V using variadic arguments
84 /// \tparam V the type to be forwarded
85 /// \tparam Args the arguments to be forwarded
86 /// \param ptr pointer to type V
87 /// \param args variadic arguments
88 /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES
89 /// is defined. The define is controlled by compiler versions detected in config.h.
90 template<typename V, typename... Args>
91 void construct(V* ptr, Args&&... args) {::new ((void*)ptr) V(std::forward<Args>(args)...);}
92
93 /// \brief Destroys an V constructed with variadic arguments
94 /// \tparam V the type to be forwarded
95 /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES
96 /// is defined. The define is controlled by compiler versions detected in config.h.
97 template<typename V>
98 void destroy(V* ptr) {if (ptr) ptr->~V();}
99
100 #endif
101
102 protected:
103
104 /// \brief Verifies the allocator can satisfy a request based on size
105 /// \param size the size of the allocation, in elements
106 /// \throw InvalidArgument
107 /// \details CheckSize verifies the number of elements requested is valid.
108 /// \details If size is greater than max_size(), then InvalidArgument is thrown.
109 /// The library throws InvalidArgument if the size is too large to satisfy.
110 /// \details Internally, preprocessor macros are used rather than std::numeric_limits
111 /// because the latter is not a constexpr. Some compilers, like Clang, do not
112 /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear
113 /// to optimize it well in either form.
114 /// \details The <tt>sizeof(T) != 1</tt> in the condition attempts to help the
115 /// compiler optimize the check for byte types. Coverity findings for
116 /// CONSTANT_EXPRESSION_RESULT were generated without it. For byte types,
117 /// size never exceeded ELEMS_MAX but the code was not removed.
118 /// \note size is the count of elements, and not the number of bytes
119 static void CheckSize(size_t size)
120 {
121 // Squash MSC C4100 warning for size. Also see commit 42b7c4ea5673.
122 CRYPTOPP_UNUSED(size);
123 // C++ throws std::bad_alloc (C++03) or std::bad_array_new_length (C++11) here.
124 if (sizeof(T) != 1 && size > ELEMS_MAX)
125 throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
126 }
127 };
128
129 #define CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T_type) \
130 typedef typename AllocatorBase<T_type>::value_type value_type;\
131 typedef typename AllocatorBase<T_type>::size_type size_type;\
132 typedef typename AllocatorBase<T_type>::difference_type difference_type;\
133 typedef typename AllocatorBase<T_type>::pointer pointer;\
134 typedef typename AllocatorBase<T_type>::const_pointer const_pointer;\
135 typedef typename AllocatorBase<T_type>::reference reference;\
136 typedef typename AllocatorBase<T_type>::const_reference const_reference;
137
138 /// \brief Reallocation function
139 /// \tparam T the class or type
140 /// \tparam A the class or type's allocator
141 /// \param alloc the allocator
142 /// \param oldPtr the previous allocation
143 /// \param oldSize the size of the previous allocation
144 /// \param newSize the new, requested size
145 /// \param preserve flag that indicates if the old allocation should be preserved
146 /// \note oldSize and newSize are the count of elements, and not the
147 /// number of bytes.
148 template <class T, class A>
StandardReallocate(A & alloc,T * oldPtr,typename A::size_type oldSize,typename A::size_type newSize,bool preserve)149 typename A::pointer StandardReallocate(A& alloc, T *oldPtr, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
150 {
151 // Avoid assert on pointer in reallocate. SecBlock regularly uses NULL
152 // pointers rather returning non-NULL 0-sized pointers.
153 if (oldSize == newSize)
154 return oldPtr;
155
156 if (preserve)
157 {
158 typename A::pointer newPtr = alloc.allocate(newSize, NULLPTR);
159 const typename A::size_type copySize = STDMIN(oldSize, newSize) * sizeof(T);
160
161 if (oldPtr && newPtr)
162 memcpy_s(newPtr, copySize, oldPtr, copySize);
163
164 if (oldPtr)
165 alloc.deallocate(oldPtr, oldSize);
166
167 return newPtr;
168 }
169 else
170 {
171 if (oldPtr)
172 alloc.deallocate(oldPtr, oldSize);
173
174 return alloc.allocate(newSize, NULLPTR);
175 }
176 }
177
178 /// \brief Allocates a block of memory with cleanup
179 /// \tparam T class or type
180 /// \tparam T_Align16 boolean that determines whether allocations should be aligned on a 16-byte boundary
181 /// \details If T_Align16 is true, then AllocatorWithCleanup calls AlignedAllocate()
182 /// for memory allocations. If T_Align16 is false, then AllocatorWithCleanup() calls
183 /// UnalignedAllocate() for memory allocations.
184 /// \details Template parameter T_Align16 is effectively controlled by cryptlib.h and mirrors
185 /// CRYPTOPP_BOOL_ALIGN16. CRYPTOPP_BOOL_ALIGN16 is often used as the template parameter.
186 template <class T, bool T_Align16 = false>
187 class AllocatorWithCleanup : public AllocatorBase<T>
188 {
189 public:
CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)190 CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)
191
192 /// \brief Allocates a block of memory
193 /// \param ptr the size of the allocation
194 /// \param size the size of the allocation, in elements
195 /// \return a memory block
196 /// \throw InvalidArgument
197 /// \details allocate() first checks the size of the request. If it is non-0
198 /// and less than max_size(), then an attempt is made to fulfill the request
199 /// using either AlignedAllocate() or UnalignedAllocate(). AlignedAllocate() is
200 /// used if T_Align16 is true. UnalignedAllocate() used if T_Align16 is false.
201 /// \details This is the C++ *Placement New* operator. ptr is not used, and the
202 /// function asserts in Debug builds if ptr is non-NULL.
203 /// \sa CallNewHandler() for the methods used to recover from a failed
204 /// allocation attempt.
205 /// \note size is the count of elements, and not the number of bytes
206 pointer allocate(size_type size, const void *ptr = NULLPTR)
207 {
208 CRYPTOPP_UNUSED(ptr); CRYPTOPP_ASSERT(ptr == NULLPTR);
209 this->CheckSize(size);
210 if (size == 0)
211 return NULLPTR;
212
213 #if CRYPTOPP_BOOL_ALIGN16
214 if (T_Align16)
215 return reinterpret_cast<pointer>(AlignedAllocate(size*sizeof(T)));
216 #endif
217
218 return reinterpret_cast<pointer>(UnalignedAllocate(size*sizeof(T)));
219 }
220
221 /// \brief Deallocates a block of memory
222 /// \param ptr the pointer for the allocation
223 /// \param size the size of the allocation, in elements
224 /// \details Internally, SecureWipeArray() is called before deallocating the
225 /// memory. Once the memory block is wiped or zeroized, AlignedDeallocate()
226 /// or UnalignedDeallocate() is called.
227 /// \details AlignedDeallocate() is used if T_Align16 is true.
228 /// UnalignedDeallocate() used if T_Align16 is false.
deallocate(void * ptr,size_type size)229 void deallocate(void *ptr, size_type size)
230 {
231 // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL
232 // pointers rather returning non-NULL 0-sized pointers.
233 if (ptr)
234 {
235 SecureWipeArray(reinterpret_cast<pointer>(ptr), size);
236
237 #if CRYPTOPP_BOOL_ALIGN16
238 if (T_Align16)
239 return AlignedDeallocate(ptr);
240 #endif
241
242 UnalignedDeallocate(ptr);
243 }
244 }
245
246 /// \brief Reallocates a block of memory
247 /// \param oldPtr the previous allocation
248 /// \param oldSize the size of the previous allocation
249 /// \param newSize the new, requested size
250 /// \param preserve flag that indicates if the old allocation should be preserved
251 /// \return pointer to the new memory block
252 /// \details Internally, reallocate() calls StandardReallocate().
253 /// \details If preserve is true, then index 0 is used to begin copying the
254 /// old memory block to the new one. If the block grows, then the old array
255 /// is copied in its entirety. If the block shrinks, then only newSize
256 /// elements are copied from the old block to the new one.
257 /// \note oldSize and newSize are the count of elements, and not the
258 /// number of bytes.
reallocate(T * oldPtr,size_type oldSize,size_type newSize,bool preserve)259 pointer reallocate(T *oldPtr, size_type oldSize, size_type newSize, bool preserve)
260 {
261 CRYPTOPP_ASSERT((oldPtr && oldSize) || !(oldPtr || oldSize));
262 return StandardReallocate(*this, oldPtr, oldSize, newSize, preserve);
263 }
264
265 /// \brief Template class member Rebind
266 /// \tparam V bound class or type
267 /// \details Rebind allows a container class to allocate a different type of object
268 /// to store elements. For example, a std::list will allocate std::list_node to
269 /// store elements in the list.
270 /// \details VS.NET STL enforces the policy of "All STL-compliant allocators
271 /// have to provide a template class member called rebind".
272 template <class V> struct rebind { typedef AllocatorWithCleanup<V, T_Align16> other; };
273 #if _MSC_VER >= 1500
AllocatorWithCleanup()274 AllocatorWithCleanup() {}
AllocatorWithCleanup(const AllocatorWithCleanup<V,A> &)275 template <class V, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<V, A> &) {}
276 #endif
277 };
278
279 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
280 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
281 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
282 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
283 #if defined(CRYPTOPP_WORD128_AVAILABLE)
284 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word128, true>; // for Integer
285 #endif
286 #if CRYPTOPP_BOOL_X86
287 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>; // for Integer
288 #endif
289
290 /// \brief NULL allocator
291 /// \tparam T class or type
292 /// \details A NullAllocator is useful for fixed-size, stack based allocations
293 /// (i.e., static arrays used by FixedSizeAllocatorWithCleanup).
294 /// \details A NullAllocator always returns 0 for max_size(), and always returns
295 /// NULL for allocation requests. Though the allocator does not allocate at
296 /// runtime, it does perform a secure wipe or zeroization during cleanup.
297 template <class T>
298 class NullAllocator : public AllocatorBase<T>
299 {
300 public:
301 //LCOV_EXCL_START
CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)302 CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)
303
304 // TODO: should this return NULL or throw bad_alloc? Non-Windows C++ standard
305 // libraries always throw. And late mode Windows throws. Early model Windows
306 // (circa VC++ 6.0) returned NULL.
307 pointer allocate(size_type n, const void* unused = NULLPTR)
308 {
309 CRYPTOPP_UNUSED(n); CRYPTOPP_UNUSED(unused);
310 CRYPTOPP_ASSERT(false); return NULLPTR;
311 }
312
deallocate(void * p,size_type n)313 void deallocate(void *p, size_type n)
314 {
315 CRYPTOPP_UNUSED(p); CRYPTOPP_UNUSED(n);
316 CRYPTOPP_ASSERT(false);
317 }
318
max_size()319 CRYPTOPP_CONSTEXPR size_type max_size() const {return 0;}
320 //LCOV_EXCL_STOP
321 };
322
323 /// \brief Static secure memory block with cleanup
324 /// \tparam T class or type
325 /// \tparam S fixed-size of the stack-based memory block, in elements
326 /// \tparam T_Align16 boolean that determines whether allocations should
327 /// be aligned on a 16-byte boundary
328 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
329 /// based allocation at compile time. The class can grow its memory
330 /// block at runtime if a suitable allocator is available. If size
331 /// grows beyond S and a suitable allocator is available, then the
332 /// statically allocated array is obsoleted.
333 /// \note This allocator can't be used with standard collections because
334 /// they require that all objects of the same allocator type are equivalent.
335 template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
336 class FixedSizeAllocatorWithCleanup : public AllocatorBase<T>
337 {
338 // The body of FixedSizeAllocatorWithCleanup is provided in the two
339 // partial specializations that follow. The two specializations
340 // pivot on the boolean template parameter T_Align16.
341 };
342
343 /// \brief Static secure memory block with cleanup
344 /// \tparam T class or type
345 /// \tparam S fixed-size of the stack-based memory block, in elements
346 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
347 /// based allocation at compile time. The class can grow its memory
348 /// block at runtime if a suitable allocator is available. If size
349 /// grows beyond S and a suitable allocator is available, then the
350 /// statically allocated array is obsoleted.
351 /// \note This allocator can't be used with standard collections because
352 /// they require that all objects of the same allocator type are equivalent.
353 template <class T, size_t S, class A>
354 class FixedSizeAllocatorWithCleanup<T, S, A, true> : public AllocatorBase<T>
355 {
356 public:
CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)357 CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)
358
359 /// \brief Constructs a FixedSizeAllocatorWithCleanup
360 FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
361
362 /// \brief Allocates a block of memory
363 /// \param size the count elements in the memory block
364 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based
365 /// allocation at compile time. If size is less than or equal to
366 /// <tt>S</tt>, then a pointer to the static array is returned.
367 /// \details The class can grow its memory block at runtime if a suitable
368 /// allocator is available. If size grows beyond S and a suitable
369 /// allocator is available, then the statically allocated array is
370 /// obsoleted. If a suitable allocator is not available, as with a
371 /// NullAllocator, then the function returns NULL and a runtime error
372 /// eventually occurs.
373 /// \sa reallocate(), SecBlockWithHint
allocate(size_type size)374 pointer allocate(size_type size)
375 {
376 CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8));
377
378 if (size <= S && !m_allocated)
379 {
380 m_allocated = true;
381 return GetAlignedArray();
382 }
383 else
384 return m_fallbackAllocator.allocate(size);
385 }
386
387 /// \brief Allocates a block of memory
388 /// \param size the count elements in the memory block
389 /// \param hint an unused hint
390 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
391 /// based allocation at compile time. If size is less than or equal to
392 /// S, then a pointer to the static array is returned.
393 /// \details The class can grow its memory block at runtime if a suitable
394 /// allocator is available. If size grows beyond S and a suitable
395 /// allocator is available, then the statically allocated array is
396 /// obsoleted. If a suitable allocator is not available, as with a
397 /// NullAllocator, then the function returns NULL and a runtime error
398 /// eventually occurs.
399 /// \sa reallocate(), SecBlockWithHint
allocate(size_type size,const void * hint)400 pointer allocate(size_type size, const void *hint)
401 {
402 CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8));
403
404 if (size <= S && !m_allocated)
405 {
406 m_allocated = true;
407 return GetAlignedArray();
408 }
409 else
410 return m_fallbackAllocator.allocate(size, hint);
411 }
412
413 /// \brief Deallocates a block of memory
414 /// \param ptr a pointer to the memory block to deallocate
415 /// \param size the count elements in the memory block
416 /// \details The memory block is wiped or zeroized before deallocation.
417 /// If the statically allocated memory block is active, then no
418 /// additional actions are taken after the wipe.
419 /// \details If a dynamic memory block is active, then the pointer and
420 /// size are passed to the allocator for deallocation.
deallocate(void * ptr,size_type size)421 void deallocate(void *ptr, size_type size)
422 {
423 // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL
424 // pointers rather returning non-NULL 0-sized pointers.
425 if (ptr == GetAlignedArray())
426 {
427 // If the m_allocated assert fires then the bit twiddling for
428 // GetAlignedArray() is probably incorrect for the platform.
429 // Be sure to check CRYPTOPP_ALIGN_DATA(8). The platform may
430 // not have a way to declaratively align data to 8.
431 CRYPTOPP_ASSERT(size <= S);
432 CRYPTOPP_ASSERT(m_allocated);
433 m_allocated = false;
434 SecureWipeArray(reinterpret_cast<pointer>(ptr), size);
435 }
436 else
437 {
438 if (ptr)
439 m_fallbackAllocator.deallocate(ptr, size);
440 }
441 }
442
443 /// \brief Reallocates a block of memory
444 /// \param oldPtr the previous allocation
445 /// \param oldSize the size of the previous allocation
446 /// \param newSize the new, requested size
447 /// \param preserve flag that indicates if the old allocation should
448 /// be preserved
449 /// \return pointer to the new memory block
450 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
451 /// based allocation at compile time. If size is less than or equal to
452 /// S, then a pointer to the static array is returned.
453 /// \details The class can grow its memory block at runtime if a suitable
454 /// allocator is available. If size grows beyond S and a suitable
455 /// allocator is available, then the statically allocated array is
456 /// obsoleted. If a suitable allocator is not available, as with a
457 /// NullAllocator, then the function returns NULL and a runtime error
458 /// eventually occurs.
459 /// \note size is the count of elements, and not the number of bytes.
460 /// \sa reallocate(), SecBlockWithHint
reallocate(pointer oldPtr,size_type oldSize,size_type newSize,bool preserve)461 pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve)
462 {
463 if (oldPtr == GetAlignedArray() && newSize <= S)
464 {
465 CRYPTOPP_ASSERT(oldSize <= S);
466 if (oldSize > newSize)
467 SecureWipeArray(oldPtr+newSize, oldSize-newSize);
468 return oldPtr;
469 }
470
471 pointer newPtr = allocate(newSize, NULLPTR);
472 if (preserve && newSize)
473 {
474 const size_type copySize = STDMIN(oldSize, newSize);
475 if (newPtr && oldPtr) // GCC analyzer warning
476 memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize);
477 }
478 deallocate(oldPtr, oldSize);
479 return newPtr;
480 }
481
max_size()482 CRYPTOPP_CONSTEXPR size_type max_size() const
483 {
484 return STDMAX(m_fallbackAllocator.max_size(), S);
485 }
486
487 private:
488
489 #if CRYPTOPP_BOOL_ALIGN16
490
491 // There be demons here... We cannot use CRYPTOPP_ALIGN_DATA(16)
492 // because linkers on 32-bit machines and some 64-bit machines
493 // align the stack to 8-bytes or less, and not 16-bytes as
494 // requested. We can only count on a smaller alignment. All
495 // toolchains tested appear to honor CRYPTOPP_ALIGN_DATA(8). Also
496 // see http://stackoverflow.com/a/1468656/608639.
497 //
498 // The 16-byte alignment is achieved by padding the requested
499 // size with extra elements so we have at least 8-bytes of slack
500 // to work with. Then the array pointer is moved to achieve a
501 // 16-byte alignment.
502 //
503 // The additional 8-bytes introduces a small secondary issue.
504 // The secondary issue is, a large T results in 0 = 8/sizeof(T).
505 // The library is OK but users may hit it. So we need to guard
506 // for a large T, and that is what the enum and PAD achieves.
GetAlignedArray()507 T* GetAlignedArray() {
508
509 // m_array is aligned on 8 byte boundaries due to
510 // CRYPTOPP_ALIGN_DATA(8). If m_array%16 is 0, then the buffer
511 // is 16-byte aligned and nothing needs to be done. if
512 // m_array%16 is 8, then the buffer is not 16-byte aligned and
513 // we need to add 8. 8 has that nice symmetric property.
514 //
515 // If we needed to use CRYPTOPP_ALIGN_DATA(4) due to toolchain
516 // limitations, then the calculation would be slightly more
517 // costly: ptr = m_array + (16 - (m_array % 16)) % 16;
518 CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8));
519 int off = reinterpret_cast<uintptr_t>(m_array) % 16;
520 byte* ptr = reinterpret_cast<byte*>(m_array) + off;
521
522 // Verify the 16-byte alignment. This is the point
523 // of these extra gyrations.
524 CRYPTOPP_ASSERT(IsAlignedOn(ptr, 16));
525 // Verify the lower bound. This is Issue 982/988.
526 CRYPTOPP_ASSERT(
527 reinterpret_cast<uintptr_t>(ptr) >=
528 reinterpret_cast<uintptr_t>(m_array)
529 );
530 // Verify the upper bound. Allocated array with
531 // pad is large enough.
532 CRYPTOPP_ASSERT(
533 reinterpret_cast<uintptr_t>(ptr+S*sizeof(T)) <=
534 reinterpret_cast<uintptr_t>(m_array+(S+PAD))
535 );
536
537 // void* to silence Clang warnings
538 return reinterpret_cast<T*>(
539 static_cast<void*>(ptr)
540 );
541 }
542
543 // PAD is elements, not bytes, and rounded up to ensure no overflow.
544 enum { Q = sizeof(T), PAD = (Q >= 8) ? 1 : (Q >= 4) ? 2 : (Q >= 2) ? 4 : 8 };
545 // enum { Q = sizeof(T), PAD = (Q >= 16) ? 1 : (Q >= 8) ? 2 : (Q >= 4) ? 4 : (Q >= 2) ? 8 : 16 };
546 CRYPTOPP_ALIGN_DATA(8) T m_array[S+PAD];
547
548 #else
549
550 // CRYPTOPP_BOOL_ALIGN16 is 0. If we are here then the user
551 // probably compiled with CRYPTOPP_DISABLE_ASM. Normally we
552 // would use the natural alignment of T. The problem we are
553 // having is, some toolchains are changing the boundary for
554 // 64-bit arrays. 64-bit elements require 8-byte alignment,
555 // but the toolchain is laying the array out on a 4 byte
556 // boundary. See GH #992 for mystery alignment,
557 // https://github.com/weidai11/cryptopp/issues/992
558 T* GetAlignedArray() {return m_array;}
559 CRYPTOPP_ALIGN_DATA(8) T m_array[S];
560
561 #endif
562
563 A m_fallbackAllocator;
564 bool m_allocated;
565 };
566
567 /// \brief Static secure memory block with cleanup
568 /// \tparam T class or type
569 /// \tparam S fixed-size of the stack-based memory block, in elements
570 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
571 /// based allocation at compile time. The class can grow its memory
572 /// block at runtime if a suitable allocator is available. If size
573 /// grows beyond S and a suitable allocator is available, then the
574 /// statically allocated array is obsoleted.
575 /// \note This allocator can't be used with standard collections because
576 /// they require that all objects of the same allocator type are equivalent.
577 template <class T, size_t S, class A>
578 class FixedSizeAllocatorWithCleanup<T, S, A, false> : public AllocatorBase<T>
579 {
580 public:
CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)581 CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)
582
583 /// \brief Constructs a FixedSizeAllocatorWithCleanup
584 FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
585
586 /// \brief Allocates a block of memory
587 /// \param size the count elements in the memory block
588 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based
589 /// allocation at compile time. If size is less than or equal to
590 /// <tt>S</tt>, then a pointer to the static array is returned.
591 /// \details The class can grow its memory block at runtime if a suitable
592 /// allocator is available. If size grows beyond S and a suitable
593 /// allocator is available, then the statically allocated array is
594 /// obsoleted. If a suitable allocator is not available, as with a
595 /// NullAllocator, then the function returns NULL and a runtime error
596 /// eventually occurs.
597 /// \sa reallocate(), SecBlockWithHint
allocate(size_type size)598 pointer allocate(size_type size)
599 {
600 CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8));
601
602 if (size <= S && !m_allocated)
603 {
604 m_allocated = true;
605 return GetAlignedArray();
606 }
607 else
608 return m_fallbackAllocator.allocate(size);
609 }
610
611 /// \brief Allocates a block of memory
612 /// \param size the count elements in the memory block
613 /// \param hint an unused hint
614 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
615 /// based allocation at compile time. If size is less than or equal to
616 /// S, then a pointer to the static array is returned.
617 /// \details The class can grow its memory block at runtime if a suitable
618 /// allocator is available. If size grows beyond S and a suitable
619 /// allocator is available, then the statically allocated array is
620 /// obsoleted. If a suitable allocator is not available, as with a
621 /// NullAllocator, then the function returns NULL and a runtime error
622 /// eventually occurs.
623 /// \sa reallocate(), SecBlockWithHint
allocate(size_type size,const void * hint)624 pointer allocate(size_type size, const void *hint)
625 {
626 if (size <= S && !m_allocated)
627 {
628 m_allocated = true;
629 return GetAlignedArray();
630 }
631 else
632 return m_fallbackAllocator.allocate(size, hint);
633 }
634
635 /// \brief Deallocates a block of memory
636 /// \param ptr a pointer to the memory block to deallocate
637 /// \param size the count elements in the memory block
638 /// \details The memory block is wiped or zeroized before deallocation.
639 /// If the statically allocated memory block is active, then no
640 /// additional actions are taken after the wipe.
641 /// \details If a dynamic memory block is active, then the pointer and
642 /// size are passed to the allocator for deallocation.
deallocate(void * ptr,size_type size)643 void deallocate(void *ptr, size_type size)
644 {
645 // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL
646 // pointers rather returning non-NULL 0-sized pointers.
647 if (ptr == GetAlignedArray())
648 {
649 // If the m_allocated assert fires then
650 // something overwrote the flag.
651 CRYPTOPP_ASSERT(size <= S);
652 CRYPTOPP_ASSERT(m_allocated);
653 m_allocated = false;
654 SecureWipeArray((pointer)ptr, size);
655 }
656 else
657 {
658 if (ptr)
659 m_fallbackAllocator.deallocate(ptr, size);
660 m_allocated = false;
661 }
662 }
663
664 /// \brief Reallocates a block of memory
665 /// \param oldPtr the previous allocation
666 /// \param oldSize the size of the previous allocation
667 /// \param newSize the new, requested size
668 /// \param preserve flag that indicates if the old allocation should
669 /// be preserved
670 /// \return pointer to the new memory block
671 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
672 /// based allocation at compile time. If size is less than or equal to
673 /// S, then a pointer to the static array is returned.
674 /// \details The class can grow its memory block at runtime if a suitable
675 /// allocator is available. If size grows beyond S and a suitable
676 /// allocator is available, then the statically allocated array is
677 /// obsoleted. If a suitable allocator is not available, as with a
678 /// NullAllocator, then the function returns NULL and a runtime error
679 /// eventually occurs.
680 /// \note size is the count of elements, and not the number of bytes.
681 /// \sa reallocate(), SecBlockWithHint
reallocate(pointer oldPtr,size_type oldSize,size_type newSize,bool preserve)682 pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve)
683 {
684 if (oldPtr == GetAlignedArray() && newSize <= S)
685 {
686 CRYPTOPP_ASSERT(oldSize <= S);
687 if (oldSize > newSize)
688 SecureWipeArray(oldPtr+newSize, oldSize-newSize);
689 return oldPtr;
690 }
691
692 pointer newPtr = allocate(newSize, NULLPTR);
693 if (preserve && newSize)
694 {
695 const size_type copySize = STDMIN(oldSize, newSize);
696 if (newPtr && oldPtr) // GCC analyzer warning
697 memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize);
698 }
699 deallocate(oldPtr, oldSize);
700 return newPtr;
701 }
702
max_size()703 CRYPTOPP_CONSTEXPR size_type max_size() const
704 {
705 return STDMAX(m_fallbackAllocator.max_size(), S);
706 }
707
708 private:
709
710 // T_Align16 is false. Normally we would use the natural
711 // alignment of T. The problem we are having is, some toolchains
712 // are changing the boundary for 64-bit arrays. 64-bit elements
713 // require 8-byte alignment, but the toolchain is laying the array
714 // out on a 4 byte boundary. See GH #992 for mystery alignment,
715 // https://github.com/weidai11/cryptopp/issues/992
GetAlignedArray()716 T* GetAlignedArray() {return m_array;}
717 CRYPTOPP_ALIGN_DATA(8) T m_array[S];
718
719 A m_fallbackAllocator;
720 bool m_allocated;
721 };
722
723 /// \brief Secure memory block with allocator and cleanup
724 /// \tparam T a class or type
725 /// \tparam A AllocatorWithCleanup derived class for allocation and cleanup
726 template <class T, class A = AllocatorWithCleanup<T> >
727 class SecBlock
728 {
729 public:
730 typedef typename A::value_type value_type;
731 typedef typename A::pointer iterator;
732 typedef typename A::const_pointer const_iterator;
733 typedef typename A::size_type size_type;
734
735 /// \brief Returns the maximum number of elements the block can hold
736 /// \details <tt>ELEMS_MAX</tt> is the maximum number of elements the
737 /// <tt>SecBlock</tt> can hold. The value of <tt>ELEMS_MAX</tt> is
738 /// <tt>SIZE_MAX/sizeof(T)</tt>. <tt>std::numeric_limits</tt> was avoided
739 /// due to lack of <tt>constexpr</tt>-ness in C++03 and below.
740 /// \note In C++03 and below <tt>ELEMS_MAX</tt> is a static data member of type
741 /// <tt>size_type</tt>. In C++11 and above <tt>ELEMS_MAX</tt> is an <tt>enum</tt>
742 /// inheriting from <tt>size_type</tt>. In both cases <tt>ELEMS_MAX</tt> can be
743 /// used before objects are fully constructed, and it does not suffer the
744 /// limitations of class methods like <tt>max_size</tt>.
745 /// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/346">Issue 346/CVE-2016-9939</A>
746 /// \since Crypto++ 6.0
747 #if defined(CRYPTOPP_DOXYGEN_PROCESSING)
748 static const size_type ELEMS_MAX = ...;
749 #elif defined(_MSC_VER) && (_MSC_VER <= 1400)
750 static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T);
751 #elif defined(CRYPTOPP_CXX11_STRONG_ENUM)
752 enum : size_type {ELEMS_MAX = A::ELEMS_MAX};
753 #else
754 static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T);
755 #endif
756
757 /// \brief Construct a SecBlock with space for size elements.
758 /// \param size the size of the allocation, in elements
759 /// \throw std::bad_alloc
760 /// \details The elements are not initialized.
761 /// \note size is the count of elements, and not the number of bytes
762 explicit SecBlock(size_type size=0)
m_mark(ELEMS_MAX)763 : m_mark(ELEMS_MAX), m_size(size), m_ptr(m_alloc.allocate(size, NULLPTR)) { }
764
765 /// \brief Copy construct a SecBlock from another SecBlock
766 /// \param t the other SecBlock
767 /// \throw std::bad_alloc
SecBlock(const SecBlock<T,A> & t)768 SecBlock(const SecBlock<T, A> &t)
769 : m_mark(t.m_mark), m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULLPTR)) {
770 CRYPTOPP_ASSERT((!t.m_ptr && !m_size) || (t.m_ptr && m_size));
771 if (m_ptr && t.m_ptr)
772 memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
773 }
774
775 /// \brief Construct a SecBlock from an array of elements.
776 /// \param ptr a pointer to an array of T
777 /// \param len the number of elements in the memory block
778 /// \throw std::bad_alloc
779 /// \details If <tt>ptr!=NULL</tt> and <tt>len!=0</tt>, then the block is initialized from the pointer
780 /// <tt>ptr</tt>. If <tt>ptr==NULL</tt> and <tt>len!=0</tt>, then the block is initialized to 0.
781 /// Otherwise, the block is empty and not initialized.
782 /// \note size is the count of elements, and not the number of bytes
SecBlock(const T * ptr,size_type len)783 SecBlock(const T *ptr, size_type len)
784 : m_mark(ELEMS_MAX), m_size(len), m_ptr(m_alloc.allocate(len, NULLPTR)) {
785 CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size));
786 if (m_ptr && ptr)
787 memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));
788 else if (m_ptr && m_size)
789 memset(m_ptr, 0, m_size*sizeof(T));
790 }
791
~SecBlock()792 ~SecBlock()
793 {m_alloc.deallocate(m_ptr, STDMIN(m_size, m_mark));}
794
795 #ifdef __BORLANDC__
796 /// \brief Cast operator
797 /// \return block pointer cast to non-const <tt>T *</tt>
798 operator T *() const
799 {return (T*)m_ptr;}
800 #else
801 /// \brief Cast operator
802 /// \return block pointer cast to <tt>const void *</tt>
803 operator const void *() const
804 {return m_ptr;}
805
806 /// \brief Cast operator
807 /// \return block pointer cast to non-const <tt>void *</tt>
808 operator void *()
809 {return m_ptr;}
810
811 /// \brief Cast operator
812 /// \return block pointer cast to <tt>const T *</tt>
813 operator const T *() const
814 {return m_ptr;}
815
816 /// \brief Cast operator
817 /// \return block pointer cast to non-const <tt>T *</tt>
818 operator T *()
819 {return m_ptr;}
820 #endif
821
822 /// \brief Provides an iterator pointing to the first element in the memory block
823 /// \return iterator pointing to the first element in the memory block
begin()824 iterator begin()
825 {return m_ptr;}
826 /// \brief Provides a constant iterator pointing to the first element in the memory block
827 /// \return constant iterator pointing to the first element in the memory block
begin()828 const_iterator begin() const
829 {return m_ptr;}
830 /// \brief Provides an iterator pointing beyond the last element in the memory block
831 /// \return iterator pointing beyond the last element in the memory block
end()832 iterator end()
833 {return m_ptr+m_size;}
834 /// \brief Provides a constant iterator pointing beyond the last element in the memory block
835 /// \return constant iterator pointing beyond the last element in the memory block
end()836 const_iterator end() const
837 {return m_ptr+m_size;}
838
839 /// \brief Provides a pointer to the first element in the memory block
840 /// \return pointer to the first element in the memory block
data()841 typename A::pointer data() {return m_ptr;}
842 /// \brief Provides a pointer to the first element in the memory block
843 /// \return constant pointer to the first element in the memory block
data()844 typename A::const_pointer data() const {return m_ptr;}
845
846 /// \brief Provides the count of elements in the SecBlock
847 /// \return number of elements in the memory block
848 /// \note the return value is the count of elements, and not the number of bytes
size()849 size_type size() const {return m_size;}
850 /// \brief Determines if the SecBlock is empty
851 /// \return true if number of elements in the memory block is 0, false otherwise
empty()852 bool empty() const {return m_size == 0;}
853
854 /// \brief Provides a byte pointer to the first element in the memory block
855 /// \return byte pointer to the first element in the memory block
BytePtr()856 byte * BytePtr() {return (byte *)m_ptr;}
857 /// \brief Return a byte pointer to the first element in the memory block
858 /// \return constant byte pointer to the first element in the memory block
BytePtr()859 const byte * BytePtr() const {return (const byte *)m_ptr;}
860 /// \brief Provides the number of bytes in the SecBlock
861 /// \return the number of bytes in the memory block
862 /// \note the return value is the number of bytes, and not count of elements.
SizeInBytes()863 size_type SizeInBytes() const {return m_size*sizeof(T);}
864
865 /// \brief Sets the number of elements to zeroize
866 /// \param count the number of elements
867 /// \details SetMark is a remediation for Issue 346/CVE-2016-9939 while
868 /// preserving the streaming interface. The <tt>count</tt> controls the number of
869 /// elements zeroized, which can be less than <tt>size</tt> or 0.
870 /// \details An internal variable, <tt>m_mark</tt>, is initialized to the maximum number
871 /// of elements. The maximum number of elements is <tt>ELEMS_MAX</tt>. Deallocation
872 /// triggers a zeroization, and the number of elements zeroized is
873 /// <tt>STDMIN(m_size, m_mark)</tt>. After zeroization, the memory is returned to the
874 /// system.
875 /// \details The ASN.1 decoder uses SetMark() to set the element count to 0
876 /// before throwing an exception. In this case, the attacker provides a large
877 /// BER encoded length (say 64MB) but only a small number of content octets
878 /// (say 16). If the allocator zeroized all 64MB, then a transient DoS could
879 /// occur as CPU cycles are spent zeroizing unintialized memory.
880 /// \details Generally speaking, any operation which changes the size of the SecBlock
881 /// results in the mark being reset to <tt>ELEMS_MAX</tt>. In particular, if Assign(),
882 /// New(), Grow(), CleanNew(), CleanGrow() are called, then the count is reset to
883 /// <tt>ELEMS_MAX</tt>. The list is not exhaustive.
884 /// \since Crypto++ 6.0
885 /// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/346">Issue 346/CVE-2016-9939</A>
SetMark(size_t count)886 void SetMark(size_t count) {m_mark = count;}
887
888 /// \brief Set contents and size from an array
889 /// \param ptr a pointer to an array of T
890 /// \param len the number of elements in the memory block
891 /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0.
892 /// Assign() resets the element count after the previous block is zeroized.
Assign(const T * ptr,size_type len)893 void Assign(const T *ptr, size_type len)
894 {
895 New(len);
896 if (m_ptr && ptr) // GCC analyzer warning
897 memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));
898 m_mark = ELEMS_MAX;
899 }
900
901 /// \brief Set contents from a value
902 /// \param count the number of values to copy
903 /// \param value the value, repeated count times
904 /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0.
905 /// Assign() resets the element count after the previous block is zeroized.
Assign(size_type count,T value)906 void Assign(size_type count, T value)
907 {
908 New(count);
909 for (size_t i=0; i<count; ++i)
910 m_ptr[i] = value;
911
912 m_mark = ELEMS_MAX;
913 }
914
915 /// \brief Copy contents from another SecBlock
916 /// \param t the other SecBlock
917 /// \details Assign checks for self assignment.
918 /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0.
919 /// If an assignment occurs, then Assign() resets the element count after the previous block
920 /// is zeroized.
Assign(const SecBlock<T,A> & t)921 void Assign(const SecBlock<T, A> &t)
922 {
923 if (this != &t)
924 {
925 New(t.m_size);
926 if (m_ptr && t.m_ptr) // GCC analyzer warning
927 memcpy_s(m_ptr, m_size*sizeof(T), t, t.m_size*sizeof(T));
928 }
929 m_mark = ELEMS_MAX;
930 }
931
932 /// \brief Assign contents from another SecBlock
933 /// \param t the other SecBlock
934 /// \details Internally, operator=() calls Assign().
935 /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0.
936 /// If an assignment occurs, then Assign() resets the element count after the previous block
937 /// is zeroized.
938 SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
939 {
940 // Assign guards for self-assignment
941 Assign(t);
942 return *this;
943 }
944
945 /// \brief Append contents from another SecBlock
946 /// \param t the other SecBlock
947 /// \details Internally, this SecBlock calls Grow and then appends t.
948 SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
949 {
950 CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size));
951 if (t.m_size)
952 {
953 const size_type oldSize = m_size;
954 if (this != &t) // s += t
955 {
956 Grow(m_size+t.m_size);
957 if (m_ptr && t.m_ptr) // GCC analyzer warning
958 memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
959 }
960 else // t += t
961 {
962 Grow(m_size*2);
963 if (m_ptr && t.m_ptr) // GCC analyzer warning
964 memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), m_ptr, oldSize*sizeof(T));
965 }
966 }
967 m_mark = ELEMS_MAX;
968 return *this;
969 }
970
971 /// \brief Construct a SecBlock from this and another SecBlock
972 /// \param t the other SecBlock
973 /// \return a newly constructed SecBlock that is a conacentation of this and t
974 /// \details Internally, a new SecBlock is created from this and a concatenation of t.
975 SecBlock<T, A> operator+(const SecBlock<T, A> &t)
976 {
977 CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size));
978 CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size));
979 if(!t.m_size) return SecBlock(*this);
980
981 SecBlock<T, A> result(m_size+t.m_size);
982 if (m_size)
983 memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
984 if (result.m_ptr && t.m_ptr) // GCC analyzer warning
985 memcpy_s(result.m_ptr+m_size, (result.m_size-m_size)*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
986 return result;
987 }
988
989 /// \brief Bitwise compare two SecBlocks
990 /// \param t the other SecBlock
991 /// \return true if the size and bits are equal, false otherwise
992 /// \details Uses a constant time compare if the arrays are equal size. The constant time
993 /// compare is VerifyBufsEqual() found in misc.h.
994 /// \sa operator!=()
995 bool operator==(const SecBlock<T, A> &t) const
996 {
997 return m_size == t.m_size && VerifyBufsEqual(
998 reinterpret_cast<const byte*>(m_ptr),
999 reinterpret_cast<const byte*>(t.m_ptr), m_size*sizeof(T));
1000 }
1001
1002 /// \brief Bitwise compare two SecBlocks
1003 /// \param t the other SecBlock
1004 /// \return true if the size and bits are equal, false otherwise
1005 /// \details Uses a constant time compare if the arrays are equal size. The constant time
1006 /// compare is VerifyBufsEqual() found in misc.h.
1007 /// \details Internally, operator!=() returns the inverse of operator==().
1008 /// \sa operator==()
1009 bool operator!=(const SecBlock<T, A> &t) const
1010 {
1011 return !operator==(t);
1012 }
1013
1014 /// \brief Change size without preserving contents
1015 /// \param newSize the new size of the memory block
1016 /// \details Old content is not preserved. If the memory block is reduced in size,
1017 /// then the reclaimed memory is set to 0. If the memory block grows in size, then
1018 /// the new memory is not initialized. New() resets the element count after the
1019 /// previous block is zeroized.
1020 /// \details Internally, this SecBlock calls reallocate().
1021 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
New(size_type newSize)1022 void New(size_type newSize)
1023 {
1024 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
1025 m_size = newSize;
1026 m_mark = ELEMS_MAX;
1027 }
1028
1029 /// \brief Change size without preserving contents
1030 /// \param newSize the new size of the memory block
1031 /// \details Old content is not preserved. If the memory block is reduced in size,
1032 /// then the reclaimed content is set to 0. If the memory block grows in size, then
1033 /// the new memory is initialized to 0. CleanNew() resets the element count after the
1034 /// previous block is zeroized.
1035 /// \details Internally, this SecBlock calls New().
1036 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
CleanNew(size_type newSize)1037 void CleanNew(size_type newSize)
1038 {
1039 New(newSize);
1040 if (m_ptr) {memset_z(m_ptr, 0, m_size*sizeof(T));}
1041 m_mark = ELEMS_MAX;
1042 }
1043
1044 /// \brief Change size and preserve contents
1045 /// \param newSize the new size of the memory block
1046 /// \details Old content is preserved. New content is not initialized.
1047 /// \details Internally, this SecBlock calls reallocate() when size must increase. If the
1048 /// size does not increase, then Grow() does not take action. If the size must
1049 /// change, then use resize(). Grow() resets the element count after the
1050 /// previous block is zeroized.
1051 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
Grow(size_type newSize)1052 void Grow(size_type newSize)
1053 {
1054 if (newSize > m_size)
1055 {
1056 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
1057 m_size = newSize;
1058 }
1059 m_mark = ELEMS_MAX;
1060 }
1061
1062 /// \brief Change size and preserve contents
1063 /// \param newSize the new size of the memory block
1064 /// \details Old content is preserved. New content is initialized to 0.
1065 /// \details Internally, this SecBlock calls reallocate() when size must increase. If the
1066 /// size does not increase, then CleanGrow() does not take action. If the size must
1067 /// change, then use resize(). CleanGrow() resets the element count after the
1068 /// previous block is zeroized.
1069 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
CleanGrow(size_type newSize)1070 void CleanGrow(size_type newSize)
1071 {
1072 if (newSize > m_size)
1073 {
1074 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
1075 memset_z(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
1076 m_size = newSize;
1077 }
1078 m_mark = ELEMS_MAX;
1079 }
1080
1081 /// \brief Change size and preserve contents
1082 /// \param newSize the new size of the memory block
1083 /// \details Old content is preserved. If the memory block grows in size, then
1084 /// new memory is not initialized. resize() resets the element count after
1085 /// the previous block is zeroized.
1086 /// \details Internally, this SecBlock calls reallocate().
1087 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
resize(size_type newSize)1088 void resize(size_type newSize)
1089 {
1090 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
1091 m_size = newSize;
1092 m_mark = ELEMS_MAX;
1093 }
1094
1095 /// \brief Swap contents with another SecBlock
1096 /// \param b the other SecBlock
1097 /// \details Internally, std::swap() is called on m_alloc, m_size and m_ptr.
swap(SecBlock<T,A> & b)1098 void swap(SecBlock<T, A> &b)
1099 {
1100 // Swap must occur on the allocator in case its FixedSize that spilled into the heap.
1101 std::swap(m_alloc, b.m_alloc);
1102 std::swap(m_mark, b.m_mark);
1103 std::swap(m_size, b.m_size);
1104 std::swap(m_ptr, b.m_ptr);
1105 }
1106
1107 protected:
1108 A m_alloc;
1109 size_type m_mark, m_size;
1110 T *m_ptr;
1111 };
1112
1113 #ifdef CRYPTOPP_DOXYGEN_PROCESSING
1114 /// \brief \ref SecBlock "SecBlock<byte>" typedef.
1115 class SecByteBlock : public SecBlock<byte> {};
1116 /// \brief \ref SecBlock "SecBlock<word>" typedef.
1117 class SecWordBlock : public SecBlock<word> {};
1118 /// \brief SecBlock using \ref AllocatorWithCleanup "AllocatorWithCleanup<byte, true>" typedef
1119 class AlignedSecByteBlock : public SecBlock<byte, AllocatorWithCleanup<byte, true> > {};
1120 #else
1121 typedef SecBlock<byte> SecByteBlock;
1122 typedef SecBlock<word> SecWordBlock;
1123 typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
1124 #endif
1125
1126 // No need for move semantics on derived class *if* the class does not add any
1127 // data members; see http://stackoverflow.com/q/31755703, and Rule of {0|3|5}.
1128
1129 /// \brief Fixed size stack-based SecBlock
1130 /// \tparam T class or type
1131 /// \tparam S fixed-size of the stack-based memory block, in elements
1132 /// \tparam A AllocatorBase derived class for allocation and cleanup
1133 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
1134 class FixedSizeSecBlock : public SecBlock<T, A>
1135 {
1136 public:
1137 /// \brief Construct a FixedSizeSecBlock
FixedSizeSecBlock()1138 explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
1139 };
1140
1141 /// \brief Fixed size stack-based SecBlock with 16-byte alignment
1142 /// \tparam T class or type
1143 /// \tparam S fixed-size of the stack-based memory block, in elements
1144 /// \tparam T_Align16 boolean that determines whether allocations should be aligned on a 16-byte boundary
1145 template <class T, unsigned int S, bool T_Align16 = true>
1146 class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
1147 {
1148 };
1149
1150 /// \brief Stack-based SecBlock that grows into the heap
1151 /// \tparam T class or type
1152 /// \tparam S fixed-size of the stack-based memory block, in elements
1153 /// \tparam A AllocatorBase derived class for allocation and cleanup
1154 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
1155 class SecBlockWithHint : public SecBlock<T, A>
1156 {
1157 public:
1158 /// construct a SecBlockWithHint with a count of elements
SecBlockWithHint(size_t size)1159 explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
1160 };
1161
1162 template<class T, bool A, class V, bool B>
1163 inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<V, B>&) {return (true);}
1164 template<class T, bool A, class V, bool B>
1165 inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<V, B>&) {return (false);}
1166
1167 NAMESPACE_END
1168
NAMESPACE_BEGIN(std)1169 NAMESPACE_BEGIN(std)
1170
1171 /// \brief Swap two SecBlocks
1172 /// \tparam T class or type
1173 /// \tparam A AllocatorBase derived class for allocation and cleanup
1174 /// \param a the first SecBlock
1175 /// \param b the second SecBlock
1176 template <class T, class A>
1177 inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
1178 {
1179 a.swap(b);
1180 }
1181
1182 #if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
1183 // working for STLport 5.1.3 and MSVC 6 SP5
1184 template <class _Tp1, class _Tp2>
1185 inline CryptoPP::AllocatorWithCleanup<_Tp2>&
__stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1> & __a,const _Tp2 *)1186 __stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
1187 {
1188 return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);
1189 }
1190 #endif
1191
1192 NAMESPACE_END
1193
1194 #if CRYPTOPP_MSC_VERSION
1195 # pragma warning(pop)
1196 #endif
1197
1198 #endif
1199