Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

804 lines
31 KiB

  1. // secblock.h - written and placed in the public domain by Wei Dai
  2. //! \file secblock.h
  3. //! \brief Classes and functions for secure memory allocations.
  4. #ifndef CRYPTOPP_SECBLOCK_H
  5. #define CRYPTOPP_SECBLOCK_H
  6. #include "config.h"
  7. #include "stdcpp.h"
  8. #include "misc.h"
  9. #if CRYPTOPP_MSC_VERSION
  10. # pragma warning(push)
  11. # pragma warning(disable: 4700)
  12. # if (CRYPTOPP_MSC_VERSION >= 1400)
  13. # pragma warning(disable: 6386)
  14. # endif
  15. #endif
  16. NAMESPACE_BEGIN(CryptoPP)
  17. // ************** secure memory allocation ***************
  18. //! \class AllocatorBase
  19. //! \brief Base class for all allocators used by SecBlock
  20. //! \tparam T the class or type
  21. template<class T>
  22. class AllocatorBase
  23. {
  24. public:
  25. typedef T value_type;
  26. typedef size_t size_type;
  27. #ifdef CRYPTOPP_MSVCRT6
  28. typedef ptrdiff_t difference_type;
  29. #else
  30. typedef std::ptrdiff_t difference_type;
  31. #endif
  32. typedef T * pointer;
  33. typedef const T * const_pointer;
  34. typedef T & reference;
  35. typedef const T & const_reference;
  36. pointer address(reference r) const {return (&r);}
  37. const_pointer address(const_reference r) const {return (&r); }
  38. void construct(pointer p, const T& val) {new (p) T(val);}
  39. void destroy(pointer p) {CRYPTOPP_UNUSED(p); p->~T();}
  40. //! \brief Returns the maximum number of elements the allocator can provide
  41. //! \returns the maximum number of elements the allocator can provide
  42. //! \details Internally, preprocessor macros are used rather than std::numeric_limits
  43. //! because the latter is \a not a \a constexpr. Some compilers, like Clang, do not
  44. //! optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear
  45. //! to optimize it well in either form.
  46. size_type max_size() const {return (SIZE_MAX/sizeof(T));}
  47. #if defined(CRYPTOPP_CXX11_VARIADIC_TEMPLATES) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
  48. //! \brief Constructs a new U using variadic arguments
  49. //! \tparam U the type to be forwarded
  50. //! \tparam Args the arguments to be forwarded
  51. //! \param ptr pointer to type U
  52. //! \param args variadic arguments
  53. //! \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES
  54. //! is defined. The define is controlled by compiler versions detected in config.h.
  55. template<typename U, typename... Args>
  56. void construct(U* ptr, Args&&... args) {::new ((void*)ptr) U(std::forward<Args>(args)...);}
  57. //! \brief Destroys an U constructed with variadic arguments
  58. //! \tparam U the type to be forwarded
  59. //! \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES
  60. //! is defined. The define is controlled by compiler versions detected in config.h.
  61. template<typename U>
  62. void destroy(U* ptr) {if(ptr) ptr->~U();}
  63. #endif
  64. protected:
  65. //! \brief Verifies the allocator can satisfy a request based on size
  66. //! \param size the number of elements
  67. //! \throws InvalidArgument
  68. //! \details CheckSize verifies the number of elements requested is valid.
  69. //! \details If size is greater than max_size(), then InvalidArgument is thrown.
  70. //! The library throws InvalidArgument if the size is too large to satisfy.
  71. //! \details Internally, preprocessor macros are used rather than std::numeric_limits
  72. //! because the latter is \a not a \a constexpr. Some compilers, like Clang, do not
  73. //! optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear
  74. //! to optimize it well in either form.
  75. //! \note size is the count of elements, and not the number of bytes
  76. static void CheckSize(size_t size)
  77. {
  78. // C++ throws std::bad_alloc (C++03) or std::bad_array_new_length (C++11) here.
  79. if (size > (SIZE_MAX/sizeof(T)))
  80. throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
  81. }
  82. };
  83. #define CRYPTOPP_INHERIT_ALLOCATOR_TYPES \
  84. typedef typename AllocatorBase<T>::value_type value_type;\
  85. typedef typename AllocatorBase<T>::size_type size_type;\
  86. typedef typename AllocatorBase<T>::difference_type difference_type;\
  87. typedef typename AllocatorBase<T>::pointer pointer;\
  88. typedef typename AllocatorBase<T>::const_pointer const_pointer;\
  89. typedef typename AllocatorBase<T>::reference reference;\
  90. typedef typename AllocatorBase<T>::const_reference const_reference;
  91. //! \brief Reallocation function
  92. //! \tparam T the class or type
  93. //! \tparam A the class or type's allocator
  94. //! \param alloc the allocator
  95. //! \param oldPtr the previous allocation
  96. //! \param oldSize the size of the previous allocation
  97. //! \param newSize the new, requested size
  98. //! \param preserve flag that indicates if the old allocation should be preserved
  99. //! \note oldSize and newSize are the count of elements, and not the
  100. //! number of bytes.
  101. template <class T, class A>
  102. typename A::pointer StandardReallocate(A& alloc, T *oldPtr, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
  103. {
  104. assert((oldPtr && oldSize) || !(oldPtr || oldSize));
  105. if (oldSize == newSize)
  106. return oldPtr;
  107. if (preserve)
  108. {
  109. typename A::pointer newPointer = alloc.allocate(newSize, NULL);
  110. const size_t copySize = STDMIN(oldSize, newSize) * sizeof(T);
  111. if (oldPtr && newPointer) {memcpy_s(newPointer, copySize, oldPtr, copySize);}
  112. alloc.deallocate(oldPtr, oldSize);
  113. return newPointer;
  114. }
  115. else
  116. {
  117. alloc.deallocate(oldPtr, oldSize);
  118. return alloc.allocate(newSize, NULL);
  119. }
  120. }
  121. //! \class AllocatorWithCleanup
  122. //! \brief Allocates a block of memory with cleanup
  123. //! \tparam T class or type
  124. //! \tparam T_Align16 boolean that determines whether allocations should be aligned on 16-byte boundaries
  125. //! \details If T_Align16 is true, then AllocatorWithCleanup calls AlignedAllocate()
  126. //! for memory allocations. If T_Align16 is false, then AllocatorWithCleanup() calls
  127. //! UnalignedAllocate() for memory allocations.
  128. //! \details Template parameter T_Align16 is effectively controlled by cryptlib.h and mirrors
  129. //! CRYPTOPP_BOOL_ALIGN16. CRYPTOPP_BOOL_ALIGN16 is often used as the template parameter.
  130. template <class T, bool T_Align16 = false>
  131. class AllocatorWithCleanup : public AllocatorBase<T>
  132. {
  133. public:
  134. CRYPTOPP_INHERIT_ALLOCATOR_TYPES
  135. //! \brief Allocates a block of memory
  136. //! \param ptr the size of the allocation
  137. //! \param size the size of the allocation
  138. //! \returns a memory block
  139. //! \throws InvalidArgument
  140. //! \details allocate() first checks the size of the request. If it is non-0
  141. //! and less than max_size(), then an attempt is made to fulfill the request using either
  142. //! AlignedAllocate() or UnalignedAllocate().
  143. //! \details AlignedAllocate() is used if T_Align16 is true.
  144. //! UnalignedAllocate() used if T_Align16 is false.
  145. //! \details This is the C++ *Placement New* operator. ptr is not used, and the function
  146. //! asserts in Debug builds if ptr is non-NULL.
  147. //! \sa CallNewHandler() for the methods used to recover from a failed
  148. //! allocation attempt.
  149. //! \note size is the count of elements, and not the number of bytes
  150. pointer allocate(size_type size, const void *ptr = NULL)
  151. {
  152. CRYPTOPP_UNUSED(ptr); assert(ptr == NULL);
  153. this->CheckSize(size);
  154. if (size == 0)
  155. return NULL;
  156. #if CRYPTOPP_BOOL_ALIGN16
  157. // TODO: should this need the test 'size*sizeof(T) >= 16'?
  158. if (T_Align16 && size*sizeof(T) >= 16)
  159. return (pointer)AlignedAllocate(size*sizeof(T));
  160. #endif
  161. return (pointer)UnalignedAllocate(size*sizeof(T));
  162. }
  163. //! \brief Deallocates a block of memory
  164. //! \param ptr the size of the allocation
  165. //! \param size the size of the allocation
  166. //! \details Internally, SecureWipeArray() is called before deallocating the memory.
  167. //! Once the memory block is wiped or zeroized, AlignedDeallocate() or
  168. //! UnalignedDeallocate() is called.
  169. //! \details AlignedDeallocate() is used if T_Align16 is true.
  170. //! UnalignedDeallocate() used if T_Align16 is false.
  171. void deallocate(void *ptr, size_type size)
  172. {
  173. assert((ptr && size) || !(ptr || size));
  174. SecureWipeArray((pointer)ptr, size);
  175. #if CRYPTOPP_BOOL_ALIGN16
  176. if (T_Align16 && size*sizeof(T) >= 16)
  177. return AlignedDeallocate(ptr);
  178. #endif
  179. UnalignedDeallocate(ptr);
  180. }
  181. //! \brief Reallocates a block of memory
  182. //! \param oldPtr the previous allocation
  183. //! \param oldSize the size of the previous allocation
  184. //! \param newSize the new, requested size
  185. //! \param preserve flag that indicates if the old allocation should be preserved
  186. //! \returns pointer to the new memory block
  187. //! \details Internally, reallocate() calls StandardReallocate().
  188. //! \details If preserve is true, then index 0 is used to begin copying the
  189. //! old memory block to the new one. If the block grows, then the old array
  190. //! is copied in its entirety. If the block shrinks, then only newSize
  191. //! elements are copied from the old block to the new one.
  192. //! \note oldSize and newSize are the count of elements, and not the
  193. //! number of bytes.
  194. pointer reallocate(T *oldPtr, size_type oldSize, size_type newSize, bool preserve)
  195. {
  196. assert((oldPtr && oldSize) || !(oldPtr || oldSize));
  197. return StandardReallocate(*this, oldPtr, oldSize, newSize, preserve);
  198. }
  199. // VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a
  200. // template class member called rebind".
  201. template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; };
  202. #if _MSC_VER >= 1500
  203. AllocatorWithCleanup() {}
  204. template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {}
  205. #endif
  206. };
  207. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
  208. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
  209. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
  210. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
  211. #if CRYPTOPP_BOOL_X86
  212. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>; // for Integer
  213. #endif
  214. //! \class NullAllocator
  215. //! \brief NULL allocator
  216. //! \tparam T class or type
  217. //! \details A NullAllocator is useful for fixed-size, stack based allocations
  218. //! (i.e., static arrays used by FixedSizeAllocatorWithCleanup).
  219. //! \details A NullAllocator always returns 0 for max_size(), and always returns
  220. //! NULL for allocation requests. Though the allocator does not allocate at
  221. //! runtime, it does perform a secure wipe or zeroization during cleanup.
  222. template <class T>
  223. class NullAllocator : public AllocatorBase<T>
  224. {
  225. public:
  226. CRYPTOPP_INHERIT_ALLOCATOR_TYPES
  227. // TODO: should this return NULL or throw bad_alloc? Non-Windows C++ standard
  228. // libraries always throw. And late mode Windows throws. Early model Windows
  229. // (circa VC++ 6.0) returned NULL.
  230. pointer allocate(size_type n, const void* unused = NULL)
  231. {
  232. CRYPTOPP_UNUSED(n); CRYPTOPP_UNUSED(unused);
  233. assert(false); return NULL;
  234. }
  235. void deallocate(void *p, size_type n)
  236. {
  237. CRYPTOPP_UNUSED(p); CRYPTOPP_UNUSED(n);
  238. assert(false);
  239. }
  240. size_type max_size() const {return 0;}
  241. };
  242. //! \class FixedSizeAllocatorWithCleanup
  243. //! \brief Static secure memory block with cleanup
  244. //! \tparam T class or type
  245. //! \tparam S fixed-size of the stack-based memory block
  246. //! \tparam A AllocatorBase derived class for allocation and cleanup
  247. //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
  248. //! based allocation at compile time. The class can grow its memory
  249. //! block at runtime if a suitable allocator is available. If size
  250. //! grows beyond S and a suitable allocator is available, then the
  251. //! statically allocated array is obsoleted.
  252. //! \note This allocator can't be used with standard collections because
  253. //! they require that all objects of the same allocator type are equivalent.
  254. template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
  255. class FixedSizeAllocatorWithCleanup : public AllocatorBase<T>
  256. {
  257. public:
  258. CRYPTOPP_INHERIT_ALLOCATOR_TYPES
  259. //! \brief Constructs a FixedSizeAllocatorWithCleanup
  260. FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
  261. //! \brief Allocates a block of memory
  262. //! \param size size of the memory block
  263. //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
  264. //! based allocation at compile time. If size is less than or equal to
  265. //! S, then a pointer to the static array is returned.
  266. //! \details The class can grow its memory block at runtime if a suitable
  267. //! allocator is available. If size grows beyond S and a suitable
  268. //! allocator is available, then the statically allocated array is
  269. //! obsoleted. If a suitable allocator is \a not available, as with a
  270. //! NullAllocator, then the function returns NULL and a runtime error
  271. //! eventually occurs.
  272. //! \note size is the count of elements, and not the number of bytes.
  273. //! \sa reallocate(), SecBlockWithHint
  274. pointer allocate(size_type size)
  275. {
  276. assert(IsAlignedOn(m_array, 8));
  277. if (size <= S && !m_allocated)
  278. {
  279. m_allocated = true;
  280. return GetAlignedArray();
  281. }
  282. else
  283. return m_fallbackAllocator.allocate(size);
  284. }
  285. //! \brief Allocates a block of memory
  286. //! \param size size of the memory block
  287. //! \param hint an unused hint
  288. //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
  289. //! based allocation at compile time. If size is less than or equal to
  290. //! S, then a pointer to the static array is returned.
  291. //! \details The class can grow its memory block at runtime if a suitable
  292. //! allocator is available. If size grows beyond S and a suitable
  293. //! allocator is available, then the statically allocated array is
  294. //! obsoleted. If a suitable allocator is \a not available, as with a
  295. //! NullAllocator, then the function returns NULL and a runtime error
  296. //! eventually occurs.
  297. //! \note size is the count of elements, and not the number of bytes.
  298. //! \sa reallocate(), SecBlockWithHint
  299. pointer allocate(size_type size, const void *hint)
  300. {
  301. if (size <= S && !m_allocated)
  302. {
  303. m_allocated = true;
  304. return GetAlignedArray();
  305. }
  306. else
  307. return m_fallbackAllocator.allocate(size, hint);
  308. }
  309. //! \brief Deallocates a block of memory
  310. //! \param ptr a pointer to the memory block to deallocate
  311. //! \param size size of the memory block
  312. //! \details The memory block is wiped or zeroized before deallocation.
  313. //! If the statically allocated memory block is active, then no
  314. //! additional actions are taken after the wipe.
  315. //! \details If a dynamic memory block is active, then the pointer and
  316. //! size are passed to the allocator for deallocation.
  317. void deallocate(void *ptr, size_type size)
  318. {
  319. if (ptr == GetAlignedArray())
  320. {
  321. assert(size <= S);
  322. assert(m_allocated);
  323. m_allocated = false;
  324. SecureWipeArray((pointer)ptr, size);
  325. }
  326. else
  327. m_fallbackAllocator.deallocate(ptr, size);
  328. }
  329. //! \brief Reallocates a block of memory
  330. //! \param oldPtr the previous allocation
  331. //! \param oldSize the size of the previous allocation
  332. //! \param newSize the new, requested size
  333. //! \param preserve flag that indicates if the old allocation should be preserved
  334. //! \returns pointer to the new memory block
  335. //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
  336. //! based allocation at compile time. If size is less than or equal to
  337. //! S, then a pointer to the static array is returned.
  338. //! \details The class can grow its memory block at runtime if a suitable
  339. //! allocator is available. If size grows beyond S and a suitable
  340. //! allocator is available, then the statically allocated array is
  341. //! obsoleted. If a suitable allocator is \a not available, as with a
  342. //! NullAllocator, then the function returns NULL and a runtime error
  343. //! eventually occurs.
  344. //! \note size is the count of elements, and not the number of bytes.
  345. //! \sa reallocate(), SecBlockWithHint
  346. pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve)
  347. {
  348. if (oldPtr == GetAlignedArray() && newSize <= S)
  349. {
  350. assert(oldSize <= S);
  351. if (oldSize > newSize)
  352. SecureWipeArray(oldPtr+newSize, oldSize-newSize);
  353. return oldPtr;
  354. }
  355. pointer newPointer = allocate(newSize, NULL);
  356. if (preserve && newSize)
  357. {
  358. const size_t copySize = STDMIN(oldSize, newSize);
  359. memcpy_s(newPointer, copySize, oldPtr, copySize);
  360. }
  361. deallocate(oldPtr, oldSize);
  362. return newPointer;
  363. }
  364. size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);}
  365. private:
  366. #ifdef __BORLANDC__
  367. T* GetAlignedArray() {return m_array;}
  368. T m_array[S];
  369. #else
  370. T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16 && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
  371. CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16 && T_Align16) ? S+8/sizeof(T) : S];
  372. #endif
  373. A m_fallbackAllocator;
  374. bool m_allocated;
  375. };
  376. //! \class SecBlock
  377. //! \brief Secure memory block with allocator and cleanup
  378. //! \tparam T a class or type
  379. //! \tparam A AllocatorWithCleanup derived class for allocation and cleanup
  380. template <class T, class A = AllocatorWithCleanup<T> >
  381. class SecBlock
  382. {
  383. public:
  384. typedef typename A::value_type value_type;
  385. typedef typename A::pointer iterator;
  386. typedef typename A::const_pointer const_iterator;
  387. typedef typename A::size_type size_type;
  388. //! \brief Construct a SecBlock with space for size elements.
  389. //! \param size the number of elements in the allocation
  390. //! \throws std::bad_alloc
  391. //! \details The elements are not initialized.
  392. //! \note size is the count of elements, and not the number of bytes
  393. explicit SecBlock(size_type size=0)
  394. : m_size(size), m_ptr(m_alloc.allocate(size, NULL)) { }
  395. //! \brief Copy construct a SecBlock from another SecBlock
  396. //! \param t the other SecBlock
  397. //! \throws std::bad_alloc
  398. SecBlock(const SecBlock<T, A> &t)
  399. : m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULL)) {
  400. assert((!t.m_ptr && !m_size) || (t.m_ptr && m_size));
  401. if (t.m_ptr) {memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));}
  402. }
  403. //! \brief Construct a SecBlock from an array of elements.
  404. //! \param ptr a pointer to an array of T
  405. //! \param len the number of elements in the memory block
  406. //! \throws std::bad_alloc
  407. //! \details If <tt>ptr!=NULL</tt> and <tt>len!=0</tt>, then the block is initialized from the pointer ptr.
  408. //! If <tt>ptr==NULL</tt> and <tt>len!=0</tt>, then the block is initialized to 0.
  409. //! Otherwise, the block is empty and uninitialized.
  410. //! \note size is the count of elements, and not the number of bytes
  411. SecBlock(const T *ptr, size_type len)
  412. : m_size(len), m_ptr(m_alloc.allocate(len, NULL)) {
  413. assert((!m_ptr && !m_size) || (m_ptr && m_size));
  414. if (ptr && m_ptr)
  415. memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));
  416. else if (m_size)
  417. memset(m_ptr, 0, m_size*sizeof(T));
  418. }
  419. ~SecBlock()
  420. {m_alloc.deallocate(m_ptr, m_size);}
  421. #ifdef __BORLANDC__
  422. operator T *() const
  423. {return (T*)m_ptr;}
  424. #else
  425. operator const void *() const
  426. {return m_ptr;}
  427. operator void *()
  428. {return m_ptr;}
  429. operator const T *() const
  430. {return m_ptr;}
  431. operator T *()
  432. {return m_ptr;}
  433. #endif
  434. //! \brief Provides an iterator pointing to the first element in the memory block
  435. //! \returns iterator pointing to the first element in the memory block
  436. iterator begin()
  437. {return m_ptr;}
  438. //! \brief Provides a constant iterator pointing to the first element in the memory block
  439. //! \returns constant iterator pointing to the first element in the memory block
  440. const_iterator begin() const
  441. {return m_ptr;}
  442. //! \brief Provides an iterator pointing beyond the last element in the memory block
  443. //! \returns iterator pointing beyond the last element in the memory block
  444. iterator end()
  445. {return m_ptr+m_size;}
  446. //! \brief Provides a constant iterator pointing beyond the last element in the memory block
  447. //! \returns constant iterator pointing beyond the last element in the memory block
  448. const_iterator end() const
  449. {return m_ptr+m_size;}
  450. //! \brief Provides a pointer to the first element in the memory block
  451. //! \returns pointer to the first element in the memory block
  452. typename A::pointer data() {return m_ptr;}
  453. //! \brief Provides a pointer to the first element in the memory block
  454. //! \returns constant pointer to the first element in the memory block
  455. typename A::const_pointer data() const {return m_ptr;}
  456. //! \brief Provides the count of elements in the SecBlock
  457. //! \returns number of elements in the memory block
  458. //! \note the return value is the count of elements, and not the number of bytes
  459. size_type size() const {return m_size;}
  460. //! \brief Determines if the SecBlock is empty
  461. //! \returns true if number of elements in the memory block is 0, false otherwise
  462. bool empty() const {return m_size == 0;}
  463. //! \brief Provides a byte pointer to the first element in the memory block
  464. //! \returns byte pointer to the first element in the memory block
  465. byte * BytePtr() {return (byte *)m_ptr;}
  466. //! \brief Return a byte pointer to the first element in the memory block
  467. //! \returns constant byte pointer to the first element in the memory block
  468. const byte * BytePtr() const {return (const byte *)m_ptr;}
  469. //! \brief Provides the number of bytes in the SecBlock
  470. //! \return the number of bytes in the memory block
  471. //! \note the return value is the number of bytes, and not count of elements.
  472. size_type SizeInBytes() const {return m_size*sizeof(T);}
  473. //! \brief Set contents and size from an array
  474. //! \param ptr a pointer to an array of T
  475. //! \param len the number of elements in the memory block
  476. //! \details If the memory block is reduced in size, then the unused area is set to 0.
  477. void Assign(const T *ptr, size_type len)
  478. {
  479. New(len);
  480. if (m_ptr && ptr && len)
  481. {memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));}
  482. }
  483. //! \brief Copy contents from another SecBlock
  484. //! \param t the other SecBlock
  485. //! \details Assign checks for self assignment.
  486. //! \details If the memory block is reduced in size, then the unused area is set to 0.
  487. void Assign(const SecBlock<T, A> &t)
  488. {
  489. if (this != &t)
  490. {
  491. New(t.m_size);
  492. if (m_ptr && t.m_ptr && t.m_size)
  493. {memcpy_s(m_ptr, m_size*sizeof(T), t, t.m_size*sizeof(T));}
  494. }
  495. }
  496. //! \brief Assign contents from another SecBlock
  497. //! \param t the other SecBlock
  498. //! \details Internally, operator=() calls Assign().
  499. //! \details If the memory block is reduced in size, then the unused area is set to 0.
  500. SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
  501. {
  502. // Assign guards for self-assignment
  503. Assign(t);
  504. return *this;
  505. }
  506. //! \brief Append contents from another SecBlock
  507. //! \param t the other SecBlock
  508. //! \details Internally, this SecBlock calls Grow and then copies the new content.
  509. //! \details If the memory block is reduced in size, then the unused area is set to 0.
  510. SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
  511. {
  512. assert((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_ptr.m_size));
  513. if(t.size)
  514. {
  515. size_type oldSize = m_size;
  516. Grow(m_size+t.m_size);
  517. if (m_ptr && t.m_ptr)
  518. {memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), t.m_ptr, t.m_size*sizeof(T));}
  519. }
  520. return *this;
  521. }
  522. //! \brief Concatenate contents from another SecBlock
  523. //! \param t the other SecBlock
  524. //! \returns a newly constructed SecBlock that is a conacentation of this and t
  525. //! \details Internally, a temporary SecBlock is created and the content from this
  526. //! SecBlock and the other SecBlock are concatenated. The temporary
  527. //! SecBlock is returned to the caller.
  528. SecBlock<T, A> operator+(const SecBlock<T, A> &t)
  529. {
  530. assert((!m_ptr && !m_size) || (m_ptr && m_size));
  531. assert((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_ptr.m_size));
  532. if(!t.size) return SecBlock(*this);
  533. SecBlock<T, A> result(m_size+t.m_size);
  534. memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
  535. memcpy_s(result.m_ptr+m_size, (t.m_size-m_size)*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
  536. return result;
  537. }
  538. //! \brief Bitwise compare two SecBlocks
  539. //! \param t the other SecBlock
  540. //! \returns true if the size and bits are equal, false otherwise
  541. //! \details Uses a constant time compare if the arrays are equal size. The constant time
  542. //! compare is VerifyBufsEqual() found in misc.h.
  543. //! \sa operator!=()
  544. bool operator==(const SecBlock<T, A> &t) const
  545. {
  546. return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
  547. }
  548. //! \brief Bitwise compare two SecBlocks
  549. //! \param t the other SecBlock
  550. //! \returns true if the size and bits are equal, false otherwise
  551. //! \details Uses a constant time compare if the arrays are equal size. The constant time
  552. //! compare is VerifyBufsEqual() found in misc.h.
  553. //! \details Internally, operator!=() returns the inverse of operator==().
  554. //! \sa operator==()
  555. bool operator!=(const SecBlock<T, A> &t) const
  556. {
  557. return !operator==(t);
  558. }
  559. //! \brief Change size without preserving contents
  560. //! \param newSize the new size of the memory block
  561. //! \details Old content is \a not preserved. If the memory block is reduced in size,
  562. //! then the unused content is set to 0. If the memory block grows in size, then
  563. //! all content is uninitialized.
  564. //! \details Internally, this SecBlock calls reallocate().
  565. //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
  566. void New(size_type newSize)
  567. {
  568. m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
  569. m_size = newSize;
  570. }
  571. //! \brief Change size without preserving contents
  572. //! \param newSize the new size of the memory block
  573. //! \details Old content is not preserved. If the memory block is reduced in size,
  574. //! then the unused content is set to 0. Existing and new content is set to 0.
  575. //! \details Internally, this SecBlock calls reallocate().
  576. //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
  577. void CleanNew(size_type newSize)
  578. {
  579. New(newSize);
  580. if (m_ptr) {memset_z(m_ptr, 0, m_size*sizeof(T));}
  581. }
  582. //! \brief Change size and preserve contents
  583. //! \param newSize the new size of the memory block
  584. //! \details Old content is preserved. If the memory block grows in size, then
  585. //! all content is uninitialized.
  586. //! \details Internally, this SecBlock calls reallocate().
  587. //! \note reallocate() is called if the size increases. If the size does not
  588. //! increase, then Grow does not take action. If the size must change,
  589. //! then use resize().
  590. //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
  591. void Grow(size_type newSize)
  592. {
  593. if (newSize > m_size)
  594. {
  595. m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
  596. m_size = newSize;
  597. }
  598. }
  599. //! \brief Change size and preserve contents
  600. //! \param newSize the new size of the memory block
  601. //! \details Old content is preserved. If the memory block is reduced in size,
  602. //! then the unused content is set to 0. If the memory block grows in size,
  603. //! then the new content is uninitialized.
  604. //! \details Internally, this SecBlock calls reallocate().
  605. //! \note reallocate() is called if the size increases. If the size does not
  606. //! increase, then Grow does not take action. If the size must change,
  607. //! then use resize().
  608. //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
  609. void CleanGrow(size_type newSize)
  610. {
  611. if (newSize > m_size)
  612. {
  613. m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
  614. memset_z(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
  615. m_size = newSize;
  616. }
  617. }
  618. //! \brief Change size and preserve contents
  619. //! \param newSize the new size of the memory block
  620. //! \details Old content is preserved. If the memory block grows in size, then
  621. //! all content is uninitialized.
  622. //! \details Internally, this SecBlock calls reallocate().
  623. //! \note reallocate() is called if the size increases. If the size does not
  624. //! increase, then Grow does not take action. If the size must change,
  625. //! then use resize().
  626. //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
  627. void resize(size_type newSize)
  628. {
  629. m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
  630. m_size = newSize;
  631. }
  632. //! \brief Swap contents with another SecBlock
  633. //! \param b the other SecBlock
  634. //! \details Internally, std::swap() is called on m_alloc, m_size and m_ptr.
  635. void swap(SecBlock<T, A> &b)
  636. {
  637. // Swap must occur on the allocator in case its FixedSize that spilled into the heap.
  638. std::swap(m_alloc, b.m_alloc);
  639. std::swap(m_size, b.m_size);
  640. std::swap(m_ptr, b.m_ptr);
  641. }
  642. // protected:
  643. A m_alloc;
  644. size_type m_size;
  645. T *m_ptr;
  646. };
  647. #ifdef CRYPTOPP_DOXYGEN_PROCESSING
  648. //! \class SecByteBlock
  649. //! \brief SecByteBlock is a SecBlock<byte> typedef.
  650. class SecByteBlock : public SecBlock<byte> {};
  651. //! \class SecWordBlock
  652. //! \brief SecWordBlock is a SecBlock<word> typedef.
  653. class SecWordBlock : public SecBlock<word> {};
  654. //! \class AlignedSecByteBlock
  655. //! \brief AlignedSecByteBlock is a SecBlock<byte, AllocatorWithCleanup<byte, true> > typedef.
  656. class AlignedSecByteBlock SecBlock<byte, AllocatorWithCleanup<byte, true> > {};
  657. #else
  658. typedef SecBlock<byte> SecByteBlock;
  659. typedef SecBlock<word> SecWordBlock;
  660. typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
  661. #endif
  662. // No need for move semantics on derived class *if* the class does not add any
  663. // data members; see http://stackoverflow.com/q/31755703, and Rule of {0|3|5}.
  664. //! \class FixedSizeSecBlock
  665. //! \brief Fixed size stack-based SecBlock
  666. //! \tparam T class or type
  667. //! \tparam S fixed-size of the stack-based memory block
  668. //! \tparam A AllocatorBase derived class for allocation and cleanup
  669. template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
  670. class FixedSizeSecBlock : public SecBlock<T, A>
  671. {
  672. public:
  673. //! \brief Construct a FixedSizeSecBlock
  674. explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
  675. };
  676. //! \class FixedSizeAlignedSecBlock
  677. //! \brief Fixed size stack-based SecBlock with 16-byte alignment
  678. //! \tparam T class or type
  679. //! \tparam S fixed-size of the stack-based memory block
  680. //! \tparam A AllocatorBase derived class for allocation and cleanup
  681. template <class T, unsigned int S, bool T_Align16 = true>
  682. class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
  683. {
  684. };
  685. //! \class SecBlockWithHint
  686. //! \brief Stack-based SecBlock that grows into the heap
  687. //! \tparam T class or type
  688. //! \tparam S fixed-size of the stack-based memory block
  689. //! \tparam A AllocatorBase derived class for allocation and cleanup
  690. template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
  691. class SecBlockWithHint : public SecBlock<T, A>
  692. {
  693. public:
  694. //! construct a SecBlockWithHint with a count of elements
  695. explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
  696. };
  697. template<class T, bool A, class U, bool B>
  698. inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);}
  699. template<class T, bool A, class U, bool B>
  700. inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);}
  701. NAMESPACE_END
  702. NAMESPACE_BEGIN(std)
  703. template <class T, class A>
  704. inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
  705. {
  706. a.swap(b);
  707. }
  708. #if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
  709. // working for STLport 5.1.3 and MSVC 6 SP5
  710. template <class _Tp1, class _Tp2>
  711. inline CryptoPP::AllocatorWithCleanup<_Tp2>&
  712. __stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
  713. {
  714. return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);
  715. }
  716. #endif
  717. NAMESPACE_END
  718. #if CRYPTOPP_MSC_VERSION
  719. # pragma warning(pop)
  720. #endif
  721. #endif