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