patterncppMinor
Hacking a SecureString based on std::basic_string for C++
Viewed 0 times
stdsecurestringbasic_stringforbasedhacking
Problem
Inspired by reading "How-to write a password-safe class?", I tried some clever (or dumb-fool) hack to create a widely-useable secure string using the
At least gcc and clang seem not to choke on it (coliru):
And a short program using it to do nothing much:
Some specific concerns:
-
How badly did I break the standard?
-
Is there any actual implementation where the liberties I took with the standard will come back to
std::basic_string-template, which does not need to be explicitly securely erased itself.At least gcc and clang seem not to choke on it (coliru):
#include
namespace my_secure {
void SecureZeroMemory(void* p, std::size_t n) {
for(volatile char* x = static_cast(p); n; --n)
*x++ = 0;
}
// Minimal allocator zeroing on deallocation
template struct secure_allocator {
using value_type = T;
secure_allocator() = default;
template secure_allocator(const secure_allocator&) {}
T* allocate(std::size_t n) { return new T[n]; }
void deallocate(T* p, std::size_t n) {
SecureZeroMemory(p, n * sizeof *p);
delete [] p;
}
};
template
inline bool operator== (const secure_allocator&, const secure_allocator&) {
return true;
}
template
inline bool operator!= (const secure_allocator&, const secure_allocator&) {
return false;
}
using secure_string = std::basic_string,
secure_allocator>;
}
namespace std {
// Zero the strings own memory on destruction
template<> my_secure::secure_string::~basic_string() {
using X =std::basic_string,
my_secure::secure_allocator>;
((X*)this)->~X();
my_secure::SecureZeroMemory(this, sizeof *this);
}
}And a short program using it to do nothing much:
//#include "my_secure.h"
using my_secure::secure_string;
#include
int main() {
secure_string s = "Hello World!";
std::cout << s << '\n';
}Some specific concerns:
-
How badly did I break the standard?
- Does the fact that one of the template-arguments is my own type heal the fact that I added my own explicit specialization to
::std?
- Are the two types actually guaranteed to be similar enough that my bait-and-switch in the destructor is ok?
-
Is there any actual implementation where the liberties I took with the standard will come back to
Solution
The only thing special about
You will probably want to call the global
Add
SecureZeroMemory (the Windows version) is that it uses volatile to prevent optimization. Therefore there's no reason to write your own. Just defer to standard algorithms:std::fill_n((volatile char*)p, n*sizeof(T), 0);You will probably want to call the global
delete:::operator delete [] p;Add
noexcept:template secure_allocator(const secure_allocator&) noexcept {}Code Snippets
std::fill_n((volatile char*)p, n*sizeof(T), 0);::operator delete [] p;template <class U> secure_allocator(const secure_allocator<U>&) noexcept {}Context
StackExchange Code Review Q#107991, answer score: 4
Revisions (0)
No revisions yet.