SecBlock

From Crypto++ Wiki
Jump to navigation Jump to search
SecBlock
Documentation
#include <cryptopp/secblock.h>

The Crypto++ library uses SecBlock class to provide secure storage that is zeroized or wiped when the block is destroyed. The class should be used to hold keys, initialization vectors, and other security parameters. The SecBlock class is fully featured and allows you to create, copy, assign and append data to a block.

SecBlock is a template class, and you can have a block of any type using SecBlock<T>. The type of T includes byte, word32 and word64. When T = byte then there is a SecByteBlock typedef. The library makes frequent use of SecByteBlock.

A SecBlock can be aligned or unaligned. Alignment is indirectly specified through a template parameter for the allocator, called AllocatorWithCleanup. When the SecBlock is aligned the alignment is 16-bytes and used with SSE and POWER8 extensions. When unaligned the SecBlock will use the natural alignment of the underlying type T.

The SecBlock class also allows you to easily acquire a block of uninitialized memory. STL container classes, like std::string and std::vector, always initialize their elements to a default value, even if the default value is unneeded.

Related topics are ByteQueue and SecByteBlockSink if you want to use a SecBlock in a pipeline.

Constructors

template <class T, class A>
    SecBlock (size_type size=0)

T the underlying type, like byte, word32 or double.

A the allocator, like AllocatorWithCleanup.

size the size of the SecBlock, in elements.

The constructor shown above provides you with a secure block of memory that will be zeroized upon destruction. The elements are not initialized.

template <class T, class A>
    SecBlock (const T *ptr, size_type len)

T the underlying type, like byte, word32 or double.

A the allocator, like AllocatorWithCleanup.

ptr a pointer to an array of T.

len the number of elements in the memory block.

This constructor shown above provides you with two choices, though it is not readily apparent. First, you can copy an existing block of memory into the SecBlock. This is the typical use case, and it occurs when ptr is not NULL.

The second choice is an initialized array. When ptr is NULL and len is valid, then a new block is allocated and the elements are initialized to the default value for the type.

Class Methods

The SecBlock class has a lot of class methods. The list below is some of the more frequent ones. If you need a member function not listed then visit SecBlock in the online manual or browse the secblock.h source file.

data() returns a pointer to the first element in the SecBlock.

size() returns the number of elements in the SecBlock.

BytePtr() returns a pointer to the first element in the SecBlock cast to a byte*.

SizeInBytes() returns the number of bytes in the SecBlock.

begin() returns an iterator to the first element in the SecBlock.

end() returns an iterator to beyond the last element in the SecBlock.

empty() returns true if the SecBlock is empty.

swap() exchanges two SecBlocks.

operator=() assigns to a SecBlock.

operator+=() appends to a SecBlock.

operator==() compares two SecBlock in near-constant time using VerifyBufsEqual.

operator!=() compares two SecBlock in near-constant time using VerifyBufsEqual.

New() change size without preserving contents.

Grow() increase size and preserve contents. The new space is uninitialized. Grow does not shrink an object; use resize() instead.

CleanNew() change size without preserving contents. The new space is initialized to 0.

CleanGrow() increase size and preserve contents. The new space is initialized to 0. Grow does not shrink an object; use resize() instead.

Assign() makes a SecBlock from another SecBlock or an array. The array must be distinct from the SecBlock.

Append() adds a SecBlock from another SecBlock or an array. The array must be distinct from the SecBlock.

SetMark() set the number of elements to zeroize. The number to zeroize may be fewer than are allocated or 0.

Alignment

The default allocator used for a SecBlock is unaligned. You can switch to an aligned allocator that provides 16-byte alignment as shown below. The library uses an aligned allocator internally for buffers when working with SSE and POWER8 SIMD units. The syntax is a little ugly, and it is one of the reasons why there is a typedef for SecByteBlock.

// An aligned SecByteBlock
typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;

// An aligned block of word32
SecBlock<word32, AllocatorWithCleanup<word32, true> > block1;

// An aligned block of double
SecBlock<double, AllocatorWithCleanup<double, true> > block2;

You usually don't need to use an aligned allocator. You usually know when you need an aligned SecBlock because you will experience a SIGBUS on Linux. SIGBUS is almost always indicative of a misaligned load or store and a SIMD unit.

Sometimes the library experiences a SIGBUS that is not related to the SIMD unit. Most recently was on Sparc64 due to a bad cast. Also see Issue 597.

There are other type of allocators available for use with SecBlock. If you think you need one of them browse the source file secblock.h.

std::string

Sometimes you have data in a std::string or std::vector and you want to move it to a SecByteBlock for ease of use with the library. And sometimes you have to move data from a SecByteBlock to another container. A number of questions exist on Stack Overflow so it appears to be a frequent task.

If you have a std::string or std::vector then you can create a SecByteBlock as shown below.

std::string str =
    "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtS"
    "YxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcD"
    "dPj3T2bJRHRVhE8Bc2AjkT7n";

SecByteBlock key(reinterpret_cast<const byte*>(&str[0]), str.size());

Taking the address of the first element of the std::string yields a const char*. The cast converts it to a const byte*.

Moving from SecByteBlock to a std::string is similar to the other operation.

SecByteBlock key;  // Assume key is populated

std::string str(reinterpret_cast<const char*>(&key[0]), key.size());
std::vector vec(reinterpret_cast<const char*>(&key[0]), key.size());

A more interesting case is getting a non-const pointer. Below is the way to get a non-const pointer and avoid undefined behavior. You must take the address of element 0. You should not use str.data() or cast it to a non-const pointer.

SecByteBlock key(...);  // Assume key is populated
std::string str;

str.resize(key.size());  // Make room for elements
std::memcpy(&str[0], &key[0], str.size());

AllocatorWithCleanup

The AllocatorWithCleanup class is a C++ allocator. It is used by SecBlock and typedefs like SecByteBlock, and it can be used in C++ container classes.

AllocatorWithCleanup is like a standard C++ allocator. There are no constructors of interest. The class provides three useful member functions for managing memroy.

  • allocate() acquires a memory block
  • deallocate() releases a memory block
  • reallocate() resizes a memory block
  • rebind() switches to a different object type

Below are examples of using the allocator with std::string and std::vector.

typedef std::basic_string<char, std::char_traits<char>, AllocatorWithCleanup<char> > secure_string;

typedef std::vector<int, AllocatorWithCleanup<int> > secure_vector;