I'm a developer who's working on a networking protocol that includes encryption. It doesn't really matter, but just for the sake of context I'll mention that I'm using libsodium crypto library. Now there's a lot of asynchronous code in my implementation and I tend to simply copy the private key that is used to encrypt the packets. The private key is a 32 byte array so the copying is supposed to be cheap CPU wise.

Some people say I should hold as few copies in memory as possible, maybe even just one and use a shared pointer throughout my application. On the other hand, if the hacker detects this specific memory location, he could replace the private key with something else. So having multiple copies scattered around in memory should make it more complex to do so, but it also opens more holes to look for the private key.

What are the good practices to manage the private/secret keys in memory?

  • 4
    Does each copy get erased properly from memory after it has served its purpoose?
    – SEJPM
    Nov 20 '18 at 9:17
  • It will be, I'm planning on using crates.io/crates/clear_on_drop library which should cover that.
    – PovilasB
    Nov 20 '18 at 9:58

The best practice to manage the private / secret keys in memory is to use a memory physically out of reach of attackers, such as a HSM, Smart Card, Trusted Platform Module, or Secure Element.

Problem is, that's hardware, and on modern machines (servers, cloud, PCs, mobile), trusted hardware is not easily usable (though often present; in particular I see some renewed interest for TPM 2.0 in server/cloud).

Software-only options are a compromise. A reasonable one it to

  • Trust the hardware + OS to keep at least memory content of a process private, and keep private / secret keys is a separate process doing the crypto, exchanging messages with the process using the crypto.
  • AND stick to algorithms that have inherent protection against side-channel / cross-process leaks, because attacks on this front are aplenty. Libsodium is a good choice from this standpoint.

The combination at least makes a leak of a private / secret key unlikely to result from vulnerabilities in the process using the crypto (due to practically inevitable bugs in the unmanageably complex software stack involved in a typical application). A drawback is that access to the process doing the crypto must be managed securely (e.g. thru access rights enforced by the OS), which adds complexity.

One way to see so-called "enclaves" is as a standardized implementation of that design principle.

My opinion on the subject of multiplying the secret versus using pointers to a centralized area is that it is secondary from a security standpoint, compared to process isolation. I tend to prefer pointers, not so much because it is slightly more efficient, but because it saves from the hassle of having to zero copies no longer in use in order to follow guidelines requiring that. I regard such zeroing as technically non-essential (again, compared to process isolation); but like using e > 216 in RSA, it's something to bow at.

  • If a language supports RAII you don't really have the hassle of zeroing out - that's done by destructors inconspicuously. There's also some literature to avoid swapping out the values to swap space and preventing keys from ever getting written to the disk (unless needed by the application of-course). Would you still have a preference if the zeroing out was taken out of the programmers responsibility and done automatically by the runtime (e.g. destructors) ? Are copies of secret keys still an inferior option (due to some other reason apart from the zeroing out part) ?
    – ustulation
    Nov 20 '18 at 13:39
  • I know languages with RAII but I do not know one that, as a language feature (mandatory or optional) performs zeroing on destruction (but I want to learn!). With C++, it historically has been a mess even to ensure that explicit zeroing of objects about to be freed (which is easily done) does not get optimized out. If there's a language-level semantic for that in a recent edition of the standard, I missed that improvement. Performance-wise, there probably remains a tiny edge for pointers (cost of copy, cache misses..) but that's not decisive.
    – fgrieu
    Nov 20 '18 at 14:24
  • Ah should have been more explicit. What i meant was you could write the zeroing out in the dtor - so you don't have to (remember to) manually do it everytime; but i think i get an overall idea of where you are going. So from the security p.o.v alone, you wouldn't really mind if i held clones of SecretKey (a type with a dtor to zero things out) in many places OR if i held pointers to the same SecretKey in many places.
    – ustulation
    Nov 21 '18 at 14:01

You can encrypt your private key with a TPM newly created Key, your TPM module is able to create a wrapper key, then you can store that key on disc or memory.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.