/* * Secure Memory Buffers * (C) 1999-2007,2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #ifndef BOTAN_SECURE_MEMORY_BUFFERS_H_ #define BOTAN_SECURE_MEMORY_BUFFERS_H_ #include // IWYU pragma: export #include // IWYU pragma: export #include #include #include #include #if defined(BOTAN_HAS_LOCKING_ALLOCATOR) #include #endif namespace Botan { template class secure_allocator { public: /* * Assert exists to prevent someone from doing something that will * probably crash anyway (like secure_vector where ~non_POD_t * deletes a member pointer which was zeroed before it ran). * MSVC in debug mode uses non-integral proxy types in container types * like std::vector, thus we disable the check there. */ #if !defined(_ITERATOR_DEBUG_LEVEL) || _ITERATOR_DEBUG_LEVEL == 0 static_assert(std::is_integral::value, "secure_allocator supports only integer types"); #endif typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; #ifdef BOTAN_BUILD_COMPILER_IS_MSVC_2013 secure_allocator() = default; secure_allocator(const secure_allocator&) = default; secure_allocator& operator=(const secure_allocator&) = default; ~secure_allocator() = default; #else secure_allocator() BOTAN_NOEXCEPT = default; secure_allocator(const secure_allocator&) BOTAN_NOEXCEPT = default; secure_allocator& operator=(const secure_allocator&) BOTAN_NOEXCEPT = default; ~secure_allocator() BOTAN_NOEXCEPT = default; #endif template secure_allocator(const secure_allocator&) BOTAN_NOEXCEPT {} pointer address(reference x) const BOTAN_NOEXCEPT { return std::addressof(x); } const_pointer address(const_reference x) const BOTAN_NOEXCEPT { return std::addressof(x); } pointer allocate(size_type n, const void* = 0) { #if defined(BOTAN_HAS_LOCKING_ALLOCATOR) if(pointer p = static_cast(mlock_allocator::instance().allocate(n, sizeof(T)))) return p; #endif pointer p = new T[n]; clear_mem(p, n); return p; } void deallocate(pointer p, size_type n) { secure_scrub_memory(p, sizeof(T)*n); #if defined(BOTAN_HAS_LOCKING_ALLOCATOR) if(mlock_allocator::instance().deallocate(p, n, sizeof(T))) return; #endif delete [] p; } size_type max_size() const BOTAN_NOEXCEPT { return static_cast(-1) / sizeof(T); } template void construct(U* p, Args&&... args) { ::new(static_cast(p)) U(std::forward(args)...); } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4100) template void destroy(U* p) { p->~U(); } #pragma warning(pop) #endif }; template inline bool operator==(const secure_allocator&, const secure_allocator&) { return true; } template inline bool operator!=(const secure_allocator&, const secure_allocator&) { return false; } template using secure_vector = std::vector>; template using secure_deque = std::deque>; // For better compatability with 1.10 API template using SecureVector = secure_vector; template std::vector unlock(const secure_vector& in) { std::vector out(in.size()); copy_mem(out.data(), in.data(), in.size()); return out; } template size_t buffer_insert(std::vector& buf, size_t buf_offset, const T input[], size_t input_length) { const size_t to_copy = std::min(input_length, buf.size() - buf_offset); if (to_copy > 0) { copy_mem(&buf[buf_offset], input, to_copy); } return to_copy; } template size_t buffer_insert(std::vector& buf, size_t buf_offset, const std::vector& input) { const size_t to_copy = std::min(input.size(), buf.size() - buf_offset); if (to_copy > 0) { copy_mem(&buf[buf_offset], input.data(), to_copy); } return to_copy; } template std::vector& operator+=(std::vector& out, const std::vector& in) { const size_t copy_offset = out.size(); out.resize(out.size() + in.size()); if (in.size() > 0) { copy_mem(&out[copy_offset], in.data(), in.size()); } return out; } template std::vector& operator+=(std::vector& out, T in) { out.push_back(in); return out; } template std::vector& operator+=(std::vector& out, const std::pair& in) { const size_t copy_offset = out.size(); out.resize(out.size() + in.second); if (in.second > 0) { copy_mem(&out[copy_offset], in.first, in.second); } return out; } template std::vector& operator+=(std::vector& out, const std::pair& in) { const size_t copy_offset = out.size(); out.resize(out.size() + in.second); if (in.second > 0) { copy_mem(&out[copy_offset], in.first, in.second); } return out; } /** * Zeroise the values; length remains unchanged * @param vec the vector to zeroise */ template void zeroise(std::vector& vec) { clear_mem(vec.data(), vec.size()); } /** * Zeroise the values then free the memory * @param vec the vector to zeroise and free */ template void zap(std::vector& vec) { zeroise(vec); vec.clear(); vec.shrink_to_fit(); } } #endif