- 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 <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