- Main Page
- Namespaces
- Classes
- Files

# 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 (CRYPTOPP_BOOL_ALIGN16_ENABLED && 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_z(p, 0, n*sizeof(T));
    00134
    00135                 if (CRYPTOPP_BOOL_ALIGN16_ENABLED && 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 (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
    00266         CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16_ENABLED && 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_z(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 && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
    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_z(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, true> > 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 = true>
    00462 class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, 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