Back to home page

EIC code displayed by LXR

 
 

    


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