source: trunk/src-cryptopp/secblock.h

Last change on this file was e230cb0, checked in by David Stainton <dstainton415@…>, at 2016-10-12T13:27:29Z

Add cryptopp from tag CRYPTOPP_5_6_5

  • Property mode set to 100644
File size: 32.0 KB
Line 
1// secblock.h - written and placed in the public domain by Wei Dai
2
3//! \file secblock.h
4//! \brief Classes and functions for secure memory allocations.
5
6#ifndef CRYPTOPP_SECBLOCK_H
7#define CRYPTOPP_SECBLOCK_H
8
9#include "config.h"
10#include "stdcpp.h"
11#include "misc.h"
12
13#if CRYPTOPP_MSC_VERSION
14# pragma warning(push)
15# pragma warning(disable: 4700)
16# if (CRYPTOPP_MSC_VERSION >= 1400)
17#  pragma warning(disable: 6386)
18# endif
19#endif
20
21NAMESPACE_BEGIN(CryptoPP)
22
23// ************** secure memory allocation ***************
24
25//! \class AllocatorBase
26//! \brief Base class for all allocators used by SecBlock
27//! \tparam T the class or type
28template<class T>
29class AllocatorBase
30{
31public:
32        typedef T value_type;
33        typedef size_t size_type;
34#ifdef CRYPTOPP_MSVCRT6
35        typedef ptrdiff_t difference_type;
36#else
37        typedef std::ptrdiff_t difference_type;
38#endif
39        typedef T * pointer;
40        typedef const T * const_pointer;
41        typedef T & reference;
42        typedef const T & const_reference;
43
44        pointer address(reference r) const {return (&r);}
45        const_pointer address(const_reference r) const {return (&r); }
46        void construct(pointer p, const T& val) {new (p) T(val);}
47        void destroy(pointer p) {CRYPTOPP_UNUSED(p); p->~T();}
48
49        //! \brief Returns the maximum number of elements the allocator can provide
50        //! \returns the maximum number of elements the allocator can provide
51        //! \details Internally, preprocessor macros are used rather than std::numeric_limits
52        //!   because the latter is \a not a \a constexpr. Some compilers, like Clang, do not
53        //!   optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear
54        //!   to optimize it well in either form.
55        CRYPTOPP_CONSTEXPR size_type max_size() const {return (SIZE_MAX/sizeof(T));}
56
57#if defined(CRYPTOPP_CXX11_VARIADIC_TEMPLATES) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
58
59        //! \brief Constructs a new U using variadic arguments
60        //! \tparam U the type to be forwarded
61        //! \tparam Args the arguments to be forwarded
62        //! \param ptr pointer to type U
63        //! \param args variadic arguments
64        //! \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES
65        //!   is defined. The define is controlled by compiler versions detected in config.h.
66    template<typename U, typename... Args>
67    void construct(U* ptr, Args&&... args) {::new ((void*)ptr) U(std::forward<Args>(args)...);}
68
69        //! \brief Destroys an U constructed with variadic arguments
70        //! \tparam U the type to be forwarded
71        //! \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES
72        //!   is defined. The define is controlled by compiler versions detected in config.h.
73    template<typename U>
74    void destroy(U* ptr) {if(ptr) ptr->~U();}
75
76#endif
77
78protected:
79
80        //! \brief Verifies the allocator can satisfy a request based on size
81        //! \param size the size of the allocation, in elements
82        //! \throws InvalidArgument
83        //! \details CheckSize verifies the number of elements requested is valid.
84        //! \details If size is greater than max_size(), then InvalidArgument is thrown.
85        //!   The library throws InvalidArgument if the size is too large to satisfy.
86        //! \details Internally, preprocessor macros are used rather than std::numeric_limits
87        //!   because the latter is \a not a \a constexpr. Some compilers, like Clang, do not
88        //!   optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear
89        //!   to optimize it well in either form.
90        //! \note size is the count of elements, and not the number of bytes
91        static void CheckSize(size_t size)
92        {
93                // C++ throws std::bad_alloc (C++03) or std::bad_array_new_length (C++11) here.
94                if (size > (SIZE_MAX/sizeof(T)))
95                        throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
96        }
97};
98
99#define CRYPTOPP_INHERIT_ALLOCATOR_TYPES        \
100typedef typename AllocatorBase<T>::value_type value_type;\
101typedef typename AllocatorBase<T>::size_type size_type;\
102typedef typename AllocatorBase<T>::difference_type difference_type;\
103typedef typename AllocatorBase<T>::pointer pointer;\
104typedef typename AllocatorBase<T>::const_pointer const_pointer;\
105typedef typename AllocatorBase<T>::reference reference;\
106typedef typename AllocatorBase<T>::const_reference const_reference;
107
108//! \brief Reallocation function
109//! \tparam T the class or type
110//! \tparam A the class or type's allocator
111//! \param alloc the allocator
112//! \param oldPtr the previous allocation
113//! \param oldSize the size of the previous allocation
114//! \param newSize the new, requested size
115//! \param preserve flag that indicates if the old allocation should be preserved
116//! \note oldSize and newSize are the count of elements, and not the
117//!   number of bytes.
118template <class T, class A>
119typename A::pointer StandardReallocate(A& alloc, T *oldPtr, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
120{
121        CRYPTOPP_ASSERT((oldPtr && oldSize) || !(oldPtr || oldSize));
122        if (oldSize == newSize)
123                return oldPtr;
124
125        if (preserve)
126        {
127                typename A::pointer newPointer = alloc.allocate(newSize, NULL);
128                const size_t copySize = STDMIN(oldSize, newSize) * sizeof(T);
129
130                if (oldPtr && newPointer) {memcpy_s(newPointer, copySize, oldPtr, copySize);}
131                alloc.deallocate(oldPtr, oldSize);
132                return newPointer;
133        }
134        else
135        {
136                alloc.deallocate(oldPtr, oldSize);
137                return alloc.allocate(newSize, NULL);
138        }
139}
140
141//! \class AllocatorWithCleanup
142//! \brief Allocates a block of memory with cleanup
143//! \tparam T class or type
144//! \tparam T_Align16 boolean that determines whether allocations should be aligned on 16-byte boundaries
145//! \details If T_Align16 is true, then AllocatorWithCleanup calls AlignedAllocate()
146//!    for memory allocations. If T_Align16 is false, then AllocatorWithCleanup() calls
147//!    UnalignedAllocate() for memory allocations.
148//! \details Template parameter T_Align16 is effectively controlled by cryptlib.h and mirrors
149//!    CRYPTOPP_BOOL_ALIGN16. CRYPTOPP_BOOL_ALIGN16 is often used as the template parameter.
150template <class T, bool T_Align16 = false>
151class AllocatorWithCleanup : public AllocatorBase<T>
152{
153public:
154        CRYPTOPP_INHERIT_ALLOCATOR_TYPES
155
156        //! \brief Allocates a block of memory
157        //! \param ptr the size of the allocation
158        //! \param size the size of the allocation, in elements
159        //! \returns a memory block
160        //! \throws InvalidArgument
161        //! \details allocate() first checks the size of the request. If it is non-0
162        //!   and less than max_size(), then an attempt is made to fulfill the request using either
163        //!   AlignedAllocate() or UnalignedAllocate().
164        //! \details AlignedAllocate() is used if T_Align16 is true.
165        //!   UnalignedAllocate() used if T_Align16 is false.
166        //! \details This is the C++ *Placement New* operator. ptr is not used, and the function
167        //!   CRYPTOPP_ASSERTs in Debug builds if ptr is non-NULL.
168        //! \sa CallNewHandler() for the methods used to recover from a failed
169        //!   allocation attempt.
170        //! \note size is the count of elements, and not the number of bytes
171        pointer allocate(size_type size, const void *ptr = NULL)
172        {
173                CRYPTOPP_UNUSED(ptr); CRYPTOPP_ASSERT(ptr == NULL);
174                this->CheckSize(size);
175                if (size == 0)
176                        return NULL;
177
178#if CRYPTOPP_BOOL_ALIGN16
179                // TODO: should this need the test 'size*sizeof(T) >= 16'?
180                if (T_Align16 && size*sizeof(T) >= 16)
181                        return (pointer)AlignedAllocate(size*sizeof(T));
182#endif
183
184                return (pointer)UnalignedAllocate(size*sizeof(T));
185        }
186
187        //! \brief Deallocates a block of memory
188        //! \param ptr the pointer for the allocation
189        //! \param size the size of the allocation, in elements
190        //! \details Internally, SecureWipeArray() is called before deallocating the memory.
191        //!   Once the memory block is wiped or zeroized, AlignedDeallocate() or
192        //!   UnalignedDeallocate() is called.
193        //! \details AlignedDeallocate() is used if T_Align16 is true.
194        //!   UnalignedDeallocate() used if T_Align16 is false.
195        void deallocate(void *ptr, size_type size)
196        {
197                CRYPTOPP_ASSERT((ptr && size) || !(ptr || size));
198                SecureWipeArray((pointer)ptr, size);
199
200#if CRYPTOPP_BOOL_ALIGN16
201                if (T_Align16 && size*sizeof(T) >= 16)
202                        return AlignedDeallocate(ptr);
203#endif
204
205                UnalignedDeallocate(ptr);
206        }
207
208        //! \brief Reallocates a block of memory
209        //! \param oldPtr the previous allocation
210        //! \param oldSize the size of the previous allocation
211        //! \param newSize the new, requested size
212        //! \param preserve flag that indicates if the old allocation should be preserved
213        //! \returns pointer to the new memory block
214        //! \details Internally, reallocate() calls StandardReallocate().
215        //! \details If preserve is true, then index 0 is used to begin copying the
216        //!   old memory block to the new one. If the block grows, then the old array
217        //!   is copied in its entirety. If the block shrinks, then only newSize
218        //!   elements are copied from the old block to the new one.
219        //! \note oldSize and newSize are the count of elements, and not the
220        //!   number of bytes.
221        pointer reallocate(T *oldPtr, size_type oldSize, size_type newSize, bool preserve)
222        {
223                CRYPTOPP_ASSERT((oldPtr && oldSize) || !(oldPtr || oldSize));
224                return StandardReallocate(*this, oldPtr, oldSize, newSize, preserve);
225        }
226
227        //! \brief Template class memeber Rebind
228        //! \tparam T allocated class or type
229        //! \tparam T_Align16 boolean that determines whether allocations should be aligned on 16-byte boundaries
230        //! \tparam U bound class or type
231        //! \details Rebind allows a container class to allocate a different type of object
232        //!   to store elements. For example, a std::list will allocate std::list_node to
233        //!   store elements in the list.
234        //! \details VS.NET STL enforces the policy of "All STL-compliant allocators
235        //!   have to provide a template class member called rebind".
236    template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; };
237#if _MSC_VER >= 1500
238        AllocatorWithCleanup() {}
239        template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {}
240#endif
241};
242
243CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
244CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
245CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
246CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
247#if defined(CRYPTOPP_WORD128_AVAILABLE)
248CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word128, true>; // for Integer
249#endif
250#if CRYPTOPP_BOOL_X86
251CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>;    // for Integer
252#endif
253
254//! \class NullAllocator
255//! \brief NULL allocator
256//! \tparam T class or type
257//! \details A NullAllocator is useful for fixed-size, stack based allocations
258//!   (i.e., static arrays used by FixedSizeAllocatorWithCleanup).
259//! \details A NullAllocator always returns 0 for max_size(), and always returns
260//!   NULL for allocation requests. Though the allocator does not allocate at
261//!   runtime, it does perform a secure wipe or zeroization during cleanup.
262template <class T>
263class NullAllocator : public AllocatorBase<T>
264{
265public:
266        //LCOV_EXCL_START
267        CRYPTOPP_INHERIT_ALLOCATOR_TYPES
268
269        // TODO: should this return NULL or throw bad_alloc? Non-Windows C++ standard
270        // libraries always throw. And late mode Windows throws. Early model Windows
271        // (circa VC++ 6.0) returned NULL.
272        pointer allocate(size_type n, const void* unused = NULL)
273        {
274                CRYPTOPP_UNUSED(n); CRYPTOPP_UNUSED(unused);
275                CRYPTOPP_ASSERT(false); return NULL;
276        }
277
278        void deallocate(void *p, size_type n)
279        {
280                CRYPTOPP_UNUSED(p); CRYPTOPP_UNUSED(n);
281                CRYPTOPP_ASSERT(false);
282        }
283
284        CRYPTOPP_CONSTEXPR size_type max_size() const {return 0;}
285        //LCOV_EXCL_STOP
286};
287
288//! \class FixedSizeAllocatorWithCleanup
289//! \brief Static secure memory block with cleanup
290//! \tparam T class or type
291//! \tparam S fixed-size of the stack-based memory block, in elements
292//! \tparam A AllocatorBase derived class for allocation and cleanup
293//! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
294//!    based allocation at compile time. The class can grow its memory
295//!    block at runtime if a suitable allocator is available. If size
296//!    grows beyond S and a suitable allocator is available, then the
297//!    statically allocated array is obsoleted.
298//! \note This allocator can't be used with standard collections because
299//!   they require that all objects of the same allocator type are equivalent.
300template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
301class FixedSizeAllocatorWithCleanup : public AllocatorBase<T>
302{
303public:
304        CRYPTOPP_INHERIT_ALLOCATOR_TYPES
305
306        //! \brief Constructs a FixedSizeAllocatorWithCleanup
307        FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
308
309        //! \brief Allocates a block of memory
310        //! \param size size of the memory block, in elements
311        //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based
312        //!   allocation at compile time. If size is less than or equal to
313        //!   <tt>S</tt>, then a pointer to the static array is returned.
314        //! \details The class can grow its memory block at runtime if a suitable
315        //!   allocator is available. If size grows beyond S and a suitable
316        //!   allocator is available, then the statically allocated array is
317        //!   obsoleted. If a suitable allocator is \a not available, as with a
318        //!   NullAllocator, then the function returns NULL and a runtime error
319        //!   eventually occurs.
320        //! \sa reallocate(), SecBlockWithHint
321        pointer allocate(size_type size)
322        {
323                CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8));
324
325                if (size <= S && !m_allocated)
326                {
327                        m_allocated = true;
328                        return GetAlignedArray();
329                }
330                else
331                        return m_fallbackAllocator.allocate(size);
332        }
333
334        //! \brief Allocates a block of memory
335        //! \param size size of the memory block, in elements
336        //! \param hint an unused hint
337        //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
338        //!   based allocation at compile time. If size is less than or equal to
339        //!   S, then a pointer to the static array is returned.
340        //! \details The class can grow its memory block at runtime if a suitable
341        //!   allocator is available. If size grows beyond S and a suitable
342        //!   allocator is available, then the statically allocated array is
343        //!   obsoleted. If a suitable allocator is \a not available, as with a
344        //!   NullAllocator, then the function returns NULL and a runtime error
345        //!   eventually occurs.
346        //! \sa reallocate(), SecBlockWithHint
347        pointer allocate(size_type size, const void *hint)
348        {
349                if (size <= S && !m_allocated)
350                {
351                        m_allocated = true;
352                        return GetAlignedArray();
353                }
354                else
355                        return m_fallbackAllocator.allocate(size, hint);
356        }
357
358        //! \brief Deallocates a block of memory
359        //! \param ptr a pointer to the memory block to deallocate
360        //! \param size size of the memory block, in elements
361        //! \details The memory block is wiped or zeroized before deallocation.
362        //!   If the statically allocated memory block is active, then no
363        //!   additional actions are taken after the wipe.
364        //! \details If a dynamic memory block is active, then the pointer and
365        //!   size are passed to the allocator for deallocation.
366        void deallocate(void *ptr, size_type size)
367        {
368                if (ptr == GetAlignedArray())
369                {
370                        CRYPTOPP_ASSERT(size <= S);
371                        CRYPTOPP_ASSERT(m_allocated);
372                        m_allocated = false;
373                        SecureWipeArray((pointer)ptr, size);
374                }
375                else
376                        m_fallbackAllocator.deallocate(ptr, size);
377        }
378
379        //! \brief Reallocates a block of memory
380        //! \param oldPtr the previous allocation
381        //! \param oldSize the size of the previous allocation
382        //! \param newSize the new, requested size
383        //! \param preserve flag that indicates if the old allocation should be preserved
384        //! \returns pointer to the new memory block
385        //! \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-
386        //!   based allocation at compile time. If size is less than or equal to
387        //!   S, then a pointer to the static array is returned.
388        //! \details The class can grow its memory block at runtime if a suitable
389        //!   allocator is available. If size grows beyond S and a suitable
390        //!   allocator is available, then the statically allocated array is
391        //!   obsoleted. If a suitable allocator is \a not available, as with a
392        //!   NullAllocator, then the function returns NULL and a runtime error
393        //!   eventually occurs.
394        //! \note size is the count of elements, and not the number of bytes.
395        //! \sa reallocate(), SecBlockWithHint
396        pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve)
397        {
398                if (oldPtr == GetAlignedArray() && newSize <= S)
399                {
400                        CRYPTOPP_ASSERT(oldSize <= S);
401                        if (oldSize > newSize)
402                                SecureWipeArray(oldPtr+newSize, oldSize-newSize);
403                        return oldPtr;
404                }
405
406                pointer newPointer = allocate(newSize, NULL);
407                if (preserve && newSize)
408                {
409                        const size_t copySize = STDMIN(oldSize, newSize);
410                        memcpy_s(newPointer, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize);
411                }
412                deallocate(oldPtr, oldSize);
413                return newPointer;
414        }
415
416        CRYPTOPP_CONSTEXPR size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);}
417
418private:
419
420#ifdef __BORLANDC__
421        T* GetAlignedArray() {return m_array;}
422        T m_array[S];
423#else
424        T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16 && T_Align16) ? (T*)(void *)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
425        CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16 && T_Align16) ? S+8/sizeof(T) : S];
426#endif
427
428        A m_fallbackAllocator;
429        bool m_allocated;
430};
431
432//! \class SecBlock
433//! \brief Secure memory block with allocator and cleanup
434//! \tparam T a class or type
435//! \tparam A AllocatorWithCleanup derived class for allocation and cleanup
436template <class T, class A = AllocatorWithCleanup<T> >
437class SecBlock
438{
439public:
440        typedef typename A::value_type value_type;
441        typedef typename A::pointer iterator;
442        typedef typename A::const_pointer const_iterator;
443        typedef typename A::size_type size_type;
444
445        //! \brief Construct a SecBlock with space for size elements.
446        //! \param size the size of the allocation, in elements
447        //! \throws std::bad_alloc
448        //! \details The elements are not initialized.
449        //! \note size is the count of elements, and not the number of bytes
450        explicit SecBlock(size_type size=0)
451                : m_size(size), m_ptr(m_alloc.allocate(size, NULL)) { }
452
453        //! \brief Copy construct a SecBlock from another SecBlock
454        //! \param t the other SecBlock
455        //! \throws std::bad_alloc
456        SecBlock(const SecBlock<T, A> &t)
457                : m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULL)) {
458                        CRYPTOPP_ASSERT((!t.m_ptr && !m_size) || (t.m_ptr && m_size));
459                        if (t.m_ptr) {memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));}
460                }
461
462        //! \brief Construct a SecBlock from an array of elements.
463        //! \param ptr a pointer to an array of T
464        //! \param len the number of elements in the memory block
465        //! \throws std::bad_alloc
466        //! \details If <tt>ptr!=NULL</tt> and <tt>len!=0</tt>, then the block is initialized from the pointer ptr.
467        //!    If <tt>ptr==NULL</tt> and <tt>len!=0</tt>, then the block is initialized to 0.
468        //!    Otherwise, the block is empty and \a not initialized.
469        //! \note size is the count of elements, and not the number of bytes
470        SecBlock(const T *ptr, size_type len)
471                : m_size(len), m_ptr(m_alloc.allocate(len, NULL)) {
472                        CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size));
473                        if (ptr && m_ptr)
474                                memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));
475                        else if (m_size)
476                                memset(m_ptr, 0, m_size*sizeof(T));
477                }
478
479        ~SecBlock()
480                {m_alloc.deallocate(m_ptr, m_size);}
481
482#ifdef __BORLANDC__
483        operator T *() const
484                {return (T*)m_ptr;}
485#else
486        operator const void *() const
487                {return m_ptr;}
488        operator void *()
489                {return m_ptr;}
490
491        operator const T *() const
492                {return m_ptr;}
493        operator T *()
494                {return m_ptr;}
495#endif
496
497        //! \brief Provides an iterator pointing to the first element in the memory block
498        //! \returns iterator pointing to the first element in the memory block
499        iterator begin()
500                {return m_ptr;}
501        //! \brief Provides a constant iterator pointing to the first element in the memory block
502        //! \returns constant iterator pointing to the first element in the memory block
503        const_iterator begin() const
504                {return m_ptr;}
505        //! \brief Provides an iterator pointing beyond the last element in the memory block
506        //! \returns iterator pointing beyond the last element in the memory block
507        iterator end()
508                {return m_ptr+m_size;}
509        //! \brief Provides a constant iterator pointing beyond the last element in the memory block
510        //! \returns constant iterator pointing beyond the last element in the memory block
511        const_iterator end() const
512                {return m_ptr+m_size;}
513
514        //! \brief Provides a pointer to the first element in the memory block
515        //! \returns pointer to the first element in the memory block
516        typename A::pointer data() {return m_ptr;}
517        //! \brief Provides a pointer to the first element in the memory block
518        //! \returns constant pointer to the first element in the memory block
519        typename A::const_pointer data() const {return m_ptr;}
520
521        //! \brief Provides the count of elements in the SecBlock
522        //! \returns number of elements in the memory block
523        //! \note the return value is the count of elements, and not the number of bytes
524        size_type size() const {return m_size;}
525        //! \brief Determines if the SecBlock is empty
526        //! \returns true if number of elements in the memory block is 0, false otherwise
527        bool empty() const {return m_size == 0;}
528
529        //! \brief Provides a byte pointer to the first element in the memory block
530        //! \returns byte pointer to the first element in the memory block
531        byte * BytePtr() {return (byte *)m_ptr;}
532        //! \brief Return a byte pointer to the first element in the memory block
533        //! \returns constant byte pointer to the first element in the memory block
534        const byte * BytePtr() const {return (const byte *)m_ptr;}
535        //! \brief Provides the number of bytes in the SecBlock
536        //! \return the number of bytes in the memory block
537        //! \note the return value is the number of bytes, and not count of elements.
538        size_type SizeInBytes() const {return m_size*sizeof(T);}
539
540        //! \brief Set contents and size from an array
541        //! \param ptr a pointer to an array of T
542        //! \param len the number of elements in the memory block
543        //! \details If the memory block is reduced in size, then the reclaimed memory is set to 0.
544        void Assign(const T *ptr, size_type len)
545        {
546                New(len);
547                if (m_ptr && ptr && len)
548                        {memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));}
549        }
550
551        //! \brief Copy contents from another SecBlock
552        //! \param t the other SecBlock
553        //! \details Assign checks for self assignment.
554        //! \details If the memory block is reduced in size, then the reclaimed memory is set to 0.
555        void Assign(const SecBlock<T, A> &t)
556        {
557                if (this != &t)
558                {
559                        New(t.m_size);
560                        if (m_ptr && t.m_ptr && t.m_size)
561                                {memcpy_s(m_ptr, m_size*sizeof(T), t, t.m_size*sizeof(T));}
562                }
563        }
564
565        //! \brief Assign contents from another SecBlock
566        //! \param t the other SecBlock
567        //! \details Internally, operator=() calls Assign().
568        //! \details If the memory block is reduced in size, then the reclaimed memory is set to 0.
569        SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
570        {
571                // Assign guards for self-assignment
572                Assign(t);
573                return *this;
574        }
575
576        //! \brief Append contents from another SecBlock
577        //! \param t the other SecBlock
578        //! \details Internally, this SecBlock calls Grow and then appends t.
579        SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
580        {
581                CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size));
582
583                if(t.m_size)
584                {
585                        const size_type oldSize = m_size;
586                        if(this != &t)  // s += t
587                        {
588                                Grow(m_size+t.m_size);
589                                memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
590                        }
591                        else            // t += t
592                        {
593                                Grow(m_size*2);
594                                memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), m_ptr, oldSize*sizeof(T));
595                        }
596                }
597                return *this;
598        }
599
600        //! \brief Construct a SecBlock from this and another SecBlock
601        //! \param t the other SecBlock
602        //! \returns a newly constructed SecBlock that is a conacentation of this and t
603        //! \details Internally, a new SecBlock is created from this and a concatenation of t.
604        SecBlock<T, A> operator+(const SecBlock<T, A> &t)
605        {
606                CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size));
607                CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size));
608                if(!t.m_size) return SecBlock(*this);
609
610                SecBlock<T, A> result(m_size+t.m_size);
611                if(m_size) {memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));}
612                memcpy_s(result.m_ptr+m_size, (result.m_size-m_size)*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
613                return result;
614        }
615
616        //! \brief Bitwise compare two SecBlocks
617        //! \param t the other SecBlock
618        //! \returns true if the size and bits are equal, false otherwise
619        //! \details Uses a constant time compare if the arrays are equal size. The constant time
620        //!    compare is VerifyBufsEqual() found in misc.h.
621        //! \sa operator!=()
622        bool operator==(const SecBlock<T, A> &t) const
623        {
624                return m_size == t.m_size &&
625                        VerifyBufsEqual(reinterpret_cast<const byte*>(m_ptr), reinterpret_cast<const byte*>(t.m_ptr), m_size*sizeof(T));
626        }
627
628        //! \brief Bitwise compare two SecBlocks
629        //! \param t the other SecBlock
630        //! \returns true if the size and bits are equal, false otherwise
631        //! \details Uses a constant time compare if the arrays are equal size. The constant time
632        //!    compare is VerifyBufsEqual() found in misc.h.
633        //! \details Internally, operator!=() returns the inverse of operator==().
634        //! \sa operator==()
635        bool operator!=(const SecBlock<T, A> &t) const
636        {
637                return !operator==(t);
638        }
639
640        //! \brief Change size without preserving contents
641        //! \param newSize the new size of the memory block
642        //! \details Old content is \a not preserved. If the memory block is reduced in size,
643        //!    then the reclaimed memory is set to 0. If the memory block grows in size, then
644        //!    the new memory is \a not initialized.
645        //! \details Internally, this SecBlock calls reallocate().
646        //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
647        void New(size_type newSize)
648        {
649                m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
650                m_size = newSize;
651        }
652
653        //! \brief Change size without preserving contents
654        //! \param newSize the new size of the memory block
655        //! \details Old content is \a not preserved. If the memory block is reduced in size,
656        //!    then the reclaimed content is set to 0. If the memory block grows in size, then
657        //!    the new memory is initialized to 0.
658        //! \details Internally, this SecBlock calls New().
659        //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
660        void CleanNew(size_type newSize)
661        {
662                New(newSize);
663                if (m_ptr) {memset_z(m_ptr, 0, m_size*sizeof(T));}
664        }
665
666        //! \brief Change size and preserve contents
667        //! \param newSize the new size of the memory block
668        //! \details Old content is preserved. New content is not initialized.
669        //! \details Internally, this SecBlock calls reallocate() when size must increase. If the
670        //!    size does not increase, then Grow() does not take action. If the size must
671        //!    change, then use resize().
672        //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
673        void Grow(size_type newSize)
674        {
675                if (newSize > m_size)
676                {
677                        m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
678                        m_size = newSize;
679                }
680        }
681
682        //! \brief Change size and preserve contents
683        //! \param newSize the new size of the memory block
684        //! \details Old content is preserved. New content is initialized to 0.
685        //! \details Internally, this SecBlock calls reallocate() when size must increase. If the
686        //!    size does not increase, then CleanGrow() does not take action. If the size must
687        //!    change, then use resize().
688        //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
689        void CleanGrow(size_type newSize)
690        {
691                if (newSize > m_size)
692                {
693                        m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
694                        memset_z(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
695                        m_size = newSize;
696                }
697        }
698
699        //! \brief Change size and preserve contents
700        //! \param newSize the new size of the memory block
701        //! \details Old content is preserved. If the memory block grows in size, then
702        //!    new memory is \a not initialized.
703        //! \details Internally, this SecBlock calls reallocate().
704        //! \sa New(), CleanNew(), Grow(), CleanGrow(), resize()
705        void resize(size_type newSize)
706        {
707                m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
708                m_size = newSize;
709        }
710
711        //! \brief Swap contents with another SecBlock
712        //! \param b the other SecBlock
713        //! \details Internally, std::swap() is called on m_alloc, m_size and m_ptr.
714        void swap(SecBlock<T, A> &b)
715        {
716                // Swap must occur on the allocator in case its FixedSize that spilled into the heap.
717                std::swap(m_alloc, b.m_alloc);
718                std::swap(m_size, b.m_size);
719                std::swap(m_ptr, b.m_ptr);
720        }
721
722// protected:
723        A m_alloc;
724        size_type m_size;
725        T *m_ptr;
726};
727
728#ifdef CRYPTOPP_DOXYGEN_PROCESSING
729//! \class SecByteBlock
730//! \brief \ref SecBlock "SecBlock<byte>" typedef.
731class SecByteBlock : public SecBlock<byte> {};
732//! \class SecWordBlock
733//! \brief \ref SecBlock "SecBlock<word>" typedef.
734class SecWordBlock : public SecBlock<word> {};
735//! \class AlignedSecByteBlock
736//! \brief SecBlock using \ref AllocatorWithCleanup "AllocatorWithCleanup<byte, true>" typedef
737class AlignedSecByteBlock : public SecBlock<byte, AllocatorWithCleanup<byte, true> > {};
738#else
739typedef SecBlock<byte> SecByteBlock;
740typedef SecBlock<word> SecWordBlock;
741typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
742#endif
743
744// No need for move semantics on derived class *if* the class does not add any
745//   data members; see http://stackoverflow.com/q/31755703, and Rule of {0|3|5}.
746
747//! \class FixedSizeSecBlock
748//! \brief Fixed size stack-based SecBlock
749//! \tparam T class or type
750//! \tparam S fixed-size of the stack-based memory block, in elements
751//! \tparam A AllocatorBase derived class for allocation and cleanup
752template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
753class FixedSizeSecBlock : public SecBlock<T, A>
754{
755public:
756        //! \brief Construct a FixedSizeSecBlock
757        explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
758};
759
760//! \class FixedSizeAlignedSecBlock
761//! \brief Fixed size stack-based SecBlock with 16-byte alignment
762//! \tparam T class or type
763//! \tparam S fixed-size of the stack-based memory block, in elements
764//! \tparam A AllocatorBase derived class for allocation and cleanup
765template <class T, unsigned int S, bool T_Align16 = true>
766class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
767{
768};
769
770//! \class SecBlockWithHint
771//! \brief Stack-based SecBlock that grows into the heap
772//! \tparam T class or type
773//! \tparam S fixed-size of the stack-based memory block, in elements
774//! \tparam A AllocatorBase derived class for allocation and cleanup
775template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
776class SecBlockWithHint : public SecBlock<T, A>
777{
778public:
779        //! construct a SecBlockWithHint with a count of elements
780        explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
781};
782
783template<class T, bool A, class U, bool B>
784inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);}
785template<class T, bool A, class U, bool B>
786inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);}
787
788NAMESPACE_END
789
790NAMESPACE_BEGIN(std)
791template <class T, class A>
792inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
793{
794        a.swap(b);
795}
796
797#if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
798// working for STLport 5.1.3 and MSVC 6 SP5
799template <class _Tp1, class _Tp2>
800inline CryptoPP::AllocatorWithCleanup<_Tp2>&
801__stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
802{
803        return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);
804}
805#endif
806
807NAMESPACE_END
808
809#if CRYPTOPP_MSC_VERSION
810# pragma warning(pop)
811#endif
812
813#endif
Note: See TracBrowser for help on using the repository browser.