HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Hacking a SecureString based on std::basic_string for C++

Submitted by: @import:stackexchange-codereview··
0
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 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 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.