Erasing Sensitive Data (The GNU C Library)

### 5.11 Erasing Sensitive Data ¶

Sensitive data, such as cryptographic keys, should be erased from memory after use, to reduce the risk that a bug will expose it to the outside world. However, compiler optimizations may determine that an erasure operation is “unnecessary,” and remove it from the generated code, because no correct program could access the variable or heap object containing the sensitive data after it’s deallocated. Since erasure is a precaution against bugs, this optimization is inappropriate.

The functions `explicit_bzero` and `memset_explicit` erase a block of memory, and guarantee that the compiler will not remove the erasure as “unnecessary.”

    #include <string.h>

    extern void encrypt (const char *key, const char *in,
                         char *out, size_t n);
    extern void genkey (const char *phrase, char *key);

    void encrypt_with_phrase (const char *phrase, const char *in,
                              char *out, size_t n)
    {
      char key[16];
      genkey (phrase, key);
      encrypt (key, in, out, n);
      explicit_bzero (key, 16);
    }

In this example, if `memset`, `bzero`, or a hand-written loop had been used, the compiler might remove them as “unnecessary.”

Warning: `explicit_bzero` and `memset_explicit` do not guarantee that sensitive data is completely erased from the computer’s memory. There may be copies in temporary storage areas, such as registers and “scratch” stack space; since these are invisible to the source code, a library function cannot erase them.

Also, `explicit_bzero` and `memset_explicit` only operate on RAM. If a sensitive data object never needs to have its address taken other than to call `explicit_bzero` or `memset_explicit`, it might be stored entirely in CPU registers until the call to `explicit_bzero` or `memset_explicit`. Then it will be copied into RAM, the copy will be erased, and the original will remain intact. Data in RAM is more likely to be exposed by a bug than data in registers, so this creates a brief window where the data is at greater risk of exposure than it would have been if the program didn’t try to erase it at all.

Declaring sensitive variables as `volatile` will make both the above problems worse; a `volatile` variable will be stored in memory for its entire lifetime, and the compiler will make more copies of it than it would otherwise have. Attempting to erase a normal variable “by hand” through a `volatile`-qualified pointer doesn’t work at all—because the variable itself is not `volatile`, some compilers will ignore the qualification on the pointer and remove the erasure anyway.

Having said all that, in most situations, using `explicit_bzero` or `memset_explicit` is better than not using it. At present, the only way to do a more thorough job is to write the entire sensitive operation in assembly language. We anticipate that future compilers will recognize calls to `explicit_bzero` or `memset_explicit` and take appropriate steps to erase all the copies of the affected data, wherever they may be.

Function: `void` explicit_bzero `(void *block, size_t len)` ¶

  Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

  `explicit_bzero` writes zero into len bytes of memory beginning at block, just as `bzero` would. The zeroes are always written, even if the compiler could determine that this is “unnecessary” because no correct program could read them back.

  Note: The only optimization that `explicit_bzero` disables is removal of “unnecessary” writes to memory. The compiler can perform all the other optimizations that it could for a call to `memset`. For instance, it may replace the function call with inline memory writes, and it may assume that block cannot be a null pointer.

  Portability Note: This function first appeared in OpenBSD 5.5 and has not been standardized. Other systems may provide the same functionality under a different name, such as `explicit_memset`, `memset_s`, or `SecureZeroMemory`.

  The GNU C Library declares this function in `string.h`, but on other systems it may be in `strings.h` instead.

Function: `void *` memset_explicit `(void *block, int c, size_t size)` ¶

  Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

  This function copies the value of c (converted to an `unsigned char`) into each of the first size bytes of the object beginning at block, just as `memset` would. It returns the value of block. The bytes are always written, even if the compiler could determine that this is “unnecessary” because no correct program could read them back.

  Note: The only optimization that `memset_explicit` disables is removal of “unnecessary” writes to memory. The compiler can perform all the other optimizations that it could for a call to `memset`. For instance, it may replace the function call with inline memory writes, and it may assume that block cannot be a null pointer.