|
||||
File indexing completed on 2025-01-18 09:55:08
0001 // secblock.h - originally written and placed in the public domain by Wei Dai 0002 0003 /// \file secblock.h 0004 /// \brief Classes and functions for secure memory allocations. 0005 0006 #ifndef CRYPTOPP_SECBLOCK_H 0007 #define CRYPTOPP_SECBLOCK_H 0008 0009 #include "config.h" 0010 #include "allocate.h" 0011 #include "misc.h" 0012 #include "stdcpp.h" 0013 0014 #if defined(CRYPTOPP_MSC_VERSION) 0015 # pragma warning(push) 0016 # pragma warning(disable: 4231 4275 4700) 0017 # if (CRYPTOPP_MSC_VERSION >= 1400) 0018 # pragma warning(disable: 6011 6386 28193) 0019 # endif 0020 #endif 0021 0022 NAMESPACE_BEGIN(CryptoPP) 0023 0024 // ************** secure memory allocation *************** 0025 0026 /// \brief Base class for all allocators used by SecBlock 0027 /// \tparam T the class or type 0028 template<class T> 0029 class AllocatorBase 0030 { 0031 public: 0032 typedef T value_type; 0033 typedef size_t size_type; 0034 typedef std::ptrdiff_t difference_type; 0035 typedef T * pointer; 0036 typedef const T * const_pointer; 0037 typedef T & reference; 0038 typedef const T & const_reference; 0039 0040 pointer address(reference r) const {return (&r);} 0041 const_pointer address(const_reference r) const {return (&r); } 0042 void construct(pointer p, const T& val) {new (p) T(val);} 0043 void destroy(pointer p) {CRYPTOPP_UNUSED(p); p->~T();} 0044 0045 /// \brief Returns the maximum number of elements the allocator can provide 0046 /// \details <tt>ELEMS_MAX</tt> is the maximum number of elements the 0047 /// <tt>Allocator</tt> can provide. The value of <tt>ELEMS_MAX</tt> is 0048 /// <tt>SIZE_MAX/sizeof(T)</tt>. <tt>std::numeric_limits</tt> was avoided 0049 /// due to lack of <tt>constexpr</tt>-ness in C++03 and below. 0050 /// \note In C++03 and below <tt>ELEMS_MAX</tt> is a static data member of type 0051 /// <tt>size_type</tt>. In C++11 and above <tt>ELEMS_MAX</tt> is an <tt>enum</tt> 0052 /// inheriting from <tt>size_type</tt>. In both cases <tt>ELEMS_MAX</tt> can be 0053 /// used before objects are fully constructed, and it does not suffer the 0054 /// limitations of class methods like <tt>max_size</tt>. 0055 /// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/346">Issue 346/CVE-2016-9939</A> 0056 /// \since Crypto++ 6.0 0057 #if defined(CRYPTOPP_DOXYGEN_PROCESSING) 0058 static const size_type ELEMS_MAX = ...; 0059 #elif defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION <= 1400) 0060 static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T); 0061 #elif defined(CRYPTOPP_CXX11_STRONG_ENUM) 0062 enum : size_type {ELEMS_MAX = SIZE_MAX/sizeof(T)}; 0063 #else 0064 static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T); 0065 #endif 0066 0067 /// \brief Returns the maximum number of elements the allocator can provide 0068 /// \return the maximum number of elements the allocator can provide 0069 /// \details Internally, preprocessor macros are used rather than std::numeric_limits 0070 /// because the latter is not a constexpr. Some compilers, like Clang, do not 0071 /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear 0072 /// to optimize it well in either form. 0073 CRYPTOPP_CONSTEXPR size_type max_size() const {return ELEMS_MAX;} 0074 0075 #if defined(__SUNPRO_CC) 0076 // https://github.com/weidai11/cryptopp/issues/770 0077 // and https://stackoverflow.com/q/53999461/608639 0078 CRYPTOPP_CONSTEXPR size_type max_size(size_type n) const {return SIZE_MAX/n;} 0079 #endif 0080 0081 #if defined(CRYPTOPP_CXX11_VARIADIC_TEMPLATES) || defined(CRYPTOPP_DOXYGEN_PROCESSING) 0082 0083 /// \brief Constructs a new V using variadic arguments 0084 /// \tparam V the type to be forwarded 0085 /// \tparam Args the arguments to be forwarded 0086 /// \param ptr pointer to type V 0087 /// \param args variadic arguments 0088 /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES 0089 /// is defined. The define is controlled by compiler versions detected in config.h. 0090 template<typename V, typename... Args> 0091 void construct(V* ptr, Args&&... args) {::new ((void*)ptr) V(std::forward<Args>(args)...);} 0092 0093 /// \brief Destroys an V constructed with variadic arguments 0094 /// \tparam V the type to be forwarded 0095 /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES 0096 /// is defined. The define is controlled by compiler versions detected in config.h. 0097 template<typename V> 0098 void destroy(V* ptr) {if (ptr) ptr->~V();} 0099 0100 #endif 0101 0102 protected: 0103 0104 /// \brief Verifies the allocator can satisfy a request based on size 0105 /// \param size the size of the allocation, in elements 0106 /// \throw InvalidArgument 0107 /// \details CheckSize verifies the number of elements requested is valid. 0108 /// \details If size is greater than max_size(), then InvalidArgument is thrown. 0109 /// The library throws InvalidArgument if the size is too large to satisfy. 0110 /// \details Internally, preprocessor macros are used rather than std::numeric_limits 0111 /// because the latter is not a constexpr. Some compilers, like Clang, do not 0112 /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear 0113 /// to optimize it well in either form. 0114 /// \details The <tt>sizeof(T) != 1</tt> in the condition attempts to help the 0115 /// compiler optimize the check for byte types. Coverity findings for 0116 /// CONSTANT_EXPRESSION_RESULT were generated without it. For byte types, 0117 /// size never exceeded ELEMS_MAX but the code was not removed. 0118 /// \note size is the count of elements, and not the number of bytes 0119 static void CheckSize(size_t size) 0120 { 0121 // Squash MSC C4100 warning for size. Also see commit 42b7c4ea5673. 0122 CRYPTOPP_UNUSED(size); 0123 // C++ throws std::bad_alloc (C++03) or std::bad_array_new_length (C++11) here. 0124 if (sizeof(T) != 1 && size > ELEMS_MAX) 0125 throw InvalidArgument("AllocatorBase: requested size would cause integer overflow"); 0126 } 0127 }; 0128 0129 #define CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T_type) \ 0130 typedef typename AllocatorBase<T_type>::value_type value_type;\ 0131 typedef typename AllocatorBase<T_type>::size_type size_type;\ 0132 typedef typename AllocatorBase<T_type>::difference_type difference_type;\ 0133 typedef typename AllocatorBase<T_type>::pointer pointer;\ 0134 typedef typename AllocatorBase<T_type>::const_pointer const_pointer;\ 0135 typedef typename AllocatorBase<T_type>::reference reference;\ 0136 typedef typename AllocatorBase<T_type>::const_reference const_reference; 0137 0138 /// \brief Reallocation function 0139 /// \tparam T the class or type 0140 /// \tparam A the class or type's allocator 0141 /// \param alloc the allocator 0142 /// \param oldPtr the previous allocation 0143 /// \param oldSize the size of the previous allocation 0144 /// \param newSize the new, requested size 0145 /// \param preserve flag that indicates if the old allocation should be preserved 0146 /// \note oldSize and newSize are the count of elements, and not the 0147 /// number of bytes. 0148 template <class T, class A> 0149 typename A::pointer StandardReallocate(A& alloc, T *oldPtr, typename A::size_type oldSize, typename A::size_type newSize, bool preserve) 0150 { 0151 // Avoid assert on pointer in reallocate. SecBlock regularly uses NULL 0152 // pointers rather returning non-NULL 0-sized pointers. 0153 if (oldSize == newSize) 0154 return oldPtr; 0155 0156 if (preserve) 0157 { 0158 typename A::pointer newPtr = alloc.allocate(newSize, NULLPTR); 0159 const typename A::size_type copySize = STDMIN(oldSize, newSize) * sizeof(T); 0160 0161 if (oldPtr && newPtr) 0162 memcpy_s(newPtr, copySize, oldPtr, copySize); 0163 0164 if (oldPtr) 0165 alloc.deallocate(oldPtr, oldSize); 0166 0167 return newPtr; 0168 } 0169 else 0170 { 0171 if (oldPtr) 0172 alloc.deallocate(oldPtr, oldSize); 0173 0174 return alloc.allocate(newSize, NULLPTR); 0175 } 0176 } 0177 0178 /// \brief Allocates a block of memory with cleanup 0179 /// \tparam T class or type 0180 /// \tparam T_Align16 boolean that determines whether allocations should be aligned on a 16-byte boundary 0181 /// \details If T_Align16 is true, then AllocatorWithCleanup calls AlignedAllocate() 0182 /// for memory allocations. If T_Align16 is false, then AllocatorWithCleanup() calls 0183 /// UnalignedAllocate() for memory allocations. 0184 /// \details Template parameter T_Align16 is effectively controlled by cryptlib.h and mirrors 0185 /// CRYPTOPP_BOOL_ALIGN16. CRYPTOPP_BOOL_ALIGN16 is often used as the template parameter. 0186 template <class T, bool T_Align16 = false> 0187 class AllocatorWithCleanup : public AllocatorBase<T> 0188 { 0189 public: 0190 CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) 0191 0192 /// \brief Allocates a block of memory 0193 /// \param ptr the size of the allocation 0194 /// \param size the size of the allocation, in elements 0195 /// \return a memory block 0196 /// \throw InvalidArgument 0197 /// \details allocate() first checks the size of the request. If it is non-0 0198 /// and less than max_size(), then an attempt is made to fulfill the request 0199 /// using either AlignedAllocate() or UnalignedAllocate(). AlignedAllocate() is 0200 /// used if T_Align16 is true. UnalignedAllocate() used if T_Align16 is false. 0201 /// \details This is the C++ *Placement New* operator. ptr is not used, and the 0202 /// function asserts in Debug builds if ptr is non-NULL. 0203 /// \sa CallNewHandler() for the methods used to recover from a failed 0204 /// allocation attempt. 0205 /// \note size is the count of elements, and not the number of bytes 0206 pointer allocate(size_type size, const void *ptr = NULLPTR) 0207 { 0208 CRYPTOPP_UNUSED(ptr); CRYPTOPP_ASSERT(ptr == NULLPTR); 0209 this->CheckSize(size); 0210 if (size == 0) 0211 return NULLPTR; 0212 0213 #if CRYPTOPP_BOOL_ALIGN16 0214 if (T_Align16) 0215 return reinterpret_cast<pointer>(AlignedAllocate(size*sizeof(T))); 0216 #endif 0217 0218 return reinterpret_cast<pointer>(UnalignedAllocate(size*sizeof(T))); 0219 } 0220 0221 /// \brief Deallocates a block of memory 0222 /// \param ptr the pointer for the allocation 0223 /// \param size the size of the allocation, in elements 0224 /// \details Internally, SecureWipeArray() is called before deallocating the 0225 /// memory. Once the memory block is wiped or zeroized, AlignedDeallocate() 0226 /// or UnalignedDeallocate() is called. 0227 /// \details AlignedDeallocate() is used if T_Align16 is true. 0228 /// UnalignedDeallocate() used if T_Align16 is false. 0229 void deallocate(void *ptr, size_type size) 0230 { 0231 // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL 0232 // pointers rather returning non-NULL 0-sized pointers. 0233 if (ptr) 0234 { 0235 SecureWipeArray(reinterpret_cast<pointer>(ptr), size); 0236 0237 #if CRYPTOPP_BOOL_ALIGN16 0238 if (T_Align16) 0239 return AlignedDeallocate(ptr); 0240 #endif 0241 0242 UnalignedDeallocate(ptr); 0243 } 0244 } 0245 0246 /// \brief Reallocates a block of memory 0247 /// \param oldPtr the previous allocation 0248 /// \param oldSize the size of the previous allocation 0249 /// \param newSize the new, requested size 0250 /// \param preserve flag that indicates if the old allocation should be preserved 0251 /// \return pointer to the new memory block 0252 /// \details Internally, reallocate() calls StandardReallocate(). 0253 /// \details If preserve is true, then index 0 is used to begin copying the 0254 /// old memory block to the new one. If the block grows, then the old array 0255 /// is copied in its entirety. If the block shrinks, then only newSize 0256 /// elements are copied from the old block to the new one. 0257 /// \note oldSize and newSize are the count of elements, and not the 0258 /// number of bytes. 0259 pointer reallocate(T *oldPtr, size_type oldSize, size_type newSize, bool preserve) 0260 { 0261 CRYPTOPP_ASSERT((oldPtr && oldSize) || !(oldPtr || oldSize)); 0262 return StandardReallocate(*this, oldPtr, oldSize, newSize, preserve); 0263 } 0264 0265 /// \brief Template class member Rebind 0266 /// \tparam V bound class or type 0267 /// \details Rebind allows a container class to allocate a different type of object 0268 /// to store elements. For example, a std::list will allocate std::list_node to 0269 /// store elements in the list. 0270 /// \details VS.NET STL enforces the policy of "All STL-compliant allocators 0271 /// have to provide a template class member called rebind". 0272 template <class V> struct rebind { typedef AllocatorWithCleanup<V, T_Align16> other; }; 0273 #if (CRYPTOPP_MSC_VERSION >= 1500) 0274 AllocatorWithCleanup() {} 0275 template <class V, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<V, A> &) {} 0276 #endif 0277 }; 0278 0279 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>; 0280 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>; 0281 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>; 0282 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>; 0283 #if defined(CRYPTOPP_WORD128_AVAILABLE) 0284 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word128, true>; // for Integer 0285 #endif 0286 #if CRYPTOPP_BOOL_X86 0287 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>; // for Integer 0288 #endif 0289 0290 /// \brief NULL allocator 0291 /// \tparam T class or type 0292 /// \details A NullAllocator is useful for fixed-size, stack based allocations 0293 /// (i.e., static arrays used by FixedSizeAllocatorWithCleanup). 0294 /// \details A NullAllocator always returns 0 for max_size(), and always returns 0295 /// NULL for allocation requests. Though the allocator does not allocate at 0296 /// runtime, it does perform a secure wipe or zeroization during cleanup. 0297 template <class T> 0298 class NullAllocator : public AllocatorBase<T> 0299 { 0300 public: 0301 //LCOV_EXCL_START 0302 CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) 0303 0304 // TODO: should this return NULL or throw bad_alloc? Non-Windows C++ standard 0305 // libraries always throw. And late mode Windows throws. Early model Windows 0306 // (circa VC++ 6.0) returned NULL. 0307 pointer allocate(size_type n, const void* unused = NULLPTR) 0308 { 0309 CRYPTOPP_UNUSED(n); CRYPTOPP_UNUSED(unused); 0310 CRYPTOPP_ASSERT(false); return NULLPTR; 0311 } 0312 0313 void deallocate(void *p, size_type n) 0314 { 0315 CRYPTOPP_UNUSED(p); CRYPTOPP_UNUSED(n); 0316 CRYPTOPP_ASSERT(false); 0317 } 0318 0319 CRYPTOPP_CONSTEXPR size_type max_size() const {return 0;} 0320 //LCOV_EXCL_STOP 0321 }; 0322 0323 /// \brief Static secure memory block with cleanup 0324 /// \tparam T class or type 0325 /// \tparam S fixed-size of the stack-based memory block, in elements 0326 /// \tparam T_Align16 boolean that determines whether allocations should 0327 /// be aligned on a 16-byte boundary 0328 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- 0329 /// based allocation at compile time. The class can grow its memory 0330 /// block at runtime if a suitable allocator is available. If size 0331 /// grows beyond S and a suitable allocator is available, then the 0332 /// statically allocated array is obsoleted. 0333 /// \note This allocator can't be used with standard collections because 0334 /// they require that all objects of the same allocator type are equivalent. 0335 template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false> 0336 class FixedSizeAllocatorWithCleanup : public AllocatorBase<T> 0337 { 0338 // The body of FixedSizeAllocatorWithCleanup is provided in the two 0339 // partial specializations that follow. The two specializations 0340 // pivot on the boolean template parameter T_Align16. 0341 }; 0342 0343 /// \brief Static secure memory block with cleanup 0344 /// \tparam T class or type 0345 /// \tparam S fixed-size of the stack-based memory block, in elements 0346 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- 0347 /// based allocation at compile time. The class can grow its memory 0348 /// block at runtime if a suitable allocator is available. If size 0349 /// grows beyond S and a suitable allocator is available, then the 0350 /// statically allocated array is obsoleted. 0351 /// \note This allocator can't be used with standard collections because 0352 /// they require that all objects of the same allocator type are equivalent. 0353 template <class T, size_t S, class A> 0354 class FixedSizeAllocatorWithCleanup<T, S, A, true> : public AllocatorBase<T> 0355 { 0356 public: 0357 CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) 0358 0359 /// \brief Constructs a FixedSizeAllocatorWithCleanup 0360 FixedSizeAllocatorWithCleanup() : m_allocated(false) {} 0361 0362 /// \brief Allocates a block of memory 0363 /// \param size the count elements in the memory block 0364 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based 0365 /// allocation at compile time. If size is less than or equal to 0366 /// <tt>S</tt>, then a pointer to the static array is returned. 0367 /// \details The class can grow its memory block at runtime if a suitable 0368 /// allocator is available. If size grows beyond S and a suitable 0369 /// allocator is available, then the statically allocated array is 0370 /// obsoleted. If a suitable allocator is not available, as with a 0371 /// NullAllocator, then the function returns NULL and a runtime error 0372 /// eventually occurs. 0373 /// \sa reallocate(), SecBlockWithHint 0374 pointer allocate(size_type size) 0375 { 0376 CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); 0377 0378 if (size <= S && !m_allocated) 0379 { 0380 m_allocated = true; 0381 return GetAlignedArray(); 0382 } 0383 else 0384 return m_fallbackAllocator.allocate(size); 0385 } 0386 0387 /// \brief Allocates a block of memory 0388 /// \param size the count elements in the memory block 0389 /// \param hint an unused hint 0390 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- 0391 /// based allocation at compile time. If size is less than or equal to 0392 /// S, then a pointer to the static array is returned. 0393 /// \details The class can grow its memory block at runtime if a suitable 0394 /// allocator is available. If size grows beyond S and a suitable 0395 /// allocator is available, then the statically allocated array is 0396 /// obsoleted. If a suitable allocator is not available, as with a 0397 /// NullAllocator, then the function returns NULL and a runtime error 0398 /// eventually occurs. 0399 /// \sa reallocate(), SecBlockWithHint 0400 pointer allocate(size_type size, const void *hint) 0401 { 0402 CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); 0403 0404 if (size <= S && !m_allocated) 0405 { 0406 m_allocated = true; 0407 return GetAlignedArray(); 0408 } 0409 else 0410 return m_fallbackAllocator.allocate(size, hint); 0411 } 0412 0413 /// \brief Deallocates a block of memory 0414 /// \param ptr a pointer to the memory block to deallocate 0415 /// \param size the count elements in the memory block 0416 /// \details The memory block is wiped or zeroized before deallocation. 0417 /// If the statically allocated memory block is active, then no 0418 /// additional actions are taken after the wipe. 0419 /// \details If a dynamic memory block is active, then the pointer and 0420 /// size are passed to the allocator for deallocation. 0421 void deallocate(void *ptr, size_type size) 0422 { 0423 // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL 0424 // pointers rather returning non-NULL 0-sized pointers. 0425 if (ptr == GetAlignedArray()) 0426 { 0427 // If the m_allocated assert fires then the bit twiddling for 0428 // GetAlignedArray() is probably incorrect for the platform. 0429 // Be sure to check CRYPTOPP_ALIGN_DATA(8). The platform may 0430 // not have a way to declaratively align data to 8. 0431 CRYPTOPP_ASSERT(size <= S); 0432 CRYPTOPP_ASSERT(m_allocated); 0433 m_allocated = false; 0434 SecureWipeArray(reinterpret_cast<pointer>(ptr), size); 0435 } 0436 else 0437 { 0438 if (ptr) 0439 m_fallbackAllocator.deallocate(ptr, size); 0440 } 0441 } 0442 0443 /// \brief Reallocates a block of memory 0444 /// \param oldPtr the previous allocation 0445 /// \param oldSize the size of the previous allocation 0446 /// \param newSize the new, requested size 0447 /// \param preserve flag that indicates if the old allocation should 0448 /// be preserved 0449 /// \return pointer to the new memory block 0450 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- 0451 /// based allocation at compile time. If size is less than or equal to 0452 /// S, then a pointer to the static array is returned. 0453 /// \details The class can grow its memory block at runtime if a suitable 0454 /// allocator is available. If size grows beyond S and a suitable 0455 /// allocator is available, then the statically allocated array is 0456 /// obsoleted. If a suitable allocator is not available, as with a 0457 /// NullAllocator, then the function returns NULL and a runtime error 0458 /// eventually occurs. 0459 /// \note size is the count of elements, and not the number of bytes. 0460 /// \sa reallocate(), SecBlockWithHint 0461 pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve) 0462 { 0463 if (oldPtr == GetAlignedArray() && newSize <= S) 0464 { 0465 CRYPTOPP_ASSERT(oldSize <= S); 0466 if (oldSize > newSize) 0467 SecureWipeArray(oldPtr+newSize, oldSize-newSize); 0468 return oldPtr; 0469 } 0470 0471 pointer newPtr = allocate(newSize, NULLPTR); 0472 if (preserve && newSize) 0473 { 0474 const size_type copySize = STDMIN(oldSize, newSize); 0475 if (newPtr && oldPtr) // GCC analyzer warning 0476 memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize); 0477 } 0478 deallocate(oldPtr, oldSize); 0479 return newPtr; 0480 } 0481 0482 CRYPTOPP_CONSTEXPR size_type max_size() const 0483 { 0484 return STDMAX(m_fallbackAllocator.max_size(), S); 0485 } 0486 0487 private: 0488 0489 #if CRYPTOPP_BOOL_ALIGN16 0490 0491 // There be demons here... We cannot use CRYPTOPP_ALIGN_DATA(16) 0492 // because linkers on 32-bit machines and some 64-bit machines 0493 // align the stack to 8-bytes or less, and not 16-bytes as 0494 // requested. We can only count on a smaller alignment. All 0495 // toolchains tested appear to honor CRYPTOPP_ALIGN_DATA(8). Also 0496 // see http://stackoverflow.com/a/1468656/608639. 0497 // 0498 // The 16-byte alignment is achieved by padding the requested 0499 // size with extra elements so we have at least 8-bytes of slack 0500 // to work with. Then the array pointer is moved to achieve a 0501 // 16-byte alignment. 0502 // 0503 // The additional 8-bytes introduces a small secondary issue. 0504 // The secondary issue is, a large T results in 0 = 8/sizeof(T). 0505 // The library is OK but users may hit it. So we need to guard 0506 // for a large T, and that is what the enum and PAD achieves. 0507 T* GetAlignedArray() { 0508 0509 // m_array is aligned on 8 byte boundaries due to 0510 // CRYPTOPP_ALIGN_DATA(8). If m_array%16 is 0, then the buffer 0511 // is 16-byte aligned and nothing needs to be done. if 0512 // m_array%16 is 8, then the buffer is not 16-byte aligned and 0513 // we need to add 8. 8 has that nice symmetric property. 0514 // 0515 // If we needed to use CRYPTOPP_ALIGN_DATA(4) due to toolchain 0516 // limitations, then the calculation would be slightly more 0517 // costly: ptr = m_array + (16 - (m_array % 16)) % 16; 0518 CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); 0519 int off = reinterpret_cast<uintptr_t>(m_array) % 16; 0520 byte* ptr = reinterpret_cast<byte*>(m_array) + off; 0521 0522 // Verify the 16-byte alignment. This is the point 0523 // of these extra gyrations. 0524 CRYPTOPP_ASSERT(IsAlignedOn(ptr, 16)); 0525 // Verify the lower bound. This is Issue 982/988. 0526 CRYPTOPP_ASSERT( 0527 reinterpret_cast<uintptr_t>(ptr) >= 0528 reinterpret_cast<uintptr_t>(m_array) 0529 ); 0530 // Verify the upper bound. Allocated array with 0531 // pad is large enough. 0532 CRYPTOPP_ASSERT( 0533 reinterpret_cast<uintptr_t>(ptr+S*sizeof(T)) <= 0534 reinterpret_cast<uintptr_t>(m_array+(S+PAD)) 0535 ); 0536 0537 // void* to silence Clang warnings 0538 return reinterpret_cast<T*>( 0539 static_cast<void*>(ptr) 0540 ); 0541 } 0542 0543 // PAD is elements, not bytes, and rounded up to ensure no overflow. 0544 enum { Q = sizeof(T), PAD = (Q >= 8) ? 1 : (Q >= 4) ? 2 : (Q >= 2) ? 4 : 8 }; 0545 // enum { Q = sizeof(T), PAD = (Q >= 16) ? 1 : (Q >= 8) ? 2 : (Q >= 4) ? 4 : (Q >= 2) ? 8 : 16 }; 0546 CRYPTOPP_ALIGN_DATA(8) T m_array[S+PAD]; 0547 0548 #else 0549 0550 // CRYPTOPP_BOOL_ALIGN16 is 0. If we are here then the user 0551 // probably compiled with CRYPTOPP_DISABLE_ASM. Normally we 0552 // would use the natural alignment of T. The problem we are 0553 // having is, some toolchains are changing the boundary for 0554 // 64-bit arrays. 64-bit elements require 8-byte alignment, 0555 // but the toolchain is laying the array out on a 4 byte 0556 // boundary. See GH #992 for mystery alignment, 0557 // https://github.com/weidai11/cryptopp/issues/992 0558 T* GetAlignedArray() {return m_array;} 0559 CRYPTOPP_ALIGN_DATA(8) T m_array[S]; 0560 0561 #endif 0562 0563 A m_fallbackAllocator; 0564 bool m_allocated; 0565 }; 0566 0567 /// \brief Static secure memory block with cleanup 0568 /// \tparam T class or type 0569 /// \tparam S fixed-size of the stack-based memory block, in elements 0570 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- 0571 /// based allocation at compile time. The class can grow its memory 0572 /// block at runtime if a suitable allocator is available. If size 0573 /// grows beyond S and a suitable allocator is available, then the 0574 /// statically allocated array is obsoleted. 0575 /// \note This allocator can't be used with standard collections because 0576 /// they require that all objects of the same allocator type are equivalent. 0577 template <class T, size_t S, class A> 0578 class FixedSizeAllocatorWithCleanup<T, S, A, false> : public AllocatorBase<T> 0579 { 0580 public: 0581 CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) 0582 0583 /// \brief Constructs a FixedSizeAllocatorWithCleanup 0584 FixedSizeAllocatorWithCleanup() : m_allocated(false) {} 0585 0586 /// \brief Allocates a block of memory 0587 /// \param size the count elements in the memory block 0588 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based 0589 /// allocation at compile time. If size is less than or equal to 0590 /// <tt>S</tt>, then a pointer to the static array is returned. 0591 /// \details The class can grow its memory block at runtime if a suitable 0592 /// allocator is available. If size grows beyond S and a suitable 0593 /// allocator is available, then the statically allocated array is 0594 /// obsoleted. If a suitable allocator is not available, as with a 0595 /// NullAllocator, then the function returns NULL and a runtime error 0596 /// eventually occurs. 0597 /// \sa reallocate(), SecBlockWithHint 0598 pointer allocate(size_type size) 0599 { 0600 CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); 0601 0602 if (size <= S && !m_allocated) 0603 { 0604 m_allocated = true; 0605 return GetAlignedArray(); 0606 } 0607 else 0608 return m_fallbackAllocator.allocate(size); 0609 } 0610 0611 /// \brief Allocates a block of memory 0612 /// \param size the count elements in the memory block 0613 /// \param hint an unused hint 0614 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- 0615 /// based allocation at compile time. If size is less than or equal to 0616 /// S, then a pointer to the static array is returned. 0617 /// \details The class can grow its memory block at runtime if a suitable 0618 /// allocator is available. If size grows beyond S and a suitable 0619 /// allocator is available, then the statically allocated array is 0620 /// obsoleted. If a suitable allocator is not available, as with a 0621 /// NullAllocator, then the function returns NULL and a runtime error 0622 /// eventually occurs. 0623 /// \sa reallocate(), SecBlockWithHint 0624 pointer allocate(size_type size, const void *hint) 0625 { 0626 if (size <= S && !m_allocated) 0627 { 0628 m_allocated = true; 0629 return GetAlignedArray(); 0630 } 0631 else 0632 return m_fallbackAllocator.allocate(size, hint); 0633 } 0634 0635 /// \brief Deallocates a block of memory 0636 /// \param ptr a pointer to the memory block to deallocate 0637 /// \param size the count elements in the memory block 0638 /// \details The memory block is wiped or zeroized before deallocation. 0639 /// If the statically allocated memory block is active, then no 0640 /// additional actions are taken after the wipe. 0641 /// \details If a dynamic memory block is active, then the pointer and 0642 /// size are passed to the allocator for deallocation. 0643 void deallocate(void *ptr, size_type size) 0644 { 0645 // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL 0646 // pointers rather returning non-NULL 0-sized pointers. 0647 if (ptr == GetAlignedArray()) 0648 { 0649 // If the m_allocated assert fires then 0650 // something overwrote the flag. 0651 CRYPTOPP_ASSERT(size <= S); 0652 CRYPTOPP_ASSERT(m_allocated); 0653 m_allocated = false; 0654 SecureWipeArray((pointer)ptr, size); 0655 } 0656 else 0657 { 0658 if (ptr) 0659 m_fallbackAllocator.deallocate(ptr, size); 0660 m_allocated = false; 0661 } 0662 } 0663 0664 /// \brief Reallocates a block of memory 0665 /// \param oldPtr the previous allocation 0666 /// \param oldSize the size of the previous allocation 0667 /// \param newSize the new, requested size 0668 /// \param preserve flag that indicates if the old allocation should 0669 /// be preserved 0670 /// \return pointer to the new memory block 0671 /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- 0672 /// based allocation at compile time. If size is less than or equal to 0673 /// S, then a pointer to the static array is returned. 0674 /// \details The class can grow its memory block at runtime if a suitable 0675 /// allocator is available. If size grows beyond S and a suitable 0676 /// allocator is available, then the statically allocated array is 0677 /// obsoleted. If a suitable allocator is not available, as with a 0678 /// NullAllocator, then the function returns NULL and a runtime error 0679 /// eventually occurs. 0680 /// \note size is the count of elements, and not the number of bytes. 0681 /// \sa reallocate(), SecBlockWithHint 0682 pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve) 0683 { 0684 if (oldPtr == GetAlignedArray() && newSize <= S) 0685 { 0686 CRYPTOPP_ASSERT(oldSize <= S); 0687 if (oldSize > newSize) 0688 SecureWipeArray(oldPtr+newSize, oldSize-newSize); 0689 return oldPtr; 0690 } 0691 0692 pointer newPtr = allocate(newSize, NULLPTR); 0693 if (preserve && newSize) 0694 { 0695 const size_type copySize = STDMIN(oldSize, newSize); 0696 if (newPtr && oldPtr) // GCC analyzer warning 0697 memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize); 0698 } 0699 deallocate(oldPtr, oldSize); 0700 return newPtr; 0701 } 0702 0703 CRYPTOPP_CONSTEXPR size_type max_size() const 0704 { 0705 return STDMAX(m_fallbackAllocator.max_size(), S); 0706 } 0707 0708 private: 0709 0710 // T_Align16 is false. Normally we would use the natural 0711 // alignment of T. The problem we are having is, some toolchains 0712 // are changing the boundary for 64-bit arrays. 64-bit elements 0713 // require 8-byte alignment, but the toolchain is laying the array 0714 // out on a 4 byte boundary. See GH #992 for mystery alignment, 0715 // https://github.com/weidai11/cryptopp/issues/992 0716 T* GetAlignedArray() {return m_array;} 0717 CRYPTOPP_ALIGN_DATA(8) T m_array[S]; 0718 0719 A m_fallbackAllocator; 0720 bool m_allocated; 0721 }; 0722 0723 /// \brief Secure memory block with allocator and cleanup 0724 /// \tparam T a class or type 0725 /// \tparam A AllocatorWithCleanup derived class for allocation and cleanup 0726 /// \sa <A HREF="https://www.cryptopp.com/wiki/SecBlock">SecBlock</A> 0727 /// on the Crypto++ wiki. 0728 /// \since Crypto++ 2.0 0729 template <class T, class A = AllocatorWithCleanup<T> > 0730 class SecBlock 0731 { 0732 public: 0733 typedef typename A::value_type value_type; 0734 typedef typename A::pointer iterator; 0735 typedef typename A::const_pointer const_iterator; 0736 typedef typename A::size_type size_type; 0737 0738 /// \brief Returns the maximum number of elements the block can hold 0739 /// \details <tt>ELEMS_MAX</tt> is the maximum number of elements the 0740 /// <tt>SecBlock</tt> can hold. The value of <tt>ELEMS_MAX</tt> is 0741 /// <tt>SIZE_MAX/sizeof(T)</tt>. <tt>std::numeric_limits</tt> was avoided 0742 /// due to lack of <tt>constexpr</tt>-ness in C++03 and below. 0743 /// \note In C++03 and below <tt>ELEMS_MAX</tt> is a static data member of type 0744 /// <tt>size_type</tt>. In C++11 and above <tt>ELEMS_MAX</tt> is an <tt>enum</tt> 0745 /// inheriting from <tt>size_type</tt>. In both cases <tt>ELEMS_MAX</tt> can be 0746 /// used before objects are fully constructed, and it does not suffer the 0747 /// limitations of class methods like <tt>max_size</tt>. 0748 /// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/346">Issue 346/CVE-2016-9939</A> 0749 /// \since Crypto++ 6.0 0750 #if defined(CRYPTOPP_DOXYGEN_PROCESSING) 0751 static const size_type ELEMS_MAX = ...; 0752 #elif defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION <= 1400) 0753 static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T); 0754 #elif defined(CRYPTOPP_CXX11_STRONG_ENUM) 0755 enum : size_type {ELEMS_MAX = A::ELEMS_MAX}; 0756 #else 0757 static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T); 0758 #endif 0759 0760 /// \brief Construct a SecBlock with space for size elements. 0761 /// \param size the size of the allocation, in elements 0762 /// \throw std::bad_alloc 0763 /// \details The elements are not initialized. 0764 /// \since Crypto++ 2.0 0765 /// \note size is the count of elements, and not the number of bytes 0766 explicit SecBlock(size_type size=0) 0767 : m_mark(ELEMS_MAX), m_size(size), m_ptr(m_alloc.allocate(size, NULLPTR)) { } 0768 0769 /// \brief Copy construct a SecBlock from another SecBlock 0770 /// \param t the other SecBlock 0771 /// \throw std::bad_alloc 0772 /// \since Crypto++ 2.0 0773 SecBlock(const SecBlock<T, A> &t) 0774 : m_mark(t.m_mark), m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULLPTR)) { 0775 CRYPTOPP_ASSERT((!t.m_ptr && !m_size) || (t.m_ptr && m_size)); 0776 if (m_ptr && t.m_ptr) 0777 memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); 0778 } 0779 0780 /// \brief Construct a SecBlock from an array of elements. 0781 /// \param ptr a pointer to an array of T 0782 /// \param len the number of elements in the memory block 0783 /// \throw std::bad_alloc 0784 /// \details If <tt>ptr!=NULL</tt> and <tt>len!=0</tt>, then the block is initialized from the pointer 0785 /// <tt>ptr</tt>. If <tt>ptr==NULL</tt> and <tt>len!=0</tt>, then the block is initialized to 0. 0786 /// Otherwise, the block is empty and not initialized. 0787 /// \since Crypto++ 2.0 0788 /// \note size is the count of elements, and not the number of bytes 0789 SecBlock(const T *ptr, size_type len) 0790 : m_mark(ELEMS_MAX), m_size(len), m_ptr(m_alloc.allocate(len, NULLPTR)) { 0791 CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size)); 0792 if (m_ptr && ptr) 0793 memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T)); 0794 else if (m_ptr && m_size) 0795 std::memset(m_ptr, 0, m_size*sizeof(T)); 0796 } 0797 0798 ~SecBlock() 0799 {m_alloc.deallocate(m_ptr, STDMIN(m_size, m_mark));} 0800 0801 #ifdef __BORLANDC__ 0802 /// \brief Cast operator 0803 /// \return block pointer cast to non-const <tt>T *</tt> 0804 /// \since Crypto++ 2.0 0805 operator T *() const 0806 {return (T*)m_ptr;} 0807 #else 0808 /// \brief Cast operator 0809 /// \return block pointer cast to <tt>const void *</tt> 0810 /// \since Crypto++ 2.0 0811 operator const void *() const 0812 {return m_ptr;} 0813 0814 /// \brief Cast operator 0815 /// \return block pointer cast to non-const <tt>void *</tt> 0816 /// \since Crypto++ 2.0 0817 operator void *() 0818 {return m_ptr;} 0819 0820 /// \brief Cast operator 0821 /// \return block pointer cast to <tt>const T *</tt> 0822 /// \since Crypto++ 2.0 0823 operator const T *() const 0824 {return m_ptr;} 0825 0826 /// \brief Cast operator 0827 /// \return block pointer cast to non-const <tt>T *</tt> 0828 /// \since Crypto++ 2.0 0829 operator T *() 0830 {return m_ptr;} 0831 #endif 0832 0833 /// \brief Provides an iterator pointing to the first element in the memory block 0834 /// \return iterator pointing to the first element in the memory block 0835 /// \since Crypto++ 2.0 0836 iterator begin() 0837 {return m_ptr;} 0838 /// \brief Provides a constant iterator pointing to the first element in the memory block 0839 /// \return constant iterator pointing to the first element in the memory block 0840 /// \since Crypto++ 2.0 0841 const_iterator begin() const 0842 {return m_ptr;} 0843 /// \brief Provides an iterator pointing beyond the last element in the memory block 0844 /// \return iterator pointing beyond the last element in the memory block 0845 /// \since Crypto++ 2.0 0846 iterator end() 0847 {return m_ptr+m_size;} 0848 /// \brief Provides a constant iterator pointing beyond the last element in the memory block 0849 /// \return constant iterator pointing beyond the last element in the memory block 0850 /// \since Crypto++ 2.0 0851 const_iterator end() const 0852 {return m_ptr+m_size;} 0853 0854 /// \brief Provides a pointer to the first element in the memory block 0855 /// \return pointer to the first element in the memory block 0856 /// \since Crypto++ 2.0 0857 typename A::pointer data() {return m_ptr;} 0858 /// \brief Provides a pointer to the first element in the memory block 0859 /// \return constant pointer to the first element in the memory block 0860 /// \since Crypto++ 2.0 0861 typename A::const_pointer data() const {return m_ptr;} 0862 0863 /// \brief Provides the count of elements in the SecBlock 0864 /// \return number of elements in the memory block 0865 /// \note the return value is the count of elements, and not the number of bytes 0866 /// \since Crypto++ 2.0 0867 size_type size() const {return m_size;} 0868 /// \brief Determines if the SecBlock is empty 0869 /// \return true if number of elements in the memory block is 0, false otherwise 0870 /// \since Crypto++ 2.0 0871 bool empty() const {return m_size == 0;} 0872 0873 /// \brief Provides a byte pointer to the first element in the memory block 0874 /// \return byte pointer to the first element in the memory block 0875 /// \since Crypto++ 2.0 0876 byte * BytePtr() {return (byte *)m_ptr;} 0877 /// \brief Return a byte pointer to the first element in the memory block 0878 /// \return constant byte pointer to the first element in the memory block 0879 /// \since Crypto++ 2.0 0880 const byte * BytePtr() const {return (const byte *)m_ptr;} 0881 /// \brief Provides the number of bytes in the SecBlock 0882 /// \return the number of bytes in the memory block 0883 /// \note the return value is the number of bytes, and not count of elements. 0884 /// \since Crypto++ 2.0 0885 size_type SizeInBytes() const {return m_size*sizeof(T);} 0886 0887 /// \brief Set contents and size from an array 0888 /// \param ptr a pointer to an array of T 0889 /// \param len the number of elements in the memory block 0890 /// \details The array pointed to by <tt>ptr</tt> must be distinct 0891 /// from this SecBlock because Assign() calls New() and then std::memcpy(). 0892 /// The call to New() will invalidate all pointers and iterators, like 0893 /// the pointer returned from data(). 0894 /// \details If the memory block is reduced in size, then the reclaimed 0895 /// memory is set to 0. If an assignment occurs, then Assign() resets 0896 /// the element count after the previous block is zeroized. 0897 /// \since Crypto++ 2.0 0898 void Assign(const T *ptr, size_type len) 0899 { 0900 New(len); 0901 if (m_ptr && ptr) // GCC analyzer warning 0902 memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T)); 0903 m_mark = ELEMS_MAX; 0904 } 0905 0906 /// \brief Set contents from a value 0907 /// \param count the number of values to copy 0908 /// \param value the value, repeated count times 0909 /// \details If the memory block is reduced in size, then the reclaimed 0910 /// memory is set to 0. If an assignment occurs, then Assign() resets 0911 /// the element count after the previous block is zeroized. 0912 /// \since Crypto++ 6.0 0913 void Assign(size_type count, T value) 0914 { 0915 New(count); 0916 for (size_t i=0; i<count; ++i) 0917 m_ptr[i] = value; 0918 m_mark = ELEMS_MAX; 0919 } 0920 0921 /// \brief Copy contents from another SecBlock 0922 /// \param t the other SecBlock 0923 /// \details Assign checks for self assignment. 0924 /// \details If the memory block is reduced in size, then the reclaimed 0925 /// memory is set to 0. If an assignment occurs, then Assign() resets 0926 /// the element count after the previous block is zeroized. 0927 /// \since Crypto++ 2.0 0928 void Assign(const SecBlock<T, A> &t) 0929 { 0930 if (this != &t) 0931 { 0932 New(t.m_size); 0933 if (m_ptr && t.m_ptr) // GCC analyzer warning 0934 memcpy_s(m_ptr, m_size*sizeof(T), t, t.m_size*sizeof(T)); 0935 } 0936 m_mark = ELEMS_MAX; 0937 } 0938 0939 /// \brief Append contents from an array 0940 /// \param ptr a pointer to an array of T 0941 /// \param len the number of elements in the memory block 0942 /// \throw InvalidArgument if resulting size would overflow 0943 /// \details The array pointed to by <tt>ptr</tt> must be distinct 0944 /// from this SecBlock because Append() calls Grow() and then std::memcpy(). 0945 /// The call to Grow() will invalidate all pointers and iterators, like 0946 /// the pointer returned from data(). 0947 /// \details Append() may be less efficient than a ByteQueue because 0948 /// Append() must Grow() the internal array and then copy elements. 0949 /// The ByteQueue can copy elements without growing. 0950 /// \sa ByteQueue 0951 /// \since Crypto++ 8.6 0952 void Append(const T *ptr, size_type len) 0953 { 0954 if (ELEMS_MAX - m_size < len) 0955 throw InvalidArgument("SecBlock: buffer overflow"); 0956 0957 const size_type oldSize = m_size; 0958 Grow(m_size+len); 0959 if (m_ptr && ptr) // GCC analyzer warning 0960 memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), ptr, len*sizeof(T)); 0961 m_mark = ELEMS_MAX; 0962 } 0963 0964 /// \brief Append contents from another SecBlock 0965 /// \param t the other SecBlock 0966 /// \throw InvalidArgument if resulting size would overflow 0967 /// \details Internally, this SecBlock calls Grow() and then appends t. 0968 /// \details Append() may be less efficient than a ByteQueue because 0969 /// Append() must Grow() the internal array and then copy elements. 0970 /// The ByteQueue can copy elements without growing. 0971 /// \sa ByteQueue 0972 /// \since Crypto++ 8.6 0973 void Append(const SecBlock<T, A> &t) 0974 { 0975 if (ELEMS_MAX - m_size < t.m_size) 0976 throw InvalidArgument("SecBlock: buffer overflow"); 0977 0978 const size_type oldSize = m_size; 0979 if (this != &t) // s += t 0980 { 0981 Grow(m_size+t.m_size); 0982 if (m_ptr && t.m_ptr) // GCC analyzer warning 0983 memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); 0984 } 0985 else // t += t 0986 { 0987 Grow(m_size*2); 0988 if (m_ptr) // GCC analyzer warning 0989 memmove_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), m_ptr, oldSize*sizeof(T)); 0990 } 0991 m_mark = ELEMS_MAX; 0992 } 0993 0994 /// \brief Append contents from a value 0995 /// \param count the number of values to copy 0996 /// \param value the value, repeated count times 0997 /// \throw InvalidArgument if resulting size would overflow 0998 /// \details Internally, this SecBlock calls Grow() and then appends value. 0999 /// \details Append() may be less efficient than a ByteQueue because 1000 /// Append() must Grow() the internal array and then copy elements. 1001 /// The ByteQueue can copy elements without growing. 1002 /// \sa ByteQueue 1003 /// \since Crypto++ 8.6 1004 void Append(size_type count, T value) 1005 { 1006 if (ELEMS_MAX - m_size < count) 1007 throw InvalidArgument("SecBlock: buffer overflow"); 1008 1009 const size_type oldSize = m_size; 1010 Grow(m_size+count); 1011 for (size_t i=oldSize; i<oldSize+count; ++i) 1012 m_ptr[i] = value; 1013 m_mark = ELEMS_MAX; 1014 } 1015 1016 /// \brief Sets the number of elements to zeroize 1017 /// \param count the number of elements 1018 /// \details SetMark is a remediation for Issue 346/CVE-2016-9939 while 1019 /// preserving the streaming interface. The <tt>count</tt> controls the number of 1020 /// elements zeroized, which can be less than <tt>size</tt> or 0. 1021 /// \details An internal variable, <tt>m_mark</tt>, is initialized to the maximum number 1022 /// of elements. The maximum number of elements is <tt>ELEMS_MAX</tt>. Deallocation 1023 /// triggers a zeroization, and the number of elements zeroized is 1024 /// <tt>STDMIN(m_size, m_mark)</tt>. After zeroization, the memory is returned to the 1025 /// system. 1026 /// \details The ASN.1 decoder uses SetMark() to set the element count to 0 1027 /// before throwing an exception. In this case, the attacker provides a large 1028 /// BER encoded length (say 64MB) but only a small number of content octets 1029 /// (say 16). If the allocator zeroized all 64MB, then a transient DoS could 1030 /// occur as CPU cycles are spent zeroizing uninitialized memory. 1031 /// \details Generally speaking, any operation which changes the size of the SecBlock 1032 /// results in the mark being reset to <tt>ELEMS_MAX</tt>. In particular, if Assign(), 1033 /// New(), Grow(), CleanNew(), CleanGrow() are called, then the count is reset to 1034 /// <tt>ELEMS_MAX</tt>. The list is not exhaustive. 1035 /// \since Crypto++ 6.0 1036 /// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/346">Issue 346/CVE-2016-9939</A> 1037 void SetMark(size_t count) {m_mark = count;} 1038 1039 /// \brief Assign contents from another SecBlock 1040 /// \param t the other SecBlock 1041 /// \return reference to this SecBlock 1042 /// \details Internally, operator=() calls Assign(). 1043 /// \details If the memory block is reduced in size, then the reclaimed 1044 /// memory is set to 0. If an assignment occurs, then Assign() resets 1045 /// the element count after the previous block is zeroized. 1046 /// \since Crypto++ 2.0 1047 SecBlock<T, A>& operator=(const SecBlock<T, A> &t) 1048 { 1049 // Assign guards for self-assignment 1050 Assign(t); 1051 return *this; 1052 } 1053 1054 /// \brief Append contents from another SecBlock 1055 /// \param t the other SecBlock 1056 /// \return reference to this SecBlock 1057 /// \details Internally, operator+=() calls Append(). 1058 /// \since Crypto++ 2.0 1059 SecBlock<T, A>& operator+=(const SecBlock<T, A> &t) 1060 { 1061 // Append guards for overflow 1062 Append(t); 1063 return *this; 1064 } 1065 1066 /// \brief Construct a SecBlock from this and another SecBlock 1067 /// \param t the other SecBlock 1068 /// \return a newly constructed SecBlock that is a concatenation of this 1069 /// and t. 1070 /// \details Internally, a new SecBlock is created from this and a 1071 /// concatenation of t. 1072 /// \since Crypto++ 2.0 1073 SecBlock<T, A> operator+(const SecBlock<T, A> &t) 1074 { 1075 CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size)); 1076 CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size)); 1077 if(!t.m_size) return SecBlock(*this); 1078 1079 SecBlock<T, A> result(m_size+t.m_size); 1080 if (m_size) 1081 memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T)); 1082 if (result.m_ptr && t.m_ptr) // GCC analyzer warning 1083 memcpy_s(result.m_ptr+m_size, (result.m_size-m_size)*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); 1084 return result; 1085 } 1086 1087 /// \brief Bitwise compare two SecBlocks 1088 /// \param t the other SecBlock 1089 /// \return true if the size and bits are equal, false otherwise 1090 /// \details Uses a constant time compare if the arrays are equal size. 1091 /// The constant time compare is VerifyBufsEqual() found in 1092 /// <tt>misc.h</tt>. 1093 /// \sa operator!=() 1094 /// \since Crypto++ 2.0 1095 bool operator==(const SecBlock<T, A> &t) const 1096 { 1097 return m_size == t.m_size && VerifyBufsEqual( 1098 reinterpret_cast<const byte*>(m_ptr), 1099 reinterpret_cast<const byte*>(t.m_ptr), m_size*sizeof(T)); 1100 } 1101 1102 /// \brief Bitwise compare two SecBlocks 1103 /// \param t the other SecBlock 1104 /// \return true if the size and bits are equal, false otherwise 1105 /// \details Uses a constant time compare if the arrays are equal size. 1106 /// The constant time compare is VerifyBufsEqual() found in 1107 /// <tt>misc.h</tt>. 1108 /// \details Internally, operator!=() returns the inverse of operator==(). 1109 /// \sa operator==() 1110 /// \since Crypto++ 2.0 1111 bool operator!=(const SecBlock<T, A> &t) const 1112 { 1113 return !operator==(t); 1114 } 1115 1116 /// \brief Change size without preserving contents 1117 /// \param newSize the new size of the memory block 1118 /// \details Old content is not preserved. If the memory block is 1119 /// reduced in size, then the reclaimed content is set to 0. If the 1120 /// memory block grows in size, then the new memory is initialized 1121 /// to 0. New() resets the element count after the previous block 1122 /// is zeroized. 1123 /// \details Internally, this SecBlock calls reallocate(). 1124 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() 1125 /// \since Crypto++ 2.0 1126 void New(size_type newSize) 1127 { 1128 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false); 1129 m_size = newSize; 1130 m_mark = ELEMS_MAX; 1131 } 1132 1133 /// \brief Change size without preserving contents 1134 /// \param newSize the new size of the memory block 1135 /// \details Old content is not preserved. If the memory block is 1136 /// reduced in size, then the reclaimed content is set to 0. If the 1137 /// memory block grows in size, then the new memory is initialized 1138 /// to 0. CleanNew() resets the element count after the previous 1139 /// block is zeroized. 1140 /// \details Internally, this SecBlock calls New(). 1141 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() 1142 /// \since Crypto++ 2.0 1143 void CleanNew(size_type newSize) 1144 { 1145 New(newSize); 1146 if (m_ptr) {memset_z(m_ptr, 0, m_size*sizeof(T));} 1147 m_mark = ELEMS_MAX; 1148 } 1149 1150 /// \brief Change size and preserve contents 1151 /// \param newSize the new size of the memory block 1152 /// \details Old content is preserved. New content is not initialized. 1153 /// \details Internally, this SecBlock calls reallocate() when size must 1154 /// increase. If the size does not increase, then CleanGrow() does not 1155 /// take action. If the size must change, then use resize(). CleanGrow() 1156 /// resets the element count after the previous block is zeroized. 1157 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() 1158 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() 1159 /// \since Crypto++ 2.0 1160 void Grow(size_type newSize) 1161 { 1162 if (newSize > m_size) 1163 { 1164 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); 1165 m_size = newSize; 1166 } 1167 m_mark = ELEMS_MAX; 1168 } 1169 1170 /// \brief Change size and preserve contents 1171 /// \param newSize the new size of the memory block 1172 /// \details Old content is preserved. New content is initialized to 0. 1173 /// \details Internally, this SecBlock calls reallocate() when size must 1174 /// increase. If the size does not increase, then CleanGrow() does not 1175 /// take action. If the size must change, then use resize(). CleanGrow() 1176 /// resets the element count after the previous block is zeroized. 1177 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() 1178 /// \since Crypto++ 2.0 1179 void CleanGrow(size_type newSize) 1180 { 1181 if (newSize > m_size) 1182 { 1183 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); 1184 memset_z(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T)); 1185 m_size = newSize; 1186 } 1187 m_mark = ELEMS_MAX; 1188 } 1189 1190 /// \brief Change size and preserve contents 1191 /// \param newSize the new size of the memory block 1192 /// \details Old content is preserved. If the memory block grows in size, then 1193 /// new memory is not initialized. resize() resets the element count after 1194 /// the previous block is zeroized. 1195 /// \details Internally, this SecBlock calls reallocate(). 1196 /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() 1197 /// \since Crypto++ 2.0 1198 void resize(size_type newSize) 1199 { 1200 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); 1201 m_size = newSize; 1202 m_mark = ELEMS_MAX; 1203 } 1204 1205 /// \brief Swap contents with another SecBlock 1206 /// \param b the other SecBlock 1207 /// \details Internally, std::swap() is called on m_alloc, m_size and m_ptr. 1208 /// \since Crypto++ 2.0 1209 void swap(SecBlock<T, A> &b) 1210 { 1211 // Swap must occur on the allocator in case its FixedSize that spilled into the heap. 1212 std::swap(m_alloc, b.m_alloc); 1213 std::swap(m_mark, b.m_mark); 1214 std::swap(m_size, b.m_size); 1215 std::swap(m_ptr, b.m_ptr); 1216 } 1217 1218 protected: 1219 A m_alloc; 1220 size_type m_mark, m_size; 1221 T *m_ptr; 1222 }; 1223 1224 #ifdef CRYPTOPP_DOXYGEN_PROCESSING 1225 /// \brief \ref SecBlock "SecBlock<byte>" typedef. 1226 class SecByteBlock : public SecBlock<byte> {}; 1227 /// \brief \ref SecBlock "SecBlock<word>" typedef. 1228 class SecWordBlock : public SecBlock<word> {}; 1229 /// \brief SecBlock using \ref AllocatorWithCleanup "AllocatorWithCleanup<byte, true>" typedef 1230 class AlignedSecByteBlock : public SecBlock<byte, AllocatorWithCleanup<byte, true> > {}; 1231 #else 1232 typedef SecBlock<byte> SecByteBlock; 1233 typedef SecBlock<word> SecWordBlock; 1234 typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock; 1235 #endif 1236 1237 // No need for move semantics on derived class *if* the class does not add any 1238 // data members; see http://stackoverflow.com/q/31755703, and Rule of {0|3|5}. 1239 1240 /// \brief Fixed size stack-based SecBlock 1241 /// \tparam T class or type 1242 /// \tparam S fixed-size of the stack-based memory block, in elements 1243 /// \tparam A AllocatorBase derived class for allocation and cleanup 1244 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> > 1245 class FixedSizeSecBlock : public SecBlock<T, A> 1246 { 1247 public: 1248 /// \brief Construct a FixedSizeSecBlock 1249 explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {} 1250 }; 1251 1252 /// \brief Fixed size stack-based SecBlock with 16-byte alignment 1253 /// \tparam T class or type 1254 /// \tparam S fixed-size of the stack-based memory block, in elements 1255 /// \tparam T_Align16 boolean that determines whether allocations should be 1256 /// aligned on a 16-byte boundary 1257 template <class T, unsigned int S, bool T_Align16 = true> 1258 class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> > 1259 { 1260 }; 1261 1262 /// \brief Stack-based SecBlock that grows into the heap 1263 /// \tparam T class or type 1264 /// \tparam S fixed-size of the stack-based memory block, in elements 1265 /// \tparam A AllocatorBase derived class for allocation and cleanup 1266 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > > 1267 class SecBlockWithHint : public SecBlock<T, A> 1268 { 1269 public: 1270 /// construct a SecBlockWithHint with a count of elements 1271 explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {} 1272 }; 1273 1274 template<class T, bool A, class V, bool B> 1275 inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<V, B>&) {return (true);} 1276 template<class T, bool A, class V, bool B> 1277 inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<V, B>&) {return (false);} 1278 1279 NAMESPACE_END 1280 1281 NAMESPACE_BEGIN(std) 1282 1283 /// \brief Swap two SecBlocks 1284 /// \tparam T class or type 1285 /// \tparam A AllocatorBase derived class for allocation and cleanup 1286 /// \param a the first SecBlock 1287 /// \param b the second SecBlock 1288 template <class T, class A> 1289 inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b) 1290 { 1291 a.swap(b); 1292 } 1293 1294 #if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES)) 1295 // working for STLport 5.1.3 and MSVC 6 SP5 1296 template <class _Tp1, class _Tp2> 1297 inline CryptoPP::AllocatorWithCleanup<_Tp2>& 1298 __stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*) 1299 { 1300 return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a); 1301 } 1302 #endif 1303 1304 NAMESPACE_END 1305 1306 #if defined(CRYPTOPP_MSC_VERSION) 1307 # pragma warning(pop) 1308 #endif 1309 1310 #endif
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |