How Does One Securely Clear Std::String

how does one securely clear std::string?

Based on the answer given here, I wrote an allocator to securely zero memory.

#include <string>
#include <windows.h>

namespace secure
{
template <class T> class allocator : public std::allocator<T>
{
public:

template<class U> struct rebind { typedef allocator<U> other; };
allocator() throw() {}
allocator(const allocator &) throw() {}
template <class U> allocator(const allocator<U>&) throw() {}

void deallocate(pointer p, size_type num)
{
SecureZeroMemory((void *)p, num);
std::allocator<T>::deallocate(p, num);
}
};

typedef std::basic_string<char, std::char_traits<char>, allocator<char> > string;
}

int main()
{
{
secure::string bar("bar");
secure::string longbar("bHow Does One Securely Clear Std::StringHow Does One Securely Clear Std::StringHow Does One Securely Clear Std::StringHow Does One Securely Clear Std::Stringaaaaar");
}
}

However, it turns out, depending on how std::string is implemented, it is possible that the allocator isn't even invoked for small values. In my code, for example, the deallocate doesn't even get called for the string bar (on Visual Studio).

The answer, then, is that we cannot use std::string to store sensitive data. Of course, we have the option to write a new class that handles the use case, but I was specifically interested in using std::string as defined.

Thanks everyone for your help!

how does one securely clear std::string?

Based on the answer given here, I wrote an allocator to securely zero memory.

#include <string>
#include <windows.h>

namespace secure
{
template <class T> class allocator : public std::allocator<T>
{
public:

template<class U> struct rebind { typedef allocator<U> other; };
allocator() throw() {}
allocator(const allocator &) throw() {}
template <class U> allocator(const allocator<U>&) throw() {}

void deallocate(pointer p, size_type num)
{
SecureZeroMemory((void *)p, num);
std::allocator<T>::deallocate(p, num);
}
};

typedef std::basic_string<char, std::char_traits<char>, allocator<char> > string;
}

int main()
{
{
secure::string bar("bar");
secure::string longbar("bHow Does One Securely Clear Std::StringHow Does One Securely Clear Std::StringHow Does One Securely Clear Std::StringHow Does One Securely Clear Std::Stringaaaaar");
}
}

However, it turns out, depending on how std::string is implemented, it is possible that the allocator isn't even invoked for small values. In my code, for example, the deallocate doesn't even get called for the string bar (on Visual Studio).

The answer, then, is that we cannot use std::string to store sensitive data. Of course, we have the option to write a new class that handles the use case, but I was specifically interested in using std::string as defined.

Thanks everyone for your help!

how does one securely clear std::string?

Based on the answer given here, I wrote an allocator to securely zero memory.

#include <string>
#include <windows.h>

namespace secure
{
template <class T> class allocator : public std::allocator<T>
{
public:

template<class U> struct rebind { typedef allocator<U> other; };
allocator() throw() {}
allocator(const allocator &) throw() {}
template <class U> allocator(const allocator<U>&) throw() {}

void deallocate(pointer p, size_type num)
{
SecureZeroMemory((void *)p, num);
std::allocator<T>::deallocate(p, num);
}
};

typedef std::basic_string<char, std::char_traits<char>, allocator<char> > string;
}

int main()
{
{
secure::string bar("bar");
secure::string longbar("bHow Does One Securely Clear Std::StringHow Does One Securely Clear Std::StringHow Does One Securely Clear Std::StringHow Does One Securely Clear Std::Stringaaaaar");
}
}

However, it turns out, depending on how std::string is implemented, it is possible that the allocator isn't even invoked for small values. In my code, for example, the deallocate doesn't even get called for the string bar (on Visual Studio).

The answer, then, is that we cannot use std::string to store sensitive data. Of course, we have the option to write a new class that handles the use case, but I was specifically interested in using std::string as defined.

Thanks everyone for your help!

Securely resizing and deletion of std::string

It's not guaranteed that c_str() will point to the original buffer and not make a copy. That's probably the way it works, but there's no way to be sure without looking at your specific implementation of basic_string.

There are enough potential problems with making std::wstring secure that I'd avoid it entirely and find a secure string class or write my own.

How secure are string values?

Yes, 1874 would be stored in memory and in the executable.

You could use a cryptography library to salt and hash the correct pin and store the salt and hashed value. In the past I have used crypto++. This would be almost impossible to try and figure out the original value by working with the hashed value, they would have to brute force it. Although the rest of your executable is not secure so they could just hack out the comparison of the response and the correct pin.

How do you clear a stringstream variable?

For all the standard library types the member function empty() is a query, not a command, i.e. it means "are you empty?" not "please throw away your contents".

The clear() member function is inherited from ios and is used to clear the error state of the stream, e.g. if a file stream has the error state set to eofbit (end-of-file), then calling clear() will set the error state back to goodbit (no error).

For clearing the contents of a stringstream, using:

m.str("");

is correct, although using:

m.str(std::string());

is technically more efficient, because you avoid invoking the std::string constructor that takes const char*. But any compiler these days should be able to generate the same code in both cases - so I would just go with whatever is more readable.

How to cleanse (overwrite with random bytes) std::string internal buffer?

It is probably safe. But not guaranteed.

However, since C++11, a std::string must be implemented as contiguous data so you can safely access its internal array using the address of its first element &secretString[0].

if(!secretString.empty()) // avoid UB
{
char* modifiable = &secretString[0];
OpenSSL_cleanse(modifiable, secretString.size());
}

How do you safely clear an object from memory (with attributes) which was created using the new keyword?

Yes. When you delete b it deletes also letters_in_box array.

But, for your b->letters_in_box = "Hello world"; you will get a compile error: "error C3863: array type 'char [80]' is not assignable"

#include <memory> // For 'memcpy_s' (since C11)

class Box
{
public:
double length;
char letters_in_box[80];
};

int main()
{
Box* b = new Box;

b->length = 2.0;
// b->letters_in_box = "Hello world"; ** Compile Error C3863: array type 'char [80]' is not assignable **
memcpy_s(b->letters_in_box, sizeof(b->letters_in_box), "Hello world", sizeof("Hello world"));

// Some code with b

delete b;
}

MODERN C++

A better practice than new is smart pointers, than for example you don't have to bother with delete in case of exception and at all:

#include <memory> // For 'std::unique_ptr' and for 'memcpy_s'

class Box
{
public:
double length;
char letters_in_box[80];
};

constexpr char my_text[] = "Hello world";

int main()
{
auto b = std::make_unique<Box>(); // No need to delete

b->length = 2.0;
memcpy_s(b->letters_in_box, sizeof(b->letters_in_box), my_text, sizeof(my_text));

// Some code with b
}

Also, (instead of C array) I prefer to use C++ array:

#include <array>  // For 'std::array'
#include <memory> // For 'std::unique_ptr' and for 'memcpy_s'

class Box
{
public:
double length;
std::array<char, 80> letters_in_box;
};

constexpr char my_text[] = "Hello world";

int main()
{
auto b = std::make_unique<Box>(); // No need to delete

b->length = 2.0;
memcpy_s(&b->letters_in_box, b->letters_in_box.size(), my_text, sizeof(my_text));

//Some code with b
}

--

One last comment: Without a constraint to use char[], I would use std::string instead:

#include <string> // For 'std::string'
#include <memory> // For 'std::unique_ptr'

class Box
{
public:
double length;
std::string letters_in_box;
};

int main()
{
auto b = std::make_unique<Box>(); // No need to delete

b->length = 2.0;
b->letters_in_box = "Hello world";

//Some code with b
}


Related Topics



Leave a reply



Submit