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