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