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 Fri Jun 1 11:11:24 2007 for Crypto++ by  doxygen 1.5.2