You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
804 lines
31 KiB
804 lines
31 KiB
// 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
|
|
|