skeeto / passphrase2pgp

Generate a PGP key from a passphrase
The Unlicense
187 stars 14 forks source link

Protected memory for Passphrase? #4

Closed eduncan911 closed 4 years ago

eduncan911 commented 5 years ago

Would it make sense to protect the memory allocation for passphrase?

I've been following this pure-Golang solution to protecting secure memory in Golang for a while:

https://spacetime.dev/memory-security-go

And an update:

https://spacetime.dev/encrypting-secrets-in-memory

Specifically, their memguard golang package.

https://github.com/awnumar/memguard

I think passphase2pgp might be a good candidate to protect the sensitive input collections.

However, I'm questioning if it is even needed:

  1. The binary is short-lived, so there's no GC intervals to worry about (e.g. leaving it on a stale stack to be scraped).
  2. If an attacker has access to memory, then they most likely have access to keyboard input and can just keylog.

To counter point 1, the binary does stay running for several seconds. So there is a window to scrap memory. E.g. Also, some systems have long memory page reset values which saves time by just marking the stale page ready for new malloc calls.

Also, another counter to 1 is that under a stressed system (low memory), memory could be allocated in the swap - especially on windows (pagefile) which would give the passphrase a very long life.in the swapfile/pagefile. Especially if the system doesn't collect, and the system goes into hibernation for some time - allowing for a swapfile attack on a cold system. (I personally use a LUKS encrypted swap partition to mitigate those attacks, but most people do not go that far)

The final counter point to 1. that I can come up on this all-nighter I just pulled is about CPU side channel cache attacks, especially around the ongoing Intel Meltdown and Spectre attacks (still new CVEs, every other month).

As for countering 2., I can't think of anything that would allow someone to read memory, but not keyboard input. Maybe someone smarter than I can come up with a limited attack that could be mitigated if we were using secure memory to protect against memory attacks but they would not have access to keyboard (USB and PS/2).

skeeto commented 5 years ago

IMHO, memory locking to protect secrets is overkill. In practical security models, anyone who can read raw swap data could already steal your keys through other means (like you mentioned with a keylogger). If that doesn't describe your security model, then you should already be managing this via encrypted swap or no swap (very practical these days). For something as small as a key or passphrase, sensitive data may be spilled all over the place as it's used, and there's little that can be done to stop it. For example, if it's ever memcpy()ed, it's likely going to end up in an x86 SSE register, and from there spilled elsewhere eventually (context switch, etc.).

My usual example of a high profile, high security project that doesn't bother with memory locking is OpenSSH, even within ssh-agent. Run "grep mlock" and you'll find nothing.

(Side note: The only time I've used encrypted swap is via FDE via LUKS, but this means the same key is always used for swap. The contents can be decrypted even after shutdown or swapoff. Ideally the swap key is destroyed at swapoff, effectively destroying all data in swap, shortening the lifetime of swapped-out sensitive data. However, at least on Linux, it seems that this is difficult to configure and nobody actually does this in practice.)

Protection from speculation attacks is more legitimate, though it has nothing to do with locked memory (i.e. mlock(2)). The memguard library mentioned in your link also doesn't provide any meaningful protection against speculation attacks. In theory, though unlikely, JavaScript running in a browser may be able to pull off this kind of attack, so it fits in a practical security model. OpenSSH got a patch to mitigate this:

https://marc.info/?l=openbsd-cvs&m=156109087822676&w=2

But, as you pointed out, passphrase2pgp is a batch program, not a long-lived daemon. There's essentially no time where the passphrase or keys are just sitting idle and unused. Trying to mitigate speculation attacks would only increase the time those secrets reside in memory.

When passphrase2pgp exits, the secrets still reside in physical memory since, typically, operating systems only lazily overwrite pages. This can be mitigated by securely zeroing sensitive buffers before exiting. However, as I understand it, and I could be wrong, unmapped memory is safe from speculation attacks since attacks go through the page table. And, of course, unused memory would never be written to swap. That just leaves cold boot attacks, but virtually anyone who could do a cold boot attack could do an evil maid attack anyway (i.e. worrying about cold boot but not evil maid is a weird security model).

eduncan911 commented 4 years ago

Thanks for the detail reply! Some follow-up statements before I close it out...

then you should already be managing this via encrypted swap or no swap (very practical these days)

While I do LUKS encrypt my swap (needed for hibernation on my Linux machine), Windows machines are such machines that cannot remove swap. Even if setting it to 0, it still creates and uses a small pagefile.

memguard prevents writes to pagefile (windows) and swap (linux). Don't know about BSD-based machines, like macOS though.

For something as small as a key or passphrase, sensitive data may be spilled all over the place as it's used, and there's little that can be done to stop it. For example, if it's ever memcpy()ed, it's likely going to end up in an x86 SSE register, and from there spilled elsewhere eventually (context switch, etc.).

Very true. However, that memguard may prevent that based on its features. Just a guess though as I haven't dug into their code yet.

Protection from speculation attacks is more legitimate, though it has nothing to do with locked memory (i.e. mlock(2)). The memguard library mentioned in your link also doesn't provide any meaningful protection against speculation attacks.

Ah, that's what i thought the mitigation efforts of memguard against side-channel attacks were helping to prevent. I'm no expert in this realm; so, I'll default to your knowledge.

When passphrase2pgp exits, the secrets still reside in physical memory since, typically, operating systems only lazily overwrite pages. This can be mitigated by securely zeroing sensitive buffers before exiting. However, as I understand it, and I could be wrong, unmapped memory is safe from speculation attacks since attacks go through the page table. And, of course, unused memory would never be written to swap.

You may be correct, again no expert here. The memguard package may only be a hope in mitigation, not a guarantee.

That just leaves cold boot attacks, but virtually anyone who could do a cold boot attack could do an evil maid attack anyway (i.e. worrying about cold boot but not evil maid is a weird security model).

memguard helps prevent/mitigate cold-boot attacks as one of its primary features.

I did configure a Qubes machine once to prevent evil-maid attacks. However, it was too much of a PITA because of the chicken-and-egg issue of no HID (USB) to initialize a keyboard to be able to decrypt LUKS. You have to enable HID, and whitelist specific USB IDs - which does work eventually - while denying all others. And, USB-stick booting (a big thing for me back then) was impossible.

Overall, evaluating the threat-model for my use-cases pretty much comes down to:

Which leaves suspend (passphrase, and disk's passphrase both still in ram) and cold boot attacks from a hibernation effort (which frankly state-actors are pretty much the only ones to pull that off).

While I have accepted the risk of the suspend/disk passphrase in memory, it's keeping the PGP key(s) on disk is what I want to prevent with Passphrase2pgp. Which then only leaves in-memory/cold-boot attacks. This is where I believe memguard could help mitigate.

Thanks for the deep dive. If time serves, I may one day fork and attempt an implementation of memguard to see if i can wrap my head around it. Until then, I'll continue to be a passphrase2pgp user! :)

Thanks!