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