Crypto++

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

secblock.h

    00001 // secblock.h - written and placed in the public domain by Wei Dai
    00002
    00003 #ifndef CRYPTOPP_SECBLOCK_H
    00004 #define CRYPTOPP_SECBLOCK_H
    00005
    00006 #include "config.h"
    00007 #include "misc.h"
    00008 #include <assert.h>
    00009
    00010 NAMESPACE_BEGIN(CryptoPP)
    00011
    00012 // ************** secure memory allocation ***************
    00013
    00014 template<class T>
    00015 class AllocatorBase
    00016 {
    00017 public:
    00018     typedef T value_type;
    00019     typedef size_t size_type;
    00020 #ifdef CRYPTOPP_MSVCRT6
    00021     typedef ptrdiff_t difference_type;
    00022 #else
    00023     typedef std::ptrdiff_t difference_type;
    00024 #endif
    00025     typedef T * pointer;
    00026     typedef const T * const_pointer;
    00027     typedef T & reference;
    00028     typedef const T & const_reference;
    00029
    00030     pointer address(reference r) const {return (&r);}
    00031     const_pointer address(const_reference r) const {return (&r); }
    00032     void construct(pointer p, const T& val) {new (p) T(val);}
    00033     void destroy(pointer p) {p->~T();}
    00034     size_type max_size() const {return ~size_type(0)/sizeof(T);}    // switch to std::numeric_limits<T>::max later
    00035
    00036 protected:
    00037     static void CheckSize(size_t n)
    00038     {
    00039         if (n > ~size_t(0) / sizeof(T))
    00040             throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
    00041     }
    00042 };
    00043
    00044 #define CRYPTOPP_INHERIT_ALLOCATOR_TYPES    \
    00045 typedef typename AllocatorBase<T>::value_type value_type;\
    00046 typedef typename AllocatorBase<T>::size_type size_type;\
    00047 typedef typename AllocatorBase<T>::difference_type difference_type;\
    00048 typedef typename AllocatorBase<T>::pointer pointer;\
    00049 typedef typename AllocatorBase<T>::const_pointer const_pointer;\
    00050 typedef typename AllocatorBase<T>::reference reference;\
    00051 typedef typename AllocatorBase<T>::const_reference const_reference;
    00052
    00053 #if defined(_MSC_VER) && (_MSC_VER < 1300)
    00054 // this pragma causes an internal compiler error if placed immediately before std::swap(a, b)
    00055 #pragma warning(push)
    00056 #pragma warning(disable: 4700)  // VC60 workaround: don't know how to get rid of this warning
    00057 #endif
    00058
    00059 template <class T, class A>
    00060 typename A::pointer StandardReallocate(A& a, T *p, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
    00061 {
    00062     if (oldSize == newSize)
    00063         return p;
    00064
    00065     if (preserve)
    00066     {
    00067         typename A::pointer newPointer = a.allocate(newSize, NULL);
    00068         memcpy_s(newPointer, sizeof(T)*newSize, p, sizeof(T)*STDMIN(oldSize, newSize));
    00069         a.deallocate(p, oldSize);
    00070         return newPointer;
    00071     }
    00072     else
    00073     {
    00074         a.deallocate(p, oldSize);
    00075         return a.allocate(newSize, NULL);
    00076     }
    00077 }
    00078
    00079 #if defined(_MSC_VER) && (_MSC_VER < 1300)
    00080 #pragma warning(pop)
    00081 #endif
    00082
    00083 template <class T, bool T_Align16 = false>
    00084 class AllocatorWithCleanup : public AllocatorBase<T>
    00085 {
    00086 public:
    00087     CRYPTOPP_INHERIT_ALLOCATOR_TYPES
    00088
    00089     pointer allocate(size_type n, const void * = NULL)
    00090     {
    00091         this->CheckSize(n);
    00092         if (n == 0)
    00093             return NULL;
    00094
    00095 #if CRYPTOPP_BOOL_ALIGN16_ENABLED
    00096         if (T_Align16 && n*sizeof(T) >= 16)
    00097             return (pointer)AlignedAllocate(n*sizeof(T));
    00098 #endif
    00099
    00100         return (pointer)UnalignedAllocate(n*sizeof(T));
    00101     }
    00102
    00103     void deallocate(void *p, size_type n)
    00104     {
    00105         SecureWipeArray((pointer)p, n);
    00106
    00107 #if CRYPTOPP_BOOL_ALIGN16_ENABLED
    00108         if (T_Align16 && n*sizeof(T) >= 16)
    00109             return AlignedDeallocate(p);
    00110 #endif
    00111
    00112         UnalignedDeallocate(p);
    00113     }
    00114
    00115     pointer reallocate(T *p, size_type oldSize, size_type newSize, bool preserve)
    00116     {
    00117         return StandardReallocate(*this, p, oldSize, newSize, preserve);
    00118     }
    00119
    00120     // VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a
    00121     // template class member called rebind".
    00122     template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; };
    00123 #if _MSC_VER >= 1500
    00124     AllocatorWithCleanup() {}
    00125     template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {}
    00126 #endif
    00127 };
    00128
    00129 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
    00130 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
    00131 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
    00132 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
    00133 #if CRYPTOPP_BOOL_X86
    00134 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>;   // for Integer
    00135 #endif
    00136
    00137 template <class T>
    00138 class NullAllocator : public AllocatorBase<T>
    00139 {
    00140 public:
    00141     CRYPTOPP_INHERIT_ALLOCATOR_TYPES
    00142
    00143     pointer allocate(size_type n, const void * = NULL)
    00144     {
    00145         assert(false);
    00146         return NULL;
    00147     }
    00148
    00149     void deallocate(void *p, size_type n)
    00150     {
    00151         assert(false);
    00152     }
    00153
    00154     size_type max_size() const {return 0;}
    00155 };
    00156
    00157 // This allocator can't be used with standard collections because
    00158 // they require that all objects of the same allocator type are equivalent.
    00159 // So this is for use with SecBlock only.
    00160 template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
    00161 class FixedSizeAllocatorWithCleanup : public AllocatorBase<T>
    00162 {
    00163 public:
    00164     CRYPTOPP_INHERIT_ALLOCATOR_TYPES
    00165
    00166     FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
    00167
    00168     pointer allocate(size_type n)
    00169     {
    00170         assert(IsAlignedOn(m_array, 8));
    00171
    00172         if (n <= S && !m_allocated)
    00173         {
    00174             m_allocated = true;
    00175             return GetAlignedArray();
    00176         }
    00177         else
    00178             return m_fallbackAllocator.allocate(n);
    00179     }
    00180
    00181     pointer allocate(size_type n, const void *hint)
    00182     {
    00183         if (n <= S && !m_allocated)
    00184         {
    00185             m_allocated = true;
    00186             return GetAlignedArray();
    00187         }
    00188         else
    00189             return m_fallbackAllocator.allocate(n, hint);
    00190     }
    00191
    00192     void deallocate(void *p, size_type n)
    00193     {
    00194         if (p == GetAlignedArray())
    00195         {
    00196             assert(n <= S);
    00197             assert(m_allocated);
    00198             m_allocated = false;
    00199             SecureWipeArray((pointer)p, n);
    00200         }
    00201         else
    00202             m_fallbackAllocator.deallocate(p, n);
    00203     }
    00204
    00205     pointer reallocate(pointer p, size_type oldSize, size_type newSize, bool preserve)
    00206     {
    00207         if (p == GetAlignedArray() && newSize <= S)
    00208         {
    00209             assert(oldSize <= S);
    00210             if (oldSize > newSize)
    00211                 SecureWipeArray(p+newSize, oldSize-newSize);
    00212             return p;
    00213         }
    00214
    00215         pointer newPointer = allocate(newSize, NULL);
    00216         if (preserve)
    00217             memcpy(newPointer, p, sizeof(T)*STDMIN(oldSize, newSize));
    00218         deallocate(p, oldSize);
    00219         return newPointer;
    00220     }
    00221
    00222     size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);}
    00223
    00224 private:
    00225 #ifdef __BORLANDC__
    00226     T* GetAlignedArray() {return m_array;}
    00227     T m_array[S];
    00228 #else
    00229     T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
    00230     CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? S+8/sizeof(T) : S];
    00231 #endif
    00232     A m_fallbackAllocator;
    00233     bool m_allocated;
    00234 };
    00235
    00236 //! a block of memory allocated using A
    00237 template <class T, class A = AllocatorWithCleanup<T> >
    00238 class SecBlock
    00239 {
    00240 public:
    00241     typedef typename A::value_type value_type;
    00242     typedef typename A::pointer iterator;
    00243     typedef typename A::const_pointer const_iterator;
    00244     typedef typename A::size_type size_type;
    00245
    00246     explicit SecBlock(size_type size=0)
    00247         : m_size(size) {m_ptr = m_alloc.allocate(size, NULL);}
    00248     SecBlock(const SecBlock<T, A> &t)
    00249         : m_size(t.m_size) {m_ptr = m_alloc.allocate(m_size, NULL); memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));}
    00250     SecBlock(const T *t, size_type len)
    00251         : m_size(len)
    00252     {
    00253         m_ptr = m_alloc.allocate(len, NULL);
    00254         if (t == NULL)
    00255             memset_z(m_ptr, 0, len*sizeof(T));
    00256         else
    00257             memcpy(m_ptr, t, len*sizeof(T));
    00258     }
    00259
    00260     ~SecBlock()
    00261         {m_alloc.deallocate(m_ptr, m_size);}
    00262
    00263 #ifdef __BORLANDC__
    00264     operator T *() const
    00265         {return (T*)m_ptr;}
    00266 #else
    00267     operator const void *() const
    00268         {return m_ptr;}
    00269     operator void *()
    00270         {return m_ptr;}
    00271
    00272     operator const T *() const
    00273         {return m_ptr;}
    00274     operator T *()
    00275         {return m_ptr;}
    00276 #endif
    00277
    00278 //  T *operator +(size_type offset)
    00279 //      {return m_ptr+offset;}
    00280
    00281 //  const T *operator +(size_type offset) const
    00282 //      {return m_ptr+offset;}
    00283
    00284 //  T& operator[](size_type index)
    00285 //      {assert(index >= 0 && index < m_size); return m_ptr[index];}
    00286
    00287 //  const T& operator[](size_type index) const
    00288 //      {assert(index >= 0 && index < m_size); return m_ptr[index];}
    00289
    00290     iterator begin()
    00291         {return m_ptr;}
    00292     const_iterator begin() const
    00293         {return m_ptr;}
    00294     iterator end()
    00295         {return m_ptr+m_size;}
    00296     const_iterator end() const
    00297         {return m_ptr+m_size;}
    00298
    00299     typename A::pointer data() {return m_ptr;}
    00300     typename A::const_pointer data() const {return m_ptr;}
    00301
    00302     size_type size() const {return m_size;}
    00303     bool empty() const {return m_size == 0;}
    00304
    00305     byte * BytePtr() {return (byte *)m_ptr;}
    00306     const byte * BytePtr() const {return (const byte *)m_ptr;}
    00307     size_type SizeInBytes() const {return m_size*sizeof(T);}
    00308
    00309     //! set contents and size
    00310     void Assign(const T *t, size_type len)
    00311     {
    00312         New(len);
    00313         memcpy_s(m_ptr, m_size*sizeof(T), t, len*sizeof(T));
    00314     }
    00315
    00316     //! copy contents and size from another SecBlock
    00317     void Assign(const SecBlock<T, A> &t)
    00318     {
    00319         if (this != &t)
    00320         {
    00321             New(t.m_size);
    00322             memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));
    00323         }
    00324     }
    00325
    00326     SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
    00327     {
    00328         Assign(t);
    00329         return *this;
    00330     }
    00331
    00332     // append to this object
    00333     SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
    00334     {
    00335         size_type oldSize = m_size;
    00336         Grow(m_size+t.m_size);
    00337         memcpy_s(m_ptr+oldSize, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
    00338         return *this;
    00339     }
    00340
    00341     // append operator
    00342     SecBlock<T, A> operator+(const SecBlock<T, A> &t)
    00343     {
    00344         SecBlock<T, A> result(m_size+t.m_size);
    00345         memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
    00346         memcpy_s(result.m_ptr+m_size, t.m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
    00347         return result;
    00348     }
    00349
    00350     bool operator==(const SecBlock<T, A> &t) const
    00351     {
    00352         return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
    00353     }
    00354
    00355     bool operator!=(const SecBlock<T, A> &t) const
    00356     {
    00357         return !operator==(t);
    00358     }
    00359
    00360     //! change size, without preserving contents
    00361     void New(size_type newSize)
    00362     {
    00363         m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
    00364         m_size = newSize;
    00365     }
    00366
    00367     //! change size and set contents to 0
    00368     void CleanNew(size_type newSize)
    00369     {
    00370         New(newSize);
    00371         memset_z(m_ptr, 0, m_size*sizeof(T));
    00372     }
    00373
    00374     //! change size only if newSize > current size. contents are preserved
    00375     void Grow(size_type newSize)
    00376     {
    00377         if (newSize > m_size)
    00378         {
    00379             m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
    00380             m_size = newSize;
    00381         }
    00382     }
    00383
    00384     //! change size only if newSize > current size. contents are preserved and additional area is set to 0
    00385     void CleanGrow(size_type newSize)
    00386     {
    00387         if (newSize > m_size)
    00388         {
    00389             m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
    00390             memset(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
    00391             m_size = newSize;
    00392         }
    00393     }
    00394
    00395     //! change size and preserve contents
    00396     void resize(size_type newSize)
    00397     {
    00398         m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
    00399         m_size = newSize;
    00400     }
    00401
    00402     //! swap contents and size with another SecBlock
    00403     void swap(SecBlock<T, A> &b)
    00404     {
    00405         std::swap(m_alloc, b.m_alloc);
    00406         std::swap(m_size, b.m_size);
    00407         std::swap(m_ptr, b.m_ptr);
    00408     }
    00409
    00410 //private:
    00411     A m_alloc;
    00412     size_type m_size;
    00413     T *m_ptr;
    00414 };
    00415
    00416 typedef SecBlock<byte> SecByteBlock;
    00417 typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
    00418 typedef SecBlock<word> SecWordBlock;
    00419
    00420 //! a SecBlock with fixed size, allocated statically
    00421 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
    00422 class FixedSizeSecBlock : public SecBlock<T, A>
    00423 {
    00424 public:
    00425     explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
    00426 };
    00427
    00428 template <class T, unsigned int S, bool T_Align16 = true>
    00429 class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
    00430 {
    00431 };
    00432
    00433 //! a SecBlock that preallocates size S statically, and uses the heap when this size is exceeded
    00434 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
    00435 class SecBlockWithHint : public SecBlock<T, A>
    00436 {
    00437 public:
    00438     explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
    00439 };
    00440
    00441 template<class T, bool A, class U, bool B>
    00442 inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);}
    00443 template<class T, bool A, class U, bool B>
    00444 inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);}
    00445
    00446 NAMESPACE_END
    00447
    00448 NAMESPACE_BEGIN(std)
    00449 template <class T, class A>
    00450 inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
    00451 {
    00452     a.swap(b);
    00453 }
    00454
    00455 #if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
    00456 // working for STLport 5.1.3 and MSVC 6 SP5
    00457 template <class _Tp1, class _Tp2>
    00458 inline CryptoPP::AllocatorWithCleanup<_Tp2>&
    00459 __stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
    00460 {
    00461     return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);
    00462 }
    00463 #endif
    00464
    00465 NAMESPACE_END
    00466
    00467 #endif