diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /external/crypto++-5.6.3/secblock.h | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'external/crypto++-5.6.3/secblock.h')
| -rw-r--r-- | external/crypto++-5.6.3/secblock.h | 804 |
1 files changed, 804 insertions, 0 deletions
diff --git a/external/crypto++-5.6.3/secblock.h b/external/crypto++-5.6.3/secblock.h new file mode 100644 index 0000000..ef8cab1 --- /dev/null +++ b/external/crypto++-5.6.3/secblock.h @@ -0,0 +1,804 @@ +// secblock.h - written and placed in the public domain by Wei Dai + +//! \file secblock.h +//! \brief Classes and functions for secure memory allocations. + +#ifndef CRYPTOPP_SECBLOCK_H +#define CRYPTOPP_SECBLOCK_H + +#include "config.h" +#include "stdcpp.h" +#include "misc.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4700) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6386) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** secure memory allocation *************** + +//! \class AllocatorBase +//! \brief Base class for all allocators used by SecBlock +//! \tparam T the class or type +template<class T> +class AllocatorBase +{ +public: + typedef T value_type; + typedef size_t size_type; +#ifdef CRYPTOPP_MSVCRT6 + typedef ptrdiff_t difference_type; +#else + typedef std::ptrdiff_t difference_type; +#endif + typedef T * pointer; + typedef const T * const_pointer; + typedef T & reference; + typedef const T & const_reference; + + pointer address(reference r) const {return (&r);} + const_pointer address(const_reference r) const {return (&r); } + void construct(pointer p, const T& val) {new (p) T(val);} + void destroy(pointer p) {CRYPTOPP_UNUSED(p); p->~T();} + + //! \brief Returns the maximum number of elements the allocator can provide + //! \returns the maximum number of elements the allocator can provide + //! \details Internally, preprocessor macros are used rather than std::numeric_limits + //! because the latter is \a not a \a constexpr. Some compilers, like Clang, do not + //! optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear + //! to optimize it well in either form. + size_type max_size() const {return (SIZE_MAX/sizeof(T));} + +#if defined(CRYPTOPP_CXX11_VARIADIC_TEMPLATES) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + + //! \brief Constructs a new U using variadic arguments + //! \tparam U the type to be forwarded + //! \tparam Args the arguments to be forwarded + //! \param ptr pointer to type U + //! \param args variadic arguments + //! \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES + //! is defined. The define is controlled by compiler versions detected in config.h. + template<typename U, typename... Args> + void construct(U* ptr, Args&&... args) {::new ((void*)ptr) U(std::forward<Args>(args)...);} + + //! \brief Destroys an U constructed with variadic arguments + //! \tparam U the type to be forwarded + //! \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES + //! is defined. The define is controlled by compiler versions detected in config.h. + template<typename U> + void destroy(U* ptr) {if(ptr) ptr->~U();} + +#endif + +protected: + + //! \brief Verifies the allocator can satisfy a request based on size + //! \param size the number of elements + //! \throws InvalidArgument + //! \details CheckSize verifies the number of elements requested is valid. + //! \details If size is greater than max_size(), then InvalidArgument is thrown. + //! The library throws InvalidArgument if the size is too large to satisfy. + //! \details Internally, preprocessor macros are used rather than std::numeric_limits + //! because the latter is \a not a \a constexpr. Some compilers, like Clang, do not + //! optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear + //! to optimize it well in either form. + //! \note size is the count of elements, and not the number of bytes + static void CheckSize(size_t size) + { + // C++ throws std::bad_alloc (C++03) or std::bad_array_new_length (C++11) here. + if (size > (SIZE_MAX/sizeof(T))) + throw InvalidArgument("AllocatorBase: requested size would cause integer overflow"); + } +}; + +#define CRYPTOPP_INHERIT_ALLOCATOR_TYPES \ +typedef typename AllocatorBase<T>::value_type value_type;\ +typedef typename AllocatorBase<T>::size_type size_type;\ +typedef typename AllocatorBase<T>::difference_type difference_type;\ +typedef typename AllocatorBase<T>::pointer pointer;\ +typedef typename AllocatorBase<T>::const_pointer const_pointer;\ +typedef typename AllocatorBase<T>::reference reference;\ +typedef typename AllocatorBase<T>::const_reference const_reference; + +//! \brief Reallocation function +//! \tparam T the class or type +//! \tparam A the class or type's allocator +//! \param alloc the allocator +//! \param oldPtr the previous allocation +//! \param oldSize the size of the previous allocation +//! \param newSize the new, requested size +//! \param preserve flag that indicates if the old allocation should be preserved +//! \note oldSize and newSize are the count of elements, and not the +//! number of bytes. +template <class T, class A> +typename A::pointer StandardReallocate(A& alloc, T *oldPtr, typename A::size_type oldSize, typename A::size_type newSize, bool preserve) +{ + assert((oldPtr && oldSize) || !(oldPtr || oldSize)); + if (oldSize == newSize) + return oldPtr; + + if (preserve) + { + typename A::pointer newPointer = alloc.allocate(newSize, NULL); + const size_t copySize = STDMIN(oldSize, newSize) * sizeof(T); + + if (oldPtr && newPointer) {memcpy_s(newPointer, copySize, oldPtr, copySize);} + alloc.deallocate(oldPtr, oldSize); + return newPointer; + } + else + { + alloc.deallocate(oldPtr, oldSize); + return alloc.allocate(newSize, NULL); + } +} + +//! \class AllocatorWithCleanup +//! \brief Allocates a block of memory with cleanup +//! \tparam T class or type +//! \tparam T_Align16 boolean that determines whether allocations should be aligned on 16-byte boundaries +//! \details If T_Align16 is true, then AllocatorWithCleanup calls AlignedAllocate() +//! for memory allocations. If T_Align16 is false, then AllocatorWithCleanup() calls +//! UnalignedAllocate() for memory allocations. +//! \details Template parameter T_Align16 is effectively controlled by cryptlib.h and mirrors +//! CRYPTOPP_BOOL_ALIGN16. CRYPTOPP_BOOL_ALIGN16 is often used as the template parameter. +template <class T, bool T_Align16 = false> +class AllocatorWithCleanup : public AllocatorBase<T> +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + //! \brief Allocates a block of memory + //! \param ptr the size of the allocation + //! \param size the size of the allocation + //! \returns a memory block + //! \throws InvalidArgument + //! \details allocate() first checks the size of the request. If it is non-0 + //! and less than max_size(), then an attempt is made to fulfill the request using either + //! AlignedAllocate() or UnalignedAllocate(). + //! \details AlignedAllocate() is used if T_Align16 is true. + //! UnalignedAllocate() used if T_Align16 is false. + //! \details This is the C++ *Placement New* operator. ptr is not used, and the function + //! asserts in Debug builds if ptr is non-NULL. + //! \sa CallNewHandler() for the methods used to recover from a failed + //! allocation attempt. + //! \note size is the count of elements, and not the number of bytes + pointer allocate(size_type size, const void *ptr = NULL) + { + CRYPTOPP_UNUSED(ptr); assert(ptr == NULL); + this->CheckSize(size); + if (size == 0) + return NULL; + +#if CRYPTOPP_BOOL_ALIGN16 + // TODO: should this need the test 'size*sizeof(T) >= 16'? + if (T_Align16 && size*sizeof(T) >= 16) + return (pointer)AlignedAllocate(size*sizeof(T)); +#endif + + return (pointer)UnalignedAllocate(size*sizeof(T)); + } + + //! \brief Deallocates a block of memory + //! \param ptr the size of the allocation + //! \param size the size of the allocation + //! \details Internally, SecureWipeArray() is called before deallocating the memory. + //! Once the memory block is wiped or zeroized, AlignedDeallocate() or + //! UnalignedDeallocate() is called. + //! \details AlignedDeallocate() is used if T_Align16 is true. + //! UnalignedDeallocate() used if T_Align16 is false. + void deallocate(void *ptr, size_type size) + { + assert((ptr && size) || !(ptr || size)); + SecureWipeArray((pointer)ptr, size); + +#if CRYPTOPP_BOOL_ALIGN16 + if (T_Align16 && size*sizeof(T) >= 16) + return AlignedDeallocate(ptr); +#endif + + UnalignedDeallocate(ptr); + } + + //! \brief Reallocates a block of memory + //! \param oldPtr the previous allocation + //! \param oldSize the size of the previous allocation + //! \param newSize the new, requested size + //! \param preserve flag that indicates if the old allocation should be preserved + //! \returns pointer to the new memory block + //! \details Internally, reallocate() calls StandardReallocate(). + //! \details If preserve is true, then index 0 is used to begin copying the + //! old memory block to the new one. If the block grows, then the old array + //! is copied in its entirety. If the block shrinks, then only newSize + //! elements are copied from the old block to the new one. + //! \note oldSize and newSize are the count of elements, and not the + //! number of bytes. + pointer reallocate(T *oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + assert((oldPtr && oldSize) || !(oldPtr || oldSize)); + return StandardReallocate(*this, oldPtr, oldSize, newSize, preserve); + } + + // VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a + // template class member called rebind". + template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; }; +#if _MSC_VER >= 1500 + AllocatorWithCleanup() {} + template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {} +#endif +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>; +#if CRYPTOPP_BOOL_X86 +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>; // for Integer +#endif + +//! \class NullAllocator +//! \brief NULL allocator +//! \tparam T class or type +//! \details A NullAllocator is useful for fixed-size, stack based allocations +//! (i.e., static arrays used by FixedSizeAllocatorWithCleanup). +//! \details A NullAllocator always returns 0 for max_size(), and always returns +//! NULL for allocation requests. Though the allocator does not allocate at +//! runtime, it does perform a secure wipe or zeroization during cleanup. +template <class T> +class NullAllocator : public AllocatorBase<T> +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + // TODO: should this return NULL or throw bad_alloc? Non-Windows C++ standard + // libraries always throw. And late mode Windows throws. Early model Windows + // (circa VC++ 6.0) returned NULL. + pointer allocate(size_type n, const void* unused = NULL) + { + CRYPTOPP_UNUSED(n); CRYPTOPP_UNUSED(unused); + assert(false); return NULL; + } + + void deallocate(void *p, size_type n) + { + CRYPTOPP_UNUSED(p); CRYPTOPP_UNUSED(n); + assert(false); + } + + size_type max_size() const {return 0;} +}; + +//! \class FixedSizeAllocatorWithCleanup +//! \brief Static secure memory block with cleanup +//! \tparam T class or type +//! \tparam S fixed-size of the stack-based memory block +//! \tparam A AllocatorBase derived class for allocation and cleanup +//! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- +//! based allocation at compile time. The class can grow its memory +//! block at runtime if a suitable allocator is available. If size +//! grows beyond S and a suitable allocator is available, then the +//! statically allocated array is obsoleted. +//! \note This allocator can't be used with standard collections because +//! they require that all objects of the same allocator type are equivalent. +template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false> +class FixedSizeAllocatorWithCleanup : public AllocatorBase<T> +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + //! \brief Constructs a FixedSizeAllocatorWithCleanup + FixedSizeAllocatorWithCleanup() : m_allocated(false) {} + + //! \brief Allocates a block of memory + //! \param size size of the memory block + //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + //! based allocation at compile time. If size is less than or equal to + //! S, then a pointer to the static array is returned. + //! \details The class can grow its memory block at runtime if a suitable + //! allocator is available. If size grows beyond S and a suitable + //! allocator is available, then the statically allocated array is + //! obsoleted. If a suitable allocator is \a not available, as with a + //! NullAllocator, then the function returns NULL and a runtime error + //! eventually occurs. + //! \note size is the count of elements, and not the number of bytes. + //! \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size) + { + assert(IsAlignedOn(m_array, 8)); + + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size); + } + + //! \brief Allocates a block of memory + //! \param size size of the memory block + //! \param hint an unused hint + //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + //! based allocation at compile time. If size is less than or equal to + //! S, then a pointer to the static array is returned. + //! \details The class can grow its memory block at runtime if a suitable + //! allocator is available. If size grows beyond S and a suitable + //! allocator is available, then the statically allocated array is + //! obsoleted. If a suitable allocator is \a not available, as with a + //! NullAllocator, then the function returns NULL and a runtime error + //! eventually occurs. + //! \note size is the count of elements, and not the number of bytes. + //! \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size, const void *hint) + { + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size, hint); + } + + //! \brief Deallocates a block of memory + //! \param ptr a pointer to the memory block to deallocate + //! \param size size of the memory block + //! \details The memory block is wiped or zeroized before deallocation. + //! If the statically allocated memory block is active, then no + //! additional actions are taken after the wipe. + //! \details If a dynamic memory block is active, then the pointer and + //! size are passed to the allocator for deallocation. + void deallocate(void *ptr, size_type size) + { + if (ptr == GetAlignedArray()) + { + assert(size <= S); + assert(m_allocated); + m_allocated = false; + SecureWipeArray((pointer)ptr, size); + } + else + m_fallbackAllocator.deallocate(ptr, size); + } + + //! \brief Reallocates a block of memory + //! \param oldPtr the previous allocation + //! \param oldSize the size of the previous allocation + //! \param newSize the new, requested size + //! \param preserve flag that indicates if the old allocation should be preserved + //! \returns pointer to the new memory block + //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + //! based allocation at compile time. If size is less than or equal to + //! S, then a pointer to the static array is returned. + //! \details The class can grow its memory block at runtime if a suitable + //! allocator is available. If size grows beyond S and a suitable + //! allocator is available, then the statically allocated array is + //! obsoleted. If a suitable allocator is \a not available, as with a + //! NullAllocator, then the function returns NULL and a runtime error + //! eventually occurs. + //! \note size is the count of elements, and not the number of bytes. + //! \sa reallocate(), SecBlockWithHint + pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + if (oldPtr == GetAlignedArray() && newSize <= S) + { + assert(oldSize <= S); + if (oldSize > newSize) + SecureWipeArray(oldPtr+newSize, oldSize-newSize); + return oldPtr; + } + + pointer newPointer = allocate(newSize, NULL); + if (preserve && newSize) + { + const size_t copySize = STDMIN(oldSize, newSize); + memcpy_s(newPointer, copySize, oldPtr, copySize); + } + deallocate(oldPtr, oldSize); + return newPointer; + } + + size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);} + +private: +#ifdef __BORLANDC__ + T* GetAlignedArray() {return m_array;} + T m_array[S]; +#else + T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16 && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;} + CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16 && T_Align16) ? S+8/sizeof(T) : S]; +#endif + A m_fallbackAllocator; + bool m_allocated; +}; + +//! \class SecBlock +//! \brief Secure memory block with allocator and cleanup +//! \tparam T a class or type +//! \tparam A AllocatorWithCleanup derived class for allocation and cleanup +template <class T, class A = AllocatorWithCleanup<T> > +class SecBlock +{ +public: + typedef typename A::value_type value_type; + typedef typename A::pointer iterator; + typedef typename A::const_pointer const_iterator; + typedef typename A::size_type size_type; + + //! \brief Construct a SecBlock with space for size elements. + //! \param size the number of elements in the allocation + //! \throws std::bad_alloc + //! \details The elements are not initialized. + //! \note size is the count of elements, and not the number of bytes + explicit SecBlock(size_type size=0) + : m_size(size), m_ptr(m_alloc.allocate(size, NULL)) { } + + //! \brief Copy construct a SecBlock from another SecBlock + //! \param t the other SecBlock + //! \throws std::bad_alloc + SecBlock(const SecBlock<T, A> &t) + : m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULL)) { + assert((!t.m_ptr && !m_size) || (t.m_ptr && m_size)); + if (t.m_ptr) {memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));} + } + + //! \brief Construct a SecBlock from an array of elements. + //! \param ptr a pointer to an array of T + //! \param len the number of elements in the memory block + //! \throws std::bad_alloc + //! \details If <tt>ptr!=NULL</tt> and <tt>len!=0</tt>, then the block is initialized from the pointer ptr. + //! If <tt>ptr==NULL</tt> and <tt>len!=0</tt>, then the block is initialized to 0. + //! Otherwise, the block is empty and uninitialized. + //! \note size is the count of elements, and not the number of bytes + SecBlock(const T *ptr, size_type len) + : m_size(len), m_ptr(m_alloc.allocate(len, NULL)) { + assert((!m_ptr && !m_size) || (m_ptr && m_size)); + if (ptr && m_ptr) + memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T)); + else if (m_size) + memset(m_ptr, 0, m_size*sizeof(T)); + } + + ~SecBlock() + {m_alloc.deallocate(m_ptr, m_size);} + +#ifdef __BORLANDC__ + operator T *() const + {return (T*)m_ptr;} +#else + operator const void *() const + {return m_ptr;} + operator void *() + {return m_ptr;} + + operator const T *() const + {return m_ptr;} + operator T *() + {return m_ptr;} +#endif + + //! \brief Provides an iterator pointing to the first element in the memory block + //! \returns iterator pointing to the first element in the memory block + iterator begin() + {return m_ptr;} + //! \brief Provides a constant iterator pointing to the first element in the memory block + //! \returns constant iterator pointing to the first element in the memory block + const_iterator begin() const + {return m_ptr;} + //! \brief Provides an iterator pointing beyond the last element in the memory block + //! \returns iterator pointing beyond the last element in the memory block + iterator end() + {return m_ptr+m_size;} + //! \brief Provides a constant iterator pointing beyond the last element in the memory block + //! \returns constant iterator pointing beyond the last element in the memory block + const_iterator end() const + {return m_ptr+m_size;} + + //! \brief Provides a pointer to the first element in the memory block + //! \returns pointer to the first element in the memory block + typename A::pointer data() {return m_ptr;} + //! \brief Provides a pointer to the first element in the memory block + //! \returns constant pointer to the first element in the memory block + typename A::const_pointer data() const {return m_ptr;} + + //! \brief Provides the count of elements in the SecBlock + //! \returns number of elements in the memory block + //! \note the return value is the count of elements, and not the number of bytes + size_type size() const {return m_size;} + //! \brief Determines if the SecBlock is empty + //! \returns true if number of elements in the memory block is 0, false otherwise + bool empty() const {return m_size == 0;} + + //! \brief Provides a byte pointer to the first element in the memory block + //! \returns byte pointer to the first element in the memory block + byte * BytePtr() {return (byte *)m_ptr;} + //! \brief Return a byte pointer to the first element in the memory block + //! \returns constant byte pointer to the first element in the memory block + const byte * BytePtr() const {return (const byte *)m_ptr;} + //! \brief Provides the number of bytes in the SecBlock + //! \return the number of bytes in the memory block + //! \note the return value is the number of bytes, and not count of elements. + size_type SizeInBytes() const {return m_size*sizeof(T);} + + //! \brief Set contents and size from an array + //! \param ptr a pointer to an array of T + //! \param len the number of elements in the memory block + //! \details If the memory block is reduced in size, then the unused area is set to 0. + void Assign(const T *ptr, size_type len) + { + New(len); + if (m_ptr && ptr && len) + {memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));} + } + + //! \brief Copy contents from another SecBlock + //! \param t the other SecBlock + //! \details Assign checks for self assignment. + //! \details If the memory block is reduced in size, then the unused area is set to 0. + void Assign(const SecBlock<T, A> &t) + { + if (this != &t) + { + New(t.m_size); + if (m_ptr && t.m_ptr && t.m_size) + {memcpy_s(m_ptr, m_size*sizeof(T), t, t.m_size*sizeof(T));} + } + } + + //! \brief Assign contents from another SecBlock + //! \param t the other SecBlock + //! \details Internally, operator=() calls Assign(). + //! \details If the memory block is reduced in size, then the unused area is set to 0. + SecBlock<T, A>& operator=(const SecBlock<T, A> &t) + { + // Assign guards for self-assignment + Assign(t); + return *this; + } + + //! \brief Append contents from another SecBlock + //! \param t the other SecBlock + //! \details Internally, this SecBlock calls Grow and then copies the new content. + //! \details If the memory block is reduced in size, then the unused area is set to 0. + SecBlock<T, A>& operator+=(const SecBlock<T, A> &t) + { + assert((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_ptr.m_size)); + + if(t.size) + { + size_type oldSize = m_size; + Grow(m_size+t.m_size); + + if (m_ptr && t.m_ptr) + {memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), t.m_ptr, t.m_size*sizeof(T));} + } + return *this; + } + + //! \brief Concatenate contents from another SecBlock + //! \param t the other SecBlock + //! \returns a newly constructed SecBlock that is a conacentation of this and t + //! \details Internally, a temporary SecBlock is created and the content from this + //! SecBlock and the other SecBlock are concatenated. The temporary + //! SecBlock is returned to the caller. + SecBlock<T, A> operator+(const SecBlock<T, A> &t) + { + assert((!m_ptr && !m_size) || (m_ptr && m_size)); + assert((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_ptr.m_size)); + if(!t.size) return SecBlock(*this); + + SecBlock<T, A> result(m_size+t.m_size); + memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T)); + memcpy_s(result.m_ptr+m_size, (t.m_size-m_size)*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); + return result; + } + + //! \brief Bitwise compare two SecBlocks + //! \param t the other SecBlock + //! \returns true if the size and bits are equal, false otherwise + //! \details Uses a constant time compare if the arrays are equal size. The constant time + //! compare is VerifyBufsEqual() found in misc.h. + //! \sa operator!=() + bool operator==(const SecBlock<T, A> &t) const + { + return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T)); + } + + //! \brief Bitwise compare two SecBlocks + //! \param t the other SecBlock + //! \returns true if the size and bits are equal, false otherwise + //! \details Uses a constant time compare if the arrays are equal size. The constant time + //! compare is VerifyBufsEqual() found in misc.h. + //! \details Internally, operator!=() returns the inverse of operator==(). + //! \sa operator==() + bool operator!=(const SecBlock<T, A> &t) const + { + return !operator==(t); + } + + //! \brief Change size without preserving contents + //! \param newSize the new size of the memory block + //! \details Old content is \a not preserved. If the memory block is reduced in size, + //! then the unused content is set to 0. If the memory block grows in size, then + //! all content is uninitialized. + //! \details Internally, this SecBlock calls reallocate(). + //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void New(size_type newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false); + m_size = newSize; + } + + //! \brief Change size without preserving contents + //! \param newSize the new size of the memory block + //! \details Old content is not preserved. If the memory block is reduced in size, + //! then the unused content is set to 0. Existing and new content is set to 0. + //! \details Internally, this SecBlock calls reallocate(). + //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void CleanNew(size_type newSize) + { + New(newSize); + if (m_ptr) {memset_z(m_ptr, 0, m_size*sizeof(T));} + } + + //! \brief Change size and preserve contents + //! \param newSize the new size of the memory block + //! \details Old content is preserved. If the memory block grows in size, then + //! all content is uninitialized. + //! \details Internally, this SecBlock calls reallocate(). + //! \note reallocate() is called if the size increases. If the size does not + //! increase, then Grow does not take action. If the size must change, + //! then use resize(). + //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void Grow(size_type newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + } + } + + //! \brief Change size and preserve contents + //! \param newSize the new size of the memory block + //! \details Old content is preserved. If the memory block is reduced in size, + //! then the unused content is set to 0. If the memory block grows in size, + //! then the new content is uninitialized. + //! \details Internally, this SecBlock calls reallocate(). + //! \note reallocate() is called if the size increases. If the size does not + //! increase, then Grow does not take action. If the size must change, + //! then use resize(). + //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void CleanGrow(size_type newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + memset_z(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T)); + m_size = newSize; + } + } + + //! \brief Change size and preserve contents + //! \param newSize the new size of the memory block + //! \details Old content is preserved. If the memory block grows in size, then + //! all content is uninitialized. + //! \details Internally, this SecBlock calls reallocate(). + //! \note reallocate() is called if the size increases. If the size does not + //! increase, then Grow does not take action. If the size must change, + //! then use resize(). + //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void resize(size_type newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + } + + //! \brief Swap contents with another SecBlock + //! \param b the other SecBlock + //! \details Internally, std::swap() is called on m_alloc, m_size and m_ptr. + void swap(SecBlock<T, A> &b) + { + // Swap must occur on the allocator in case its FixedSize that spilled into the heap. + std::swap(m_alloc, b.m_alloc); + std::swap(m_size, b.m_size); + std::swap(m_ptr, b.m_ptr); + } + +// protected: + A m_alloc; + size_type m_size; + T *m_ptr; +}; + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +//! \class SecByteBlock +//! \brief SecByteBlock is a SecBlock<byte> typedef. +class SecByteBlock : public SecBlock<byte> {}; +//! \class SecWordBlock +//! \brief SecWordBlock is a SecBlock<word> typedef. +class SecWordBlock : public SecBlock<word> {}; +//! \class AlignedSecByteBlock +//! \brief AlignedSecByteBlock is a SecBlock<byte, AllocatorWithCleanup<byte, true> > typedef. +class AlignedSecByteBlock SecBlock<byte, AllocatorWithCleanup<byte, true> > {}; +#else +typedef SecBlock<byte> SecByteBlock; +typedef SecBlock<word> SecWordBlock; +typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock; +#endif + +// No need for move semantics on derived class *if* the class does not add any +// data members; see http://stackoverflow.com/q/31755703, and Rule of {0|3|5}. + +//! \class FixedSizeSecBlock +//! \brief Fixed size stack-based SecBlock +//! \tparam T class or type +//! \tparam S fixed-size of the stack-based memory block +//! \tparam A AllocatorBase derived class for allocation and cleanup +template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> > +class FixedSizeSecBlock : public SecBlock<T, A> +{ +public: + //! \brief Construct a FixedSizeSecBlock + explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {} +}; + +//! \class FixedSizeAlignedSecBlock +//! \brief Fixed size stack-based SecBlock with 16-byte alignment +//! \tparam T class or type +//! \tparam S fixed-size of the stack-based memory block +//! \tparam A AllocatorBase derived class for allocation and cleanup +template <class T, unsigned int S, bool T_Align16 = true> +class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> > +{ +}; + +//! \class SecBlockWithHint +//! \brief Stack-based SecBlock that grows into the heap +//! \tparam T class or type +//! \tparam S fixed-size of the stack-based memory block +//! \tparam A AllocatorBase derived class for allocation and cleanup +template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > > +class SecBlockWithHint : public SecBlock<T, A> +{ +public: + //! construct a SecBlockWithHint with a count of elements + explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {} +}; + +template<class T, bool A, class U, bool B> +inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);} +template<class T, bool A, class U, bool B> +inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template <class T, class A> +inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b) +{ + a.swap(b); +} + +#if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES)) +// working for STLport 5.1.3 and MSVC 6 SP5 +template <class _Tp1, class _Tp2> +inline CryptoPP::AllocatorWithCleanup<_Tp2>& +__stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*) +{ + return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a); +} +#endif + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif |