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

Generated on Thu Jul 5 22:21:38 2007 for Crypto++ by  doxygen 1.5.2