Counter Strike : Global Offensive Source Code
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.

468 lines
12 KiB

  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 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. // VALVE: clang requires AllocatorBase::CheckSize instead of CheckSize
  78. AllocatorBase<T>::CheckSize(n);
  79. if (n == 0)
  80. return NULL;
  81. #if CRYPTOPP_BOOL_ALIGN16_ENABLED
  82. if (T_Align16 && n*sizeof(T) >= 16)
  83. return (pointer)AlignedAllocate(n*sizeof(T));
  84. #endif
  85. return (pointer)UnalignedAllocate(n*sizeof(T));
  86. }
  87. void deallocate(void *p, size_type n)
  88. {
  89. SecureWipeArray((pointer)p, n);
  90. #if CRYPTOPP_BOOL_ALIGN16_ENABLED
  91. if (T_Align16 && n*sizeof(T) >= 16)
  92. return AlignedDeallocate(p);
  93. #endif
  94. UnalignedDeallocate(p);
  95. }
  96. pointer reallocate(T *p, size_type oldSize, size_type newSize, bool preserve)
  97. {
  98. return StandardReallocate(*this, p, oldSize, newSize, preserve);
  99. }
  100. // VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a
  101. // template class member called rebind".
  102. template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; };
  103. #if _MSC_VER >= 1500
  104. AllocatorWithCleanup() {}
  105. template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {}
  106. #endif
  107. };
  108. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
  109. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
  110. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
  111. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
  112. #if CRYPTOPP_BOOL_X86
  113. CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>; // for Integer
  114. #endif
  115. template <class T>
  116. class NullAllocator : public AllocatorBase<T>
  117. {
  118. public:
  119. CRYPTOPP_INHERIT_ALLOCATOR_TYPES
  120. pointer allocate(size_type n, const void * = NULL)
  121. {
  122. assert(false);
  123. return NULL;
  124. }
  125. void deallocate(void *p, size_type n)
  126. {
  127. assert(false);
  128. }
  129. size_type max_size() const {return 0;}
  130. };
  131. // This allocator can't be used with standard collections because
  132. // they require that all objects of the same allocator type are equivalent.
  133. // So this is for use with SecBlock only.
  134. template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
  135. class FixedSizeAllocatorWithCleanup : public AllocatorBase<T>
  136. {
  137. public:
  138. CRYPTOPP_INHERIT_ALLOCATOR_TYPES
  139. FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
  140. pointer allocate(size_type n)
  141. {
  142. assert(IsAlignedOn(m_array, 8));
  143. if (n <= S && !m_allocated)
  144. {
  145. m_allocated = true;
  146. return GetAlignedArray();
  147. }
  148. else
  149. return m_fallbackAllocator.allocate(n);
  150. }
  151. pointer allocate(size_type n, const void *hint)
  152. {
  153. if (n <= S && !m_allocated)
  154. {
  155. m_allocated = true;
  156. return GetAlignedArray();
  157. }
  158. else
  159. return m_fallbackAllocator.allocate(n, hint);
  160. }
  161. void deallocate(void *p, size_type n)
  162. {
  163. if (p == GetAlignedArray())
  164. {
  165. assert(n <= S);
  166. assert(m_allocated);
  167. m_allocated = false;
  168. SecureWipeArray((pointer)p, n);
  169. }
  170. else
  171. m_fallbackAllocator.deallocate(p, n);
  172. }
  173. pointer reallocate(pointer p, size_type oldSize, size_type newSize, bool preserve)
  174. {
  175. if (p == GetAlignedArray() && newSize <= S)
  176. {
  177. assert(oldSize <= S);
  178. if (oldSize > newSize)
  179. SecureWipeArray(p+newSize, oldSize-newSize);
  180. return p;
  181. }
  182. pointer newPointer = allocate(newSize, NULL);
  183. if (preserve)
  184. memcpy(newPointer, p, sizeof(T)*STDMIN(oldSize, newSize));
  185. deallocate(p, oldSize);
  186. return newPointer;
  187. }
  188. size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);}
  189. private:
  190. #ifdef __BORLANDC__
  191. T* GetAlignedArray() {return m_array;}
  192. T m_array[S];
  193. #else
  194. T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
  195. CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? S+8/sizeof(T) : S];
  196. #endif
  197. A m_fallbackAllocator;
  198. bool m_allocated;
  199. };
  200. //! a block of memory allocated using A
  201. template <class T, class A = AllocatorWithCleanup<T> >
  202. class SecBlock
  203. {
  204. public:
  205. typedef typename A::value_type value_type;
  206. typedef typename A::pointer iterator;
  207. typedef typename A::const_pointer const_iterator;
  208. typedef typename A::size_type size_type;
  209. explicit SecBlock(size_type size_in=0)
  210. : m_size(size_in) {m_ptr = m_alloc.allocate(size_in, NULL);}
  211. SecBlock(const SecBlock<T, A> &t)
  212. : 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));}
  213. SecBlock(const T *t, size_type len)
  214. : m_size(len)
  215. {
  216. m_ptr = m_alloc.allocate(len, NULL);
  217. if (t == NULL)
  218. memset_z(m_ptr, 0, len*sizeof(T));
  219. else
  220. memcpy(m_ptr, t, len*sizeof(T));
  221. }
  222. ~SecBlock()
  223. {m_alloc.deallocate(m_ptr, m_size);}
  224. #ifdef __BORLANDC__
  225. operator T *() const
  226. {return (T*)m_ptr;}
  227. #else
  228. operator const void *() const
  229. {return m_ptr;}
  230. operator void *()
  231. {return m_ptr;}
  232. operator const T *() const
  233. {return m_ptr;}
  234. operator T *()
  235. {return m_ptr;}
  236. #endif
  237. // T *operator +(size_type offset)
  238. // {return m_ptr+offset;}
  239. // const T *operator +(size_type offset) const
  240. // {return m_ptr+offset;}
  241. // T& operator[](size_type index)
  242. // {assert(index >= 0 && index < m_size); return m_ptr[index];}
  243. // const T& operator[](size_type index) const
  244. // {assert(index >= 0 && index < m_size); return m_ptr[index];}
  245. iterator begin()
  246. {return m_ptr;}
  247. const_iterator begin() const
  248. {return m_ptr;}
  249. iterator end()
  250. {return m_ptr+m_size;}
  251. const_iterator end() const
  252. {return m_ptr+m_size;}
  253. typename A::pointer data() {return m_ptr;}
  254. typename A::const_pointer data() const {return m_ptr;}
  255. size_type size() const {return m_size;}
  256. bool empty() const {return m_size == 0;}
  257. byte * BytePtr() {return (byte *)m_ptr;}
  258. const byte * BytePtr() const {return (const byte *)m_ptr;}
  259. size_type SizeInBytes() const {return m_size*sizeof(T);}
  260. //! set contents and size
  261. void Assign(const T *t, size_type len)
  262. {
  263. New(len);
  264. memcpy_s(m_ptr, m_size*sizeof(T), t, len*sizeof(T));
  265. }
  266. //! copy contents and size from another SecBlock
  267. void Assign(const SecBlock<T, A> &t)
  268. {
  269. if (this != &t)
  270. {
  271. New(t.m_size);
  272. memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));
  273. }
  274. }
  275. SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
  276. {
  277. Assign(t);
  278. return *this;
  279. }
  280. // append to this object
  281. SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
  282. {
  283. size_type oldSize = m_size;
  284. Grow(m_size+t.m_size);
  285. memcpy_s(m_ptr+oldSize, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
  286. return *this;
  287. }
  288. // append operator
  289. SecBlock<T, A> operator+(const SecBlock<T, A> &t)
  290. {
  291. SecBlock<T, A> result(m_size+t.m_size);
  292. memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
  293. memcpy_s(result.m_ptr+m_size, t.m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
  294. return result;
  295. }
  296. bool operator==(const SecBlock<T, A> &t) const
  297. {
  298. return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
  299. }
  300. bool operator!=(const SecBlock<T, A> &t) const
  301. {
  302. return !operator==(t);
  303. }
  304. //! change size, without preserving contents
  305. void New(size_type newSize)
  306. {
  307. m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
  308. m_size = newSize;
  309. }
  310. //! change size and set contents to 0
  311. void CleanNew(size_type newSize)
  312. {
  313. New(newSize);
  314. memset_z(m_ptr, 0, m_size*sizeof(T));
  315. }
  316. //! change size only if newSize > current size. contents are preserved
  317. void Grow(size_type newSize)
  318. {
  319. if (newSize > m_size)
  320. {
  321. m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
  322. m_size = newSize;
  323. }
  324. }
  325. //! change size only if newSize > current size. contents are preserved and additional area is set to 0
  326. void CleanGrow(size_type newSize)
  327. {
  328. if (newSize > m_size)
  329. {
  330. m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
  331. memset(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
  332. m_size = newSize;
  333. }
  334. }
  335. //! change size and preserve contents
  336. void resize(size_type newSize)
  337. {
  338. m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
  339. m_size = newSize;
  340. }
  341. //! swap contents and size with another SecBlock
  342. void swap(SecBlock<T, A> &b)
  343. {
  344. std::swap(m_alloc, b.m_alloc);
  345. std::swap(m_size, b.m_size);
  346. std::swap(m_ptr, b.m_ptr);
  347. }
  348. //private:
  349. A m_alloc;
  350. size_type m_size;
  351. T *m_ptr;
  352. };
  353. typedef SecBlock<byte> SecByteBlock;
  354. typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
  355. typedef SecBlock<word> SecWordBlock;
  356. //! a SecBlock with fixed size, allocated statically
  357. template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
  358. class FixedSizeSecBlock : public SecBlock<T, A>
  359. {
  360. public:
  361. explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
  362. };
  363. template <class T, unsigned int S, bool T_Align16 = true>
  364. class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
  365. {
  366. };
  367. //! a SecBlock that preallocates size S statically, and uses the heap when this size is exceeded
  368. template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
  369. class SecBlockWithHint : public SecBlock<T, A>
  370. {
  371. public:
  372. explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
  373. };
  374. template<class T, bool A, class U, bool B>
  375. inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);}
  376. template<class T, bool A, class U, bool B>
  377. inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);}
  378. NAMESPACE_END
  379. NAMESPACE_BEGIN(std)
  380. template <class T, class A>
  381. inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
  382. {
  383. a.swap(b);
  384. }
  385. #if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
  386. // working for STLport 5.1.3 and MSVC 6 SP5
  387. template <class _Tp1, class _Tp2>
  388. inline CryptoPP::AllocatorWithCleanup<_Tp2>&
  389. __stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
  390. {
  391. return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);
  392. }
  393. #endif
  394. NAMESPACE_END
  395. #endif