secblock.h
Go to the documentation of this file.
// secblock.h - originally 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 "allocate.h"
#include "misc.h"
#include "stdcpp.h"
#if defined(CRYPTOPP_MSC_VERSION)
# pragma warning(push)
# pragma warning(disable: 4231 4275 4700)
# if (CRYPTOPP_MSC_VERSION >= 1400)
# pragma warning(disable: 6011 6386 28193)
# endif
#endif
NAMESPACE_BEGIN(CryptoPP)
// ************** secure memory allocation ***************
/// \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;
typedef std::ptrdiff_t difference_type;
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
/// \details <tt>ELEMS_MAX</tt> is the maximum number of elements the
/// <tt>Allocator</tt> can provide. The value of <tt>ELEMS_MAX</tt> is
/// <tt>SIZE_MAX/sizeof(T)</tt>. <tt>std::numeric_limits</tt> was avoided
/// due to lack of <tt>constexpr</tt>-ness in C++03 and below.
/// \note In C++03 and below <tt>ELEMS_MAX</tt> is a static data member of type
/// <tt>size_type</tt>. In C++11 and above <tt>ELEMS_MAX</tt> is an <tt>enum</tt>
/// inheriting from <tt>size_type</tt>. In both cases <tt>ELEMS_MAX</tt> can be
/// used before objects are fully constructed, and it does not suffer the
/// limitations of class methods like <tt>max_size</tt>.
/// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/346">Issue 346/CVE-2016-9939</A>
/// \since Crypto++ 6.0
#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
static const size_type ELEMS_MAX = ...;
#elif defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION <= 1400)
static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T);
#elif defined(CRYPTOPP_CXX11_STRONG_ENUM)
enum : size_type {ELEMS_MAX = SIZE_MAX/sizeof(T)};
#else
static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T);
#endif
/// \brief Returns the maximum number of elements the allocator can provide
/// \return the maximum number of elements the allocator can provide
/// \details Internally, preprocessor macros are used rather than std::numeric_limits
/// because the latter is not 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.
CRYPTOPP_CONSTEXPR size_type max_size() const {return ELEMS_MAX;}
#if defined(__SUNPRO_CC)
// https://github.com/weidai11/cryptopp/issues/770
// and https://stackoverflow.com/q/53999461/608639
CRYPTOPP_CONSTEXPR size_type max_size(size_type n) const {return SIZE_MAX/n;}
#endif
#if defined(CRYPTOPP_CXX11_VARIADIC_TEMPLATES) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
/// \brief Constructs a new V using variadic arguments
/// \tparam V the type to be forwarded
/// \tparam Args the arguments to be forwarded
/// \param ptr pointer to type V
/// \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 V, typename... Args>
void construct(V* ptr, Args&&... args) {::new ((void*)ptr) V(std::forward<Args>(args)...);}
/// \brief Destroys an V constructed with variadic arguments
/// \tparam V 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 V>
void destroy(V* ptr) {if (ptr) ptr->~V();}
#endif
protected:
/// \brief Verifies the allocator can satisfy a request based on size
/// \param size the size of the allocation, in elements
/// \throw 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 not 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.
/// \details The <tt>sizeof(T) != 1</tt> in the condition attempts to help the
/// compiler optimize the check for byte types. Coverity findings for
/// CONSTANT_EXPRESSION_RESULT were generated without it. For byte types,
/// size never exceeded ELEMS_MAX but the code was not removed.
/// \note size is the count of elements, and not the number of bytes
static void CheckSize(size_t size)
{
// Squash MSC C4100 warning for size. Also see commit 42b7c4ea5673.
CRYPTOPP_UNUSED(size);
// C++ throws std::bad_alloc (C++03) or std::bad_array_new_length (C++11) here.
if (sizeof(T) != 1 && size > ELEMS_MAX)
throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
}
};
#define CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T_type) \
typedef typename AllocatorBase<T_type>::value_type value_type;\
typedef typename AllocatorBase<T_type>::size_type size_type;\
typedef typename AllocatorBase<T_type>::difference_type difference_type;\
typedef typename AllocatorBase<T_type>::pointer pointer;\
typedef typename AllocatorBase<T_type>::const_pointer const_pointer;\
typedef typename AllocatorBase<T_type>::reference reference;\
typedef typename AllocatorBase<T_type>::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)
{
// Avoid assert on pointer in reallocate. SecBlock regularly uses NULL
// pointers rather returning non-NULL 0-sized pointers.
if (oldSize == newSize)
return oldPtr;
if (preserve)
{
typename A::pointer newPtr = alloc.allocate(newSize, NULLPTR);
const typename A::size_type copySize = STDMIN(oldSize, newSize) * sizeof(T);
if (oldPtr && newPtr)
memcpy_s(newPtr, copySize, oldPtr, copySize);
if (oldPtr)
alloc.deallocate(oldPtr, oldSize);
return newPtr;
}
else
{
if (oldPtr)
alloc.deallocate(oldPtr, oldSize);
return alloc.allocate(newSize, NULLPTR);
}
}
/// \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 a 16-byte boundary
/// \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(T)
/// \brief Allocates a block of memory
/// \param ptr the size of the allocation
/// \param size the size of the allocation, in elements
/// \return a memory block
/// \throw 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(). 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 = NULLPTR)
{
CRYPTOPP_UNUSED(ptr); CRYPTOPP_ASSERT(ptr == NULLPTR);
this->CheckSize(size);
if (size == 0)
return NULLPTR;
#if CRYPTOPP_BOOL_ALIGN16
if (T_Align16)
return reinterpret_cast<pointer>(AlignedAllocate(size*sizeof(T)));
#endif
return reinterpret_cast<pointer>(UnalignedAllocate(size*sizeof(T)));
}
/// \brief Deallocates a block of memory
/// \param ptr the pointer for the allocation
/// \param size the size of the allocation, in elements
/// \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)
{
// Avoid assert on pointer in deallocate. SecBlock regularly uses NULL
// pointers rather returning non-NULL 0-sized pointers.
if (ptr)
{
SecureWipeArray(reinterpret_cast<pointer>(ptr), size);
#if CRYPTOPP_BOOL_ALIGN16
if (T_Align16)
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
/// \return 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)
{
CRYPTOPP_ASSERT((oldPtr && oldSize) || !(oldPtr || oldSize));
return StandardReallocate(*this, oldPtr, oldSize, newSize, preserve);
}
/// \brief Template class member Rebind
/// \tparam V bound class or type
/// \details Rebind allows a container class to allocate a different type of object
/// to store elements. For example, a std::list will allocate std::list_node to
/// store elements in the list.
/// \details VS.NET STL enforces the policy of "All STL-compliant allocators
/// have to provide a template class member called rebind".
template <class V> struct rebind { typedef AllocatorWithCleanup<V, T_Align16> other; };
#if (CRYPTOPP_MSC_VERSION >= 1500)
AllocatorWithCleanup() {}
template <class V, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<V, 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 defined(CRYPTOPP_WORD128_AVAILABLE)
CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word128, true>; // for Integer
#endif
#if CRYPTOPP_BOOL_X86
CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>; // for Integer
#endif
/// \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:
//LCOV_EXCL_START
CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)
// 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 = NULLPTR)
{
CRYPTOPP_UNUSED(n); CRYPTOPP_UNUSED(unused);
CRYPTOPP_ASSERT(false); return NULLPTR;
}
void deallocate(void *p, size_type n)
{
CRYPTOPP_UNUSED(p); CRYPTOPP_UNUSED(n);
CRYPTOPP_ASSERT(false);
}
CRYPTOPP_CONSTEXPR size_type max_size() const {return 0;}
//LCOV_EXCL_STOP
};
/// \brief Static secure memory block with cleanup
/// \tparam T class or type
/// \tparam S fixed-size of the stack-based memory block, in elements
/// \tparam T_Align16 boolean that determines whether allocations should
/// be aligned on a 16-byte boundary
/// \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>
{
// The body of FixedSizeAllocatorWithCleanup is provided in the two
// partial specializations that follow. The two specializations
// pivot on the boolean template parameter T_Align16.
};
/// \brief Static secure memory block with cleanup
/// \tparam T class or type
/// \tparam S fixed-size of the stack-based memory block, in elements
/// \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>
class FixedSizeAllocatorWithCleanup<T, S, A, true> : public AllocatorBase<T>
{
public:
CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)
/// \brief Constructs a FixedSizeAllocatorWithCleanup
FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
/// \brief Allocates a block of memory
/// \param size the count elements in the memory block
/// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based
/// allocation at compile time. If size is less than or equal to
/// <tt>S</tt>, 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 not available, as with a
/// NullAllocator, then the function returns NULL and a runtime error
/// eventually occurs.
/// \sa reallocate(), SecBlockWithHint
pointer allocate(size_type size)
{
CRYPTOPP_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 the count elements in 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 not available, as with a
/// NullAllocator, then the function returns NULL and a runtime error
/// eventually occurs.
/// \sa reallocate(), SecBlockWithHint
pointer allocate(size_type size, const void *hint)
{
CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8));
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 the count elements in 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)
{
// Avoid assert on pointer in deallocate. SecBlock regularly uses NULL
// pointers rather returning non-NULL 0-sized pointers.
if (ptr == GetAlignedArray())
{
// If the m_allocated assert fires then the bit twiddling for
// GetAlignedArray() is probably incorrect for the platform.
// Be sure to check CRYPTOPP_ALIGN_DATA(8). The platform may
// not have a way to declaratively align data to 8.
CRYPTOPP_ASSERT(size <= S);
CRYPTOPP_ASSERT(m_allocated);
m_allocated = false;
SecureWipeArray(reinterpret_cast<pointer>(ptr), size);
}
else
{
if (ptr)
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
/// \return 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 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)
{
CRYPTOPP_ASSERT(oldSize <= S);
if (oldSize > newSize)
SecureWipeArray(oldPtr+newSize, oldSize-newSize);
return oldPtr;
}
pointer newPtr = allocate(newSize, NULLPTR);
if (preserve && newSize)
{
const size_type copySize = STDMIN(oldSize, newSize);
if (newPtr && oldPtr) // GCC analyzer warning
memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize);
}
deallocate(oldPtr, oldSize);
return newPtr;
}
CRYPTOPP_CONSTEXPR size_type max_size() const
{
return STDMAX(m_fallbackAllocator.max_size(), S);
}
private:
#if CRYPTOPP_BOOL_ALIGN16
// There be demons here... We cannot use CRYPTOPP_ALIGN_DATA(16)
// because linkers on 32-bit machines and some 64-bit machines
// align the stack to 8-bytes or less, and not 16-bytes as
// requested. We can only count on a smaller alignment. All
// toolchains tested appear to honor CRYPTOPP_ALIGN_DATA(8). Also
// see http://stackoverflow.com/a/1468656/608639.
//
// The 16-byte alignment is achieved by padding the requested
// size with extra elements so we have at least 8-bytes of slack
// to work with. Then the array pointer is moved to achieve a
// 16-byte alignment.
//
// The additional 8-bytes introduces a small secondary issue.
// The secondary issue is, a large T results in 0 = 8/sizeof(T).
// The library is OK but users may hit it. So we need to guard
// for a large T, and that is what the enum and PAD achieves.
T* GetAlignedArray() {
// m_array is aligned on 8 byte boundaries due to
// CRYPTOPP_ALIGN_DATA(8). If m_array%16 is 0, then the buffer
// is 16-byte aligned and nothing needs to be done. if
// m_array%16 is 8, then the buffer is not 16-byte aligned and
// we need to add 8. 8 has that nice symmetric property.
//
// If we needed to use CRYPTOPP_ALIGN_DATA(4) due to toolchain
// limitations, then the calculation would be slightly more
// costly: ptr = m_array + (16 - (m_array % 16)) % 16;
CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8));
int off = reinterpret_cast<uintptr_t>(m_array) % 16;
byte* ptr = reinterpret_cast<byte*>(m_array) + off;
// Verify the 16-byte alignment. This is the point
// of these extra gyrations.
CRYPTOPP_ASSERT(IsAlignedOn(ptr, 16));
// Verify the lower bound. This is Issue 982/988.
CRYPTOPP_ASSERT(
reinterpret_cast<uintptr_t>(ptr) >=
reinterpret_cast<uintptr_t>(m_array)
);
// Verify the upper bound. Allocated array with
// pad is large enough.
CRYPTOPP_ASSERT(
reinterpret_cast<uintptr_t>(ptr+S*sizeof(T)) <=
reinterpret_cast<uintptr_t>(m_array+(S+PAD))
);
// void* to silence Clang warnings
return reinterpret_cast<T*>(
static_cast<void*>(ptr)
);
}
// PAD is elements, not bytes, and rounded up to ensure no overflow.
enum { Q = sizeof(T), PAD = (Q >= 8) ? 1 : (Q >= 4) ? 2 : (Q >= 2) ? 4 : 8 };
// enum { Q = sizeof(T), PAD = (Q >= 16) ? 1 : (Q >= 8) ? 2 : (Q >= 4) ? 4 : (Q >= 2) ? 8 : 16 };
CRYPTOPP_ALIGN_DATA(8) T m_array[S+PAD];
#else
// CRYPTOPP_BOOL_ALIGN16 is 0. If we are here then the user
// probably compiled with CRYPTOPP_DISABLE_ASM. Normally we
// would use the natural alignment of T. The problem we are
// having is, some toolchains are changing the boundary for
// 64-bit arrays. 64-bit elements require 8-byte alignment,
// but the toolchain is laying the array out on a 4 byte
// boundary. See GH #992 for mystery alignment,
// https://github.com/weidai11/cryptopp/issues/992
T* GetAlignedArray() {return m_array;}
CRYPTOPP_ALIGN_DATA(8) T m_array[S];
#endif
A m_fallbackAllocator;
bool m_allocated;
};
/// \brief Static secure memory block with cleanup
/// \tparam T class or type
/// \tparam S fixed-size of the stack-based memory block, in elements
/// \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>
class FixedSizeAllocatorWithCleanup<T, S, A, false> : public AllocatorBase<T>
{
public:
CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T)
/// \brief Constructs a FixedSizeAllocatorWithCleanup
FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
/// \brief Allocates a block of memory
/// \param size the count elements in the memory block
/// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based
/// allocation at compile time. If size is less than or equal to
/// <tt>S</tt>, 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 not available, as with a
/// NullAllocator, then the function returns NULL and a runtime error
/// eventually occurs.
/// \sa reallocate(), SecBlockWithHint
pointer allocate(size_type size)
{
CRYPTOPP_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 the count elements in 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 not available, as with a
/// NullAllocator, then the function returns NULL and a runtime error
/// eventually occurs.
/// \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 the count elements in 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)
{
// Avoid assert on pointer in deallocate. SecBlock regularly uses NULL
// pointers rather returning non-NULL 0-sized pointers.
if (ptr == GetAlignedArray())
{
// If the m_allocated assert fires then
// something overwrote the flag.
CRYPTOPP_ASSERT(size <= S);
CRYPTOPP_ASSERT(m_allocated);
m_allocated = false;
SecureWipeArray((pointer)ptr, size);
}
else
{
if (ptr)
m_fallbackAllocator.deallocate(ptr, size);
m_allocated = false;
}
}
/// \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
/// \return 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 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)
{
CRYPTOPP_ASSERT(oldSize <= S);
if (oldSize > newSize)
SecureWipeArray(oldPtr+newSize, oldSize-newSize);
return oldPtr;
}
pointer newPtr = allocate(newSize, NULLPTR);
if (preserve && newSize)
{
const size_type copySize = STDMIN(oldSize, newSize);
if (newPtr && oldPtr) // GCC analyzer warning
memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize);
}
deallocate(oldPtr, oldSize);
return newPtr;
}
CRYPTOPP_CONSTEXPR size_type max_size() const
{
return STDMAX(m_fallbackAllocator.max_size(), S);
}
private:
// T_Align16 is false. Normally we would use the natural
// alignment of T. The problem we are having is, some toolchains
// are changing the boundary for 64-bit arrays. 64-bit elements
// require 8-byte alignment, but the toolchain is laying the array
// out on a 4 byte boundary. See GH #992 for mystery alignment,
// https://github.com/weidai11/cryptopp/issues/992
T* GetAlignedArray() {return m_array;}
CRYPTOPP_ALIGN_DATA(8) T m_array[S];
A m_fallbackAllocator;
bool m_allocated;
};
/// \brief Secure memory block with allocator and cleanup
/// \tparam T a class or type
/// \tparam A AllocatorWithCleanup derived class for allocation and cleanup
/// \sa <A HREF="https://www.cryptopp.com/wiki/SecBlock">SecBlock</A>
/// on the Crypto++ wiki.
/// \since Crypto++ 2.0
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 Returns the maximum number of elements the block can hold
/// \details <tt>ELEMS_MAX</tt> is the maximum number of elements the
/// <tt>SecBlock</tt> can hold. The value of <tt>ELEMS_MAX</tt> is
/// <tt>SIZE_MAX/sizeof(T)</tt>. <tt>std::numeric_limits</tt> was avoided
/// due to lack of <tt>constexpr</tt>-ness in C++03 and below.
/// \note In C++03 and below <tt>ELEMS_MAX</tt> is a static data member of type
/// <tt>size_type</tt>. In C++11 and above <tt>ELEMS_MAX</tt> is an <tt>enum</tt>
/// inheriting from <tt>size_type</tt>. In both cases <tt>ELEMS_MAX</tt> can be
/// used before objects are fully constructed, and it does not suffer the
/// limitations of class methods like <tt>max_size</tt>.
/// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/346">Issue 346/CVE-2016-9939</A>
/// \since Crypto++ 6.0
#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
static const size_type ELEMS_MAX = ...;
#elif defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION <= 1400)
static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T);
#elif defined(CRYPTOPP_CXX11_STRONG_ENUM)
enum : size_type {ELEMS_MAX = A::ELEMS_MAX};
#else
static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T);
#endif
/// \brief Construct a SecBlock with space for size elements.
/// \param size the size of the allocation, in elements
/// \throw std::bad_alloc
/// \details The elements are not initialized.
/// \since Crypto++ 2.0
/// \note size is the count of elements, and not the number of bytes
explicit SecBlock(size_type size=0)
: m_mark(ELEMS_MAX), m_size(size), m_ptr(m_alloc.allocate(size, NULLPTR)) { }
/// \brief Copy construct a SecBlock from another SecBlock
/// \param t the other SecBlock
/// \throw std::bad_alloc
/// \since Crypto++ 2.0
SecBlock(const SecBlock<T, A> &t)
: m_mark(t.m_mark), m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULLPTR)) {
CRYPTOPP_ASSERT((!t.m_ptr && !m_size) || (t.m_ptr && m_size));
if (m_ptr && 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
/// \throw std::bad_alloc
/// \details If <tt>ptr!=NULL</tt> and <tt>len!=0</tt>, then the block is initialized from the pointer
/// <tt>ptr</tt>. If <tt>ptr==NULL</tt> and <tt>len!=0</tt>, then the block is initialized to 0.
/// Otherwise, the block is empty and not initialized.
/// \since Crypto++ 2.0
/// \note size is the count of elements, and not the number of bytes
SecBlock(const T *ptr, size_type len)
: m_mark(ELEMS_MAX), m_size(len), m_ptr(m_alloc.allocate(len, NULLPTR)) {
CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size));
if (m_ptr && ptr)
memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));
else if (m_ptr && m_size)
std::memset(m_ptr, 0, m_size*sizeof(T));
}
~SecBlock()
{m_alloc.deallocate(m_ptr, STDMIN(m_size, m_mark));}
#ifdef __BORLANDC__
/// \brief Cast operator
/// \return block pointer cast to non-const <tt>T *</tt>
/// \since Crypto++ 2.0
operator T *() const
{return (T*)m_ptr;}
#else
/// \brief Cast operator
/// \return block pointer cast to <tt>const void *</tt>
/// \since Crypto++ 2.0
operator const void *() const
{return m_ptr;}
/// \brief Cast operator
/// \return block pointer cast to non-const <tt>void *</tt>
/// \since Crypto++ 2.0
operator void *()
{return m_ptr;}
/// \brief Cast operator
/// \return block pointer cast to <tt>const T *</tt>
/// \since Crypto++ 2.0
operator const T *() const
{return m_ptr;}
/// \brief Cast operator
/// \return block pointer cast to non-const <tt>T *</tt>
/// \since Crypto++ 2.0
operator T *()
{return m_ptr;}
#endif
/// \brief Provides an iterator pointing to the first element in the memory block
/// \return iterator pointing to the first element in the memory block
/// \since Crypto++ 2.0
iterator begin()
{return m_ptr;}
/// \brief Provides a constant iterator pointing to the first element in the memory block
/// \return constant iterator pointing to the first element in the memory block
/// \since Crypto++ 2.0
const_iterator begin() const
{return m_ptr;}
/// \brief Provides an iterator pointing beyond the last element in the memory block
/// \return iterator pointing beyond the last element in the memory block
/// \since Crypto++ 2.0
iterator end()
{return m_ptr+m_size;}
/// \brief Provides a constant iterator pointing beyond the last element in the memory block
/// \return constant iterator pointing beyond the last element in the memory block
/// \since Crypto++ 2.0
const_iterator end() const
{return m_ptr+m_size;}
/// \brief Provides a pointer to the first element in the memory block
/// \return pointer to the first element in the memory block
/// \since Crypto++ 2.0
typename A::pointer data() {return m_ptr;}
/// \brief Provides a pointer to the first element in the memory block
/// \return constant pointer to the first element in the memory block
/// \since Crypto++ 2.0
typename A::const_pointer data() const {return m_ptr;}
/// \brief Provides the count of elements in the SecBlock
/// \return number of elements in the memory block
/// \note the return value is the count of elements, and not the number of bytes
/// \since Crypto++ 2.0
size_type size() const {return m_size;}
/// \brief Determines if the SecBlock is empty
/// \return true if number of elements in the memory block is 0, false otherwise
/// \since Crypto++ 2.0
bool empty() const {return m_size == 0;}
/// \brief Provides a byte pointer to the first element in the memory block
/// \return byte pointer to the first element in the memory block
/// \since Crypto++ 2.0
byte * BytePtr() {return (byte *)m_ptr;}
/// \brief Return a byte pointer to the first element in the memory block
/// \return constant byte pointer to the first element in the memory block
/// \since Crypto++ 2.0
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.
/// \since Crypto++ 2.0
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 The array pointed to by <tt>ptr</tt> must be distinct
/// from this SecBlock because Assign() calls New() and then std::memcpy().
/// The call to New() will invalidate all pointers and iterators, like
/// the pointer returned from data().
/// \details If the memory block is reduced in size, then the reclaimed
/// memory is set to 0. If an assignment occurs, then Assign() resets
/// the element count after the previous block is zeroized.
/// \since Crypto++ 2.0
void Assign(const T *ptr, size_type len)
{
New(len);
if (m_ptr && ptr) // GCC analyzer warning
memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));
m_mark = ELEMS_MAX;
}
/// \brief Set contents from a value
/// \param count the number of values to copy
/// \param value the value, repeated count times
/// \details If the memory block is reduced in size, then the reclaimed
/// memory is set to 0. If an assignment occurs, then Assign() resets
/// the element count after the previous block is zeroized.
/// \since Crypto++ 6.0
void Assign(size_type count, T value)
{
New(count);
for (size_t i=0; i<count; ++i)
m_ptr[i] = value;
m_mark = ELEMS_MAX;
}
/// \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 reclaimed
/// memory is set to 0. If an assignment occurs, then Assign() resets
/// the element count after the previous block is zeroized.
/// \since Crypto++ 2.0
void Assign(const SecBlock<T, A> &t)
{
if (this != &t)
{
New(t.m_size);
if (m_ptr && t.m_ptr) // GCC analyzer warning
memcpy_s(m_ptr, m_size*sizeof(T), t, t.m_size*sizeof(T));
}
m_mark = ELEMS_MAX;
}
/// \brief Append contents from an array
/// \param ptr a pointer to an array of T
/// \param len the number of elements in the memory block
/// \throw InvalidArgument if resulting size would overflow
/// \details The array pointed to by <tt>ptr</tt> must be distinct
/// from this SecBlock because Append() calls Grow() and then std::memcpy().
/// The call to Grow() will invalidate all pointers and iterators, like
/// the pointer returned from data().
/// \details Append() may be less efficient than a ByteQueue because
/// Append() must Grow() the internal array and then copy elements.
/// The ByteQueue can copy elements without growing.
/// \sa ByteQueue
/// \since Crypto++ 8.6
void Append(const T *ptr, size_type len)
{
if (ELEMS_MAX - m_size < len)
throw InvalidArgument("SecBlock: buffer overflow");
const size_type oldSize = m_size;
Grow(m_size+len);
if (m_ptr && ptr) // GCC analyzer warning
memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), ptr, len*sizeof(T));
m_mark = ELEMS_MAX;
}
/// \brief Append contents from another SecBlock
/// \param t the other SecBlock
/// \throw InvalidArgument if resulting size would overflow
/// \details Internally, this SecBlock calls Grow() and then appends t.
/// \details Append() may be less efficient than a ByteQueue because
/// Append() must Grow() the internal array and then copy elements.
/// The ByteQueue can copy elements without growing.
/// \sa ByteQueue
/// \since Crypto++ 8.6
void Append(const SecBlock<T, A> &t)
{
if (ELEMS_MAX - m_size < t.m_size)
throw InvalidArgument("SecBlock: buffer overflow");
const size_type oldSize = m_size;
if (this != &t) // s += t
{
Grow(m_size+t.m_size);
if (m_ptr && t.m_ptr) // GCC analyzer warning
memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
}
else // t += t
{
Grow(m_size*2);
if (m_ptr) // GCC analyzer warning
memmove_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), m_ptr, oldSize*sizeof(T));
}
m_mark = ELEMS_MAX;
}
/// \brief Append contents from a value
/// \param count the number of values to copy
/// \param value the value, repeated count times
/// \throw InvalidArgument if resulting size would overflow
/// \details Internally, this SecBlock calls Grow() and then appends value.
/// \details Append() may be less efficient than a ByteQueue because
/// Append() must Grow() the internal array and then copy elements.
/// The ByteQueue can copy elements without growing.
/// \sa ByteQueue
/// \since Crypto++ 8.6
void Append(size_type count, T value)
{
if (ELEMS_MAX - m_size < count)
throw InvalidArgument("SecBlock: buffer overflow");
const size_type oldSize = m_size;
Grow(m_size+count);
for (size_t i=oldSize; i<oldSize+count; ++i)
m_ptr[i] = value;
m_mark = ELEMS_MAX;
}
/// \brief Sets the number of elements to zeroize
/// \param count the number of elements
/// \details SetMark is a remediation for Issue 346/CVE-2016-9939 while
/// preserving the streaming interface. The <tt>count</tt> controls the number of
/// elements zeroized, which can be less than <tt>size</tt> or 0.
/// \details An internal variable, <tt>m_mark</tt>, is initialized to the maximum number
/// of elements. The maximum number of elements is <tt>ELEMS_MAX</tt>. Deallocation
/// triggers a zeroization, and the number of elements zeroized is
/// <tt>STDMIN(m_size, m_mark)</tt>. After zeroization, the memory is returned to the
/// system.
/// \details The ASN.1 decoder uses SetMark() to set the element count to 0
/// before throwing an exception. In this case, the attacker provides a large
/// BER encoded length (say 64MB) but only a small number of content octets
/// (say 16). If the allocator zeroized all 64MB, then a transient DoS could
/// occur as CPU cycles are spent zeroizing uninitialized memory.
/// \details Generally speaking, any operation which changes the size of the SecBlock
/// results in the mark being reset to <tt>ELEMS_MAX</tt>. In particular, if Assign(),
/// New(), Grow(), CleanNew(), CleanGrow() are called, then the count is reset to
/// <tt>ELEMS_MAX</tt>. The list is not exhaustive.
/// \since Crypto++ 6.0
/// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/346">Issue 346/CVE-2016-9939</A>
void SetMark(size_t count) {m_mark = count;}
/// \brief Assign contents from another SecBlock
/// \param t the other SecBlock
/// \return reference to this SecBlock
/// \details Internally, operator=() calls Assign().
/// \details If the memory block is reduced in size, then the reclaimed
/// memory is set to 0. If an assignment occurs, then Assign() resets
/// the element count after the previous block is zeroized.
/// \since Crypto++ 2.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
/// \return reference to this SecBlock
/// \details Internally, operator+=() calls Append().
/// \since Crypto++ 2.0
SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
{
// Append guards for overflow
Append(t);
return *this;
}
/// \brief Construct a SecBlock from this and another SecBlock
/// \param t the other SecBlock
/// \return a newly constructed SecBlock that is a concatenation of this
/// and t.
/// \details Internally, a new SecBlock is created from this and a
/// concatenation of t.
/// \since Crypto++ 2.0
SecBlock<T, A> operator+(const SecBlock<T, A> &t)
{
CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size));
CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size));
if(!t.m_size) return SecBlock(*this);
SecBlock<T, A> result(m_size+t.m_size);
if (m_size)
memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
if (result.m_ptr && t.m_ptr) // GCC analyzer warning
memcpy_s(result.m_ptr+m_size, (result.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
/// \return 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
/// <tt>misc.h</tt>.
/// \sa operator!=()
/// \since Crypto++ 2.0
bool operator==(const SecBlock<T, A> &t) const
{
return m_size == t.m_size && VerifyBufsEqual(
reinterpret_cast<const byte*>(m_ptr),
reinterpret_cast<const byte*>(t.m_ptr), m_size*sizeof(T));
}
/// \brief Bitwise compare two SecBlocks
/// \param t the other SecBlock
/// \return 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
/// <tt>misc.h</tt>.
/// \details Internally, operator!=() returns the inverse of operator==().
/// \sa operator==()
/// \since Crypto++ 2.0
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 not preserved. If the memory block is
/// reduced in size, then the reclaimed content is set to 0. If the
/// memory block grows in size, then the new memory is initialized
/// to 0. New() resets the element count after the previous block
/// is zeroized.
/// \details Internally, this SecBlock calls reallocate().
/// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
/// \since Crypto++ 2.0
void New(size_type newSize)
{
m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
m_size = newSize;
m_mark = ELEMS_MAX;
}
/// \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 reclaimed content is set to 0. If the
/// memory block grows in size, then the new memory is initialized
/// to 0. CleanNew() resets the element count after the previous
/// block is zeroized.
/// \details Internally, this SecBlock calls New().
/// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
/// \since Crypto++ 2.0
void CleanNew(size_type newSize)
{
New(newSize);
if (m_ptr) {memset_z(m_ptr, 0, m_size*sizeof(T));}
m_mark = ELEMS_MAX;
}
/// \brief Change size and preserve contents
/// \param newSize the new size of the memory block
/// \details Old content is preserved. New content is not initialized.
/// \details Internally, this SecBlock calls reallocate() when size must
/// increase. If the size does not increase, then CleanGrow() does not
/// take action. If the size must change, then use resize(). CleanGrow()
/// resets the element count after the previous block is zeroized.
/// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
/// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
/// \since Crypto++ 2.0
void Grow(size_type newSize)
{
if (newSize > m_size)
{
m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
m_size = newSize;
}
m_mark = ELEMS_MAX;
}
/// \brief Change size and preserve contents
/// \param newSize the new size of the memory block
/// \details Old content is preserved. New content is initialized to 0.
/// \details Internally, this SecBlock calls reallocate() when size must
/// increase. If the size does not increase, then CleanGrow() does not
/// take action. If the size must change, then use resize(). CleanGrow()
/// resets the element count after the previous block is zeroized.
/// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
/// \since Crypto++ 2.0
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;
}
m_mark = ELEMS_MAX;
}
/// \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
/// new memory is not initialized. resize() resets the element count after
/// the previous block is zeroized.
/// \details Internally, this SecBlock calls reallocate().
/// \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
/// \since Crypto++ 2.0
void resize(size_type newSize)
{
m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
m_size = newSize;
m_mark = ELEMS_MAX;
}
/// \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.
/// \since Crypto++ 2.0
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_mark, b.m_mark);
std::swap(m_size, b.m_size);
std::swap(m_ptr, b.m_ptr);
}
protected:
A m_alloc;
size_type m_mark, m_size;
T *m_ptr;
};
#ifdef CRYPTOPP_DOXYGEN_PROCESSING
/// \brief \ref SecBlock "SecBlock<byte>" typedef.
class SecByteBlock : public SecBlock<byte> {};
/// \brief \ref SecBlock "SecBlock<word>" typedef.
class SecWordBlock : public SecBlock<word> {};
/// \brief SecBlock using \ref AllocatorWithCleanup "AllocatorWithCleanup<byte, true>" typedef
class AlignedSecByteBlock : public 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}.
/// \brief Fixed size stack-based SecBlock
/// \tparam T class or type
/// \tparam S fixed-size of the stack-based memory block, in elements
/// \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) {}
};
/// \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, in elements
/// \tparam T_Align16 boolean that determines whether allocations should be
/// aligned on a 16-byte boundary
template <class T, unsigned int S, bool T_Align16 = true>
class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
{
};
/// \brief Stack-based SecBlock that grows into the heap
/// \tparam T class or type
/// \tparam S fixed-size of the stack-based memory block, in elements
/// \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 V, bool B>
inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<V, B>&) {return (true);}
template<class T, bool A, class V, bool B>
inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<V, B>&) {return (false);}
NAMESPACE_END
NAMESPACE_BEGIN(std)
/// \brief Swap two SecBlocks
/// \tparam T class or type
/// \tparam A AllocatorBase derived class for allocation and cleanup
/// \param a the first SecBlock
/// \param b the second SecBlock
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 defined(CRYPTOPP_MSC_VERSION)
# pragma warning(pop)
#endif
#endif
allocate.h
Functions for allocating aligned buffers.
AlignedDeallocate
CRYPTOPP_DLL void AlignedDeallocate(void *ptr)
Frees a buffer allocated with AlignedAllocate.
UnalignedAllocate
CRYPTOPP_DLL void * UnalignedAllocate(size_t size)
Allocates a buffer.
UnalignedDeallocate
CRYPTOPP_DLL void UnalignedDeallocate(void *ptr)
Frees a buffer allocated with UnalignedAllocate.
AlignedAllocate
CRYPTOPP_DLL void * AlignedAllocate(size_t size)
Allocates a buffer on 16-byte boundary.
operator==
bool operator==(const OID &lhs, const OID &rhs)
Compare two OIDs for equality.
operator!=
bool operator!=(const OID &lhs, const OID &rhs)
Compare two OIDs for inequality.
AlignedSecByteBlock
SecBlock using AllocatorWithCleanup<byte, true> typedef.
Definition secblock.h:1230
AllocatorBase
Base class for all allocators used by SecBlock.
Definition secblock.h:30
AllocatorBase::construct
void construct(V *ptr, Args &&... args)
Constructs a new V using variadic arguments.
Definition secblock.h:91
AllocatorBase::ELEMS_MAX
static const size_type ELEMS_MAX
Returns the maximum number of elements the allocator can provide.
Definition secblock.h:58
AllocatorBase::max_size
size_type max_size() const
Returns the maximum number of elements the allocator can provide.
Definition secblock.h:73
AllocatorBase::destroy
void destroy(V *ptr)
Destroys an V constructed with variadic arguments.
Definition secblock.h:98
AllocatorWithCleanup
Allocates a block of memory with cleanup.
Definition secblock.h:188
AllocatorWithCleanup::allocate
pointer allocate(size_type size, const void *ptr=NULL)
Allocates a block of memory.
Definition secblock.h:206
AllocatorWithCleanup::reallocate
pointer reallocate(T *oldPtr, size_type oldSize, size_type newSize, bool preserve)
Reallocates a block of memory.
Definition secblock.h:259
AllocatorWithCleanup::deallocate
void deallocate(void *ptr, size_type size)
Deallocates a block of memory.
Definition secblock.h:229
FixedSizeAlignedSecBlock
Fixed size stack-based SecBlock with 16-byte alignment.
Definition secblock.h:1259
FixedSizeAllocatorWithCleanup< T, S, A, false >::deallocate
void deallocate(void *ptr, size_type size)
Deallocates a block of memory.
Definition secblock.h:643
FixedSizeAllocatorWithCleanup< T, S, A, false >::allocate
pointer allocate(size_type size)
Allocates a block of memory.
Definition secblock.h:598
FixedSizeAllocatorWithCleanup< T, S, A, false >::reallocate
pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve)
Reallocates a block of memory.
Definition secblock.h:682
FixedSizeAllocatorWithCleanup< T, S, A, false >::allocate
pointer allocate(size_type size, const void *hint)
Allocates a block of memory.
Definition secblock.h:624
FixedSizeAllocatorWithCleanup< T, S, A, true >::reallocate
pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve)
Reallocates a block of memory.
Definition secblock.h:461
FixedSizeAllocatorWithCleanup< T, S, A, true >::allocate
pointer allocate(size_type size, const void *hint)
Allocates a block of memory.
Definition secblock.h:400
FixedSizeAllocatorWithCleanup< T, S, A, true >::deallocate
void deallocate(void *ptr, size_type size)
Deallocates a block of memory.
Definition secblock.h:421
FixedSizeAllocatorWithCleanup< T, S, A, true >::allocate
pointer allocate(size_type size)
Allocates a block of memory.
Definition secblock.h:374
FixedSizeAllocatorWithCleanup
Static secure memory block with cleanup.
Definition secblock.h:337
FixedSizeSecBlock
Fixed size stack-based SecBlock.
Definition secblock.h:1246
FixedSizeSecBlock::FixedSizeSecBlock
FixedSizeSecBlock()
Construct a FixedSizeSecBlock.
Definition secblock.h:1249
InvalidArgument
An invalid argument was detected.
Definition cryptlib.h:208
NullAllocator
NULL allocator.
Definition secblock.h:299
SecBlock
Secure memory block with allocator and cleanup.
Definition secblock.h:731
SecBlock::Assign
void Assign(size_type count, T value)
Set contents from a value.
Definition secblock.h:913
SecBlock::begin
iterator begin()
Provides an iterator pointing to the first element in the memory block.
Definition secblock.h:836
SecBlock::begin
const_iterator begin() const
Provides a constant iterator pointing to the first element in the memory block.
Definition secblock.h:841
SecBlock::Append
void Append(const T *ptr, size_type len)
Append contents from an array.
Definition secblock.h:952
SecBlock::end
iterator end()
Provides an iterator pointing beyond the last element in the memory block.
Definition secblock.h:846
SecBlock::operator+
SecBlock< T, A > operator+(const SecBlock< T, A > &t)
Construct a SecBlock from this and another SecBlock.
Definition secblock.h:1073
SecBlock::SecBlock
SecBlock(const SecBlock< T, A > &t)
Copy construct a SecBlock from another SecBlock.
Definition secblock.h:773
SecBlock::CleanNew
void CleanNew(size_type newSize)
Change size without preserving contents.
Definition secblock.h:1143
SecBlock::Assign
void Assign(const SecBlock< T, A > &t)
Copy contents from another SecBlock.
Definition secblock.h:928
SecBlock::swap
void swap(SecBlock< T, A > &b)
Swap contents with another SecBlock.
Definition secblock.h:1209
SecBlock::SecBlock
SecBlock(size_type size=0)
Construct a SecBlock with space for size elements.
Definition secblock.h:766
SecBlock::data
A::pointer data()
Provides a pointer to the first element in the memory block.
Definition secblock.h:857
SecBlock::CleanGrow
void CleanGrow(size_type newSize)
Change size and preserve contents.
Definition secblock.h:1179
SecBlock::operator!=
bool operator!=(const SecBlock< T, A > &t) const
Bitwise compare two SecBlocks.
Definition secblock.h:1111
SecBlock::SecBlock
SecBlock(const T *ptr, size_type len)
Construct a SecBlock from an array of elements.
Definition secblock.h:789
SecBlock::Append
void Append(size_type count, T value)
Append contents from a value.
Definition secblock.h:1004
SecBlock::operator==
bool operator==(const SecBlock< T, A > &t) const
Bitwise compare two SecBlocks.
Definition secblock.h:1095
SecBlock::Grow
void Grow(size_type newSize)
Change size and preserve contents.
Definition secblock.h:1160
SecBlock::New
void New(size_type newSize)
Change size without preserving contents.
Definition secblock.h:1126
SecBlock::SizeInBytes
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition secblock.h:885
SecBlock::Append
void Append(const SecBlock< T, A > &t)
Append contents from another SecBlock.
Definition secblock.h:973
SecBlock::SetMark
void SetMark(size_t count)
Sets the number of elements to zeroize.
Definition secblock.h:1037
SecBlock::Assign
void Assign(const T *ptr, size_type len)
Set contents and size from an array.
Definition secblock.h:898
SecBlock::BytePtr
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition secblock.h:876
SecBlock::end
const_iterator end() const
Provides a constant iterator pointing beyond the last element in the memory block.
Definition secblock.h:851
SecBlock::data
A::const_pointer data() const
Provides a pointer to the first element in the memory block.
Definition secblock.h:861
SecBlock::operator+=
SecBlock< T, A > & operator+=(const SecBlock< T, A > &t)
Append contents from another SecBlock.
Definition secblock.h:1059
SecBlock::empty
bool empty() const
Determines if the SecBlock is empty.
Definition secblock.h:871
SecBlock::BytePtr
const byte * BytePtr() const
Return a byte pointer to the first element in the memory block.
Definition secblock.h:880
SecBlock::operator=
SecBlock< T, A > & operator=(const SecBlock< T, A > &t)
Assign contents from another SecBlock.
Definition secblock.h:1047
SecBlock::size
size_type size() const
Provides the count of elements in the SecBlock.
Definition secblock.h:867
SecBlock::resize
void resize(size_type newSize)
Change size and preserve contents.
Definition secblock.h:1198
SecBlockWithHint
Stack-based SecBlock that grows into the heap.
Definition secblock.h:1268
SecBlockWithHint::SecBlockWithHint
SecBlockWithHint(size_t size)
construct a SecBlockWithHint with a count of elements
Definition secblock.h:1271
SecByteBlock
SecBlock<byte> typedef.
Definition secblock.h:1226
SecWordBlock
SecBlock<word> typedef.
Definition secblock.h:1228
config.h
Library configuration file.
CRYPTOPP_DLL_TEMPLATE_CLASS
#define CRYPTOPP_DLL_TEMPLATE_CLASS
Instantiate templates in a dynamic library.
Definition config_dll.h:72
misc.h
Utility functions for the Crypto++ library.
memset_z
void * memset_z(void *ptr, int val, size_t num)
Memory block initializer.
Definition misc.h:640
STDMAX
const T & STDMAX(const T &a, const T &b)
Replacement function for std::max.
Definition misc.h:668
SIZE_MAX
#define SIZE_MAX
The maximum value of a machine word.
Definition misc.h:120
SecureWipeArray
void SecureWipeArray(T *buf, size_t n)
Sets each element of an array to 0.
Definition misc.h:1700
memcpy_s
void memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count)
Bounds checking replacement for memcpy()
Definition misc.h:527
STDMIN
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition misc.h:657
IsAlignedOn
bool IsAlignedOn(const void *ptr, unsigned int alignment)
Determines whether ptr is aligned to a minimum value.
Definition misc.h:1436
memmove_s
void memmove_s(void *dest, size_t sizeInBytes, const void *src, size_t count)
Bounds checking replacement for memmove()
Definition misc.h:573
VerifyBufsEqual
CRYPTOPP_DLL bool VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count)
Performs a near constant-time comparison of two equally sized buffers.
CryptoPP
Crypto++ library namespace.
StandardReallocate
A::pointer StandardReallocate(A &alloc, T *oldPtr, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
Reallocation function.
Definition secblock.h:149
swap
void swap(::SecBlock< T, A > &a, ::SecBlock< T, A > &b)
Swap two SecBlocks.
Definition secblock.h:1289
stdcpp.h
Common C++ header files.
AllocatorWithCleanup::rebind
Template class member Rebind.
Definition secblock.h:272
CRYPTOPP_ASSERT
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition trap.h:68