c++securitymemorycryptographypasswords

Clearing memory securely and reallocations


Following the discussion here, if you want to have a secure class for storing sensitive information (e.g passwords) on memory, you have to:

So this sounds good, and I created a test class to see if this works. So I made a simple test case where I keep adding the words "LOL" and "WUT", followed by a number to this secure buffer class around a thousand times, destroying that object, before finally doing something that causes a core dump.

Since the class is supposed to securely clear the memory before the destruction, I'm not supposed to be able to find a "LOLWUT" on the coredump. However, I managed to find them still, and wondered if my implementation is just buggy. However, I tried the same thing using CryptoPP library's SecByteBlock:

#include <cryptopp/osrng.h>
#include <cryptopp/dh.h>
#include <cryptopp/sha.h>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;

int main(){
   {
      CryptoPP::SecByteBlock moo;

      int i;
      for(i = 0; i < 234; i++){
         moo += (CryptoPP::SecByteBlock((byte*)"LOL", 3));
         moo += (CryptoPP::SecByteBlock((byte*)"WUT", 3));

         char buffer[33];
         sprintf(buffer, "%d", i);
         string thenumber (buffer);

         moo += (CryptoPP::SecByteBlock((byte*)thenumber.c_str(), thenumber.size()));
      }

      moo.CleanNew(0);

   }

   sleep(1);

   *((int*)NULL) = 1;

   return 0;
}

And then compile using:

g++ clearer.cpp -lcryptopp -O0

And then enable core dump

ulimit -c 99999999

But then, enabling core dump and running it

./a.out ; grep LOLWUT core ; echo hello

gives the following output

Segmentation fault (core dumped)
Binary file core matches
hello

What is causing this? Did the whole memory region for the application realloc itself, because of the reallocation caused by SecByteBlock's append?

Also, This is SecByteBlock's Documentation

edit: After checking the core dump using vim, I got this: https://i.sstatic.net/3iXb3.jpg

edit2: updated code so it's more readily compilable, and compilation instructions

final edit3: It looks like memcpy is the culprit. See Rasmus' mymemcpy implementation on his answer below.


Solution

  • Here is another program that reproduces the problem more directly:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    inline void SecureWipeBuffer(char* buf, size_t n){
      volatile char* p = buf;
      asm volatile("rep stosb" : "+c"(n), "+D"(p) : "a"(0) : "memory");
    }
    
    void mymemcpy(char* b, const char* a, size_t n){
      char* s1 = b;
      const char* s2= a;
      for(; 0<n; --n) *s1++ = *s2++;
    }
    
    int main(){
      const size_t size1 = 200;
      const size_t size2 = 400;
    
      char* b = new char[size1];
      for(int j=0;j<size1-10;j+=10){
        memcpy(b+j, "LOL", 3);
        memcpy(b+j+3, "WUT", 3);
        sprintf((char*) (b+j+6), "%d", j);
      }
      char* nb = new char[size2];
      memcpy(nb, b, size1);
      //mymemcpy(nb, b, size1);
      SecureWipeBuffer(b,size1);
      SecureWipeBuffer(nb,size2);
    
      *((int*)NULL) = 1;
    
      return 0;    
    }
    

    If you replace memcpy with mymemcpy or use smaller sizes the problem goes away, so my best guess is that the builtin memcpy does something that leaves part of the copied data in memory.

    I guess this just shows that clearing sensitive data from memory is practically impossible unless it is designed into the entire system from scratch.