Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Advantages of SecByteBlock class from Crypto++

I am using Crypto++ library to decrypt files with AES algorithm in CBC mode. I came across SecByteBlock class in sample code of AES which says

The key is declared on the stack using a SecByteBlock to ensure the sensitive material is zeroized.

Can someone please explain me when the contents of SecByteBlock will get cleared and what advantages this class offer over char*.

Thanks In Advance

like image 678
user3494614 Avatar asked Sep 28 '16 15:09

user3494614


1 Answers

[title] Advantages of SecByteBlock class from Crypto++

The advantage of using SecByteBlock is you get the managed buffer with zeroization. Zeroization is often a compliance item. For example, FIPS 140-2 requires it, even at Level 1 validations.

A second, non obvious benefit is the allocator does not initialize POD memory - it returns a raw block. That makes a lot of sense since you often take a 0-value initialized and then overwrite the contents with data. There's no sense in intializing it, and it saves a lot of time.

You can get SecBlock to provide a 0-value initialized block. Here's how to do both:

SecByteBlock block1(32);
SecByteBlock block2(NULL, 32);

block1 is 32-bytes in size, uninitialized and its contents will be garbage.

block2 is also 32-bytes in size, but it uses the (ptr, size) overload. The overload will either copy-in the block pointed to by ptr, or it will write 0's if its NULL.


For completeness and reference, a SecByteBlock is just a typedef for SecBlock<byte>. SecBlock<T> is the class of interest, and the library frequently uses SecBlock<byte>, SecBlock<word32>, SecBlock<word64>, etc.

Here's the Doxygen generated manual page for SecBlock: SecBlock< T, A > Class Template Reference. And here's the header file for secblock.h (its a header only implementation).


Can someone please explain me when the contents of SecByteBlock will get cleared ...

The contents of SecByteBlock are cleared under the obvious case of object destruction. That is, the memory allocated to the SecBlock are cleared with a pattern of 0's when the destructor runs.

There's a non obvious case, and that's when resize is called to shrink one. In this case, the extra space being returned to the OS is wiped, too.

You can see the wiping in the source code. For example, from Crypto++ 5.6.4 secblock.h:

  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     }

what advantages this class offer over char*.

Well, the SecBlock<byte> is a class that manages a buffer. char* is just a type and there's not much to it. You have to managed the buffer that the char* is pointing to.

You can use something like a std::string, but you will not get overflow detection (only std::vector is required to check for it) and you will not get zeroization.

With that said, you can do both of these:

  • typdef SecBlock<char> SecCharBlock
  • typedef std::basic_string<char, std::char_traits<char>, AllocatorWithCleanup<char> > secure_string

The second one is kind of cool. You can do it because secblock.h provides a secure allocator that's compatible with the standard library. SecBlock<T> uses the secure allocator internally, and its called an AllocatiorWithCleanup<T>.

OpenSSL's wiki page on EVP Symmetric Encryption and Decryption | C++ Progams uses a similar allocator to supply a secure_string class in their example. OpenSS:'s zallocator calls OpenSSL_cleanse.

From Crypto++ 5.6.4 secblock.h:

  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.
  150 template <class T, bool T_Align16 = false>
  151 class AllocatorWithCleanup : public AllocatorBase<T>
  152 {
  153 public:
  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
  163     //!   using either 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     ...
  241 };
like image 135
jww Avatar answered Oct 20 '22 08:10

jww