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

Generated on Fri Feb 6 00:56:25 2009 for Crypto++ by  doxygen 1.4.7