It's protected by DPAPI [0] which uses the user's password to encrypt the keys. Any other programs running under that user can theoretically access it (just like how any program can access your ~/.ssh/id_rsa) but other users shouldn't be able to access it.
~/.ssh/id_rsa can be protected by a password, you'll want to access the running ssh-agent process memory to get the key in cleartext (unless the person use some security token in which case you can't access the key, just try to login on a remote computer directly while the HSM is available).
But while ssh-agent has the key unlocked on a Linux system, any process running as that user can use the key without knowing the passphrase the ssh-agent. That's the more direct comparison.
No, part of this involved using Windows's Data Protection API to decrypt it.
Other non-administrator users can't read these registry keys, it's encrypted with the login password (as is common with macOS Keychain and GNOME/KDE's credential stores) so even other administrators can't decrypt it.
On Linux, administrators (root) can extract the keys from ssh-agent. This is actually no less secure and usually more secure.
This is a cool demo of how to do it on Windows, and there's a reason the author didn't call it a vulnerability - it's working as designed and this form of attack is outside the intended threat model.
>On Linux, administrators (root) can extract the keys from ssh-agent.
I don't understand how the situation is different. Of course you can extract the keys from a running ssh-agent since the whole point is not having to provide your password every time so they have to have access to the private key one way or an other. How is the situation different on Windows? Surely when the user is logged an administrator with access to the full RAM and storage will be able to piece everything together (like TFA does for instance)?
On the other hand if you really can't trust your admin you have a huge problem anyway, even with a HSM you could be phished very easily.
Actually overall I'd say that this Windows method is slightly less secure because it means that the Windows keychain thingy is a single point of failure, if somebody compromises it they have access to everything including the ssh keys in the registry.
I don't think Windows gives an administrator account unfettered access to the full RAM, no. And without that or the user's login password, all they could get from the registry is the encrypted version, just as on disk. The encryption is separate per-user with that user's password.
Of course there may be ways to get an even more advanced level of access than administrator, such as the system account, but honestly Windows does lock some things down really hard at the kernel level and Data Protection decryption based on in-RAM credentials might be one. I don't know modern Windows internals to that level.
>I don't think Windows gives an administrator account unfettered access to the full RAM, no.
Are you sure? Typically root has access to the full RAM on an unx system. Unless this is linked to a hardware TPM module I'm not sure why and how it would be protected. Maybe I'm wrong to assume that Windows Administrator == unx root?
Anyway, if the OS has a way to hide some of its state from even the admin then surely it could use it to hide the unencrypted SSH key in RAM instead of hiding the key-to-the-registry-key? My main argument is that at some point if the OS doesn't want to prompt the user for a password it must have access to the private key one way or an other, so I'm not convinced that Windows is more (or less) secure than Linux in this situation.
If you're admin, you might have to install a driver to scrape all memory. So... one hoop to jump through :)
Caveat: you're still trapped in your hypervisor partition. Enclaves (e.g. SGX) are also protected from admin/root snooping. IIRC, this is the same as on Linux.
> To do that, we simply start the ssh-agent service (as Administrator) and use ssh-add to store our private key.
Did Microsoft do some major surgery on the ssh-agent program or am I missing something else? If the agent is started as Administrator, why can I connect to it with my user privileges? And if I do, can other users on the same system do so, too, accessing the same set of keys?
Unprivileged processes can communicate with privileged services.
The service itself sometimes controls which user can access which data, but in this case since the encrypted keys are stored in the Current User Registry Hive (NTUSER.DAT) it likely doesn't need to, filesystem permissions handle that.
Plus even if another user gained access to your registry hive, the data is encrypted with your context via the Data Protection APIs.
I'm sure they have a good reason to do it that way but why run a privileged process when per-user processes could do the job just fine? You'd reduce the surface of attack tremendously that way.
If somebody finds a flaw in their admin ssh-agent process they potentially have a way to access other people's key or maybe even escalate their privileges.
Wow thanks for this. I never knew the current user registry hive was stored at NTUSER.dat. I've always figured out the user id and navigated through hkey_users.
You can actually offline mount NTUSER via "Load Hive" in RegEdit. Very useful if you're working with a backup or older system image and need something out of the user's registry (rather than the system registry stored in C:\Windows\System32\config).
> The service itself sometimes controls which user can access which data,
Sure, but ssh-agent does not. That's what I was alluding to with "major surgery".
Also, while the encrypted keys are stored in the file system or registry, the agent process necessarily has them in unencrypted form. That's the reason for loading keys into the agent in the first place.
To have an ssh-agent that can run as a privileged system service with multiple unprivileged clients, you need to extend it to have some notion of client identity and per-user key space. The standard OpenSSH ssh-agent doesn't have that. Users run their own instance each and if you can connect to it, you can use the keys loaded into it. All of them.
The agent code at github.com/PowerShell/openssh-portable doesn't look any different to me, at least from a cursory glance.
Thus, the decision to run it as a system service seems odd to me.
edit: are they hooking into the agent as a PKCS11 provider/"smartcard" and the plaintext keys never even hit the agent's in-memory table, to be queried by all connected clients?
Just a heads-up - the pixelation used to hide the keys in the final screenshot is not safe! There aren't that many possible characters in each of those 10x10px blocks, and ~256 levels of average brightness is enough to distinguish between them. (Here's a simplistic demo: https://dheera.net/projects/blur)
Stick to the block-of-constant-colour method used in the first few screenshots. It's ugly but safer!
I don't understand what it "suffers" from. It's performing as-intended. A user needs to be able to retrieve the plaintext of their SSH private keys.
There's nothing that seems architecturally unsound about how Microsoft implemented this. DPAPI is a reasonable way to protect the keys "at rest" in the registry. The OP was able to extract the keys because he has the credentials for the user from whom he is extracting the keys.
Short of storing the keys in the memory of a dedicated crypto-processor outside the host computer (and performing the cryptographic operations there) the plaintext of the private keys will have to be recoverable to the user.
the entire point of agents is that they DON'T just hand you key plaintext, otherwise what would the point of them be compared to just an un-encrypted file.
ssh-agent signs requests, tokens, etc on your behalf. You never see the private key.
I haven't looked at Cygwin's ssh-agent but I'm sure it's possible to achieve the same thing. The unencrypted private keys have to be stored somewhere (either in memory or protected on disk). Could probably just dump Cygwin's memory and extract from there.
Am I correct in thinking that this is working as intended, and not actually a vulnerability? Many people seem to be sharing this as "look at Microsoft screwing up ssh-agent security", but I can't actually see any evidence of this in the article.
You are correct. There is no "vulnerability" here. The plaintext of the user's private keys must be accessible to the CPU performing the cryptographic operations. DPAPI is a reasonable method to keep the keys encrypted "at rest" while allowing the keys to be decrypted w/o the requiring password entry each time the keys are used.
It is helpful for post-exploitation toolkits to have this functionality.
> The agent will never send a private key over its request channel. Instead, operations that require a private key will be performed by the agent, and the result will be returned to the requester. This way, private keys are not exposed to clients using the agent.
This sounds like a pretty gaping security hole by Microsoft. I would not assume loading private keys to an "ssh-agent" means giving any process (browser, email client etc.) running on the same machine access to the unencrypted values!
The SSH agent isn't divulging the keys. The OP is decrypting the keys from the underlying storage. The API used to protect the keys allows the keys to be decrypted without explicit password entry. The OP has the necessary password to decrypt the keys, so the API allows it. The SSH agent isn't involved.
A program would need the appropriate level of access (which isn't actually that high a bar), but at the end of the day the fact of the matter remains: other processes can potentially access private keys that would otherwise remain password protected.
> I would not assume loading private keys to an "ssh-agent" means giving any process (browser, email client etc.) running on the same machine access to the unencrypted values!
It doesn't.
> AFAIK the whole point of ssh-agent is that the private keys are NOT extractable by other processes.
Any process with sufficient privileges (i.e., root) can extract the private key from ssh-agent on Linux as well.
But the definition of "sufficient privileges" is different here - on most Linux distros (and I'd guess on other OSes?) ssh-agent protects itself from being accessed by the same user account (via the debugging APIs) by being setgid to group ssh. On Windows, the data protection API specifically allows any process running as the same user on the same computer to decrypt protected data.
So it's not a vulnerability in the sense of an unintended exposure, but, it's certainly true that Microsoft's design gives the private key much more exposure than the design used on most Linux distros. (And it's unclear whether MS intended to deviate from this behavior.)
> ssh-agent protects itself from being accessed by the same user account (via the debugging APIs) by being setgid to group ssh
I don't think this is correct. ssh-agent typically will be run under your user/group; it shouldn't have the necessary privileges to setgid to ssh. Further, I have ssh-agent running on a machine, and it is still my gid. Last, that machine doesn't even have an "ssh" group.
Rather, I think ssh-agent likely protects itself from being debugged (ptrace'd) by ptrace'ing itself. My understanding is that a process can only be ptraced by one process at a time, and by ptrace'ing yourself, you deny the ability for anything else to attach to you.
Perhaps this is just my machine however, and if I did have a `ssh` group, and I were a member of it, it would setgid to it. I don't think that's foolproof, however: something running under your uid could kill ssh-agent, and restart it under a debugger, skip or elide the setgid() and ptrace() calls, then continue to allow it to execute normally, and now be attached as a debugger.
I'm also not sure if ptrace()'ing yourself prevents you from reading out the process's memory from /proc.
Edit: so, on Linux, it seems this is what it does[1]:
prctl(PR_SET_DUMPABLE, 0)
That makes the process "undumpable", which means it won't leave behind core files, /proc/pid is root:root, and it can't be ptrace()'d. I still think the caveat about starting it under a debugger applies, but that certainly makes it less trivial.
"most Linux distros" might have been wrong, but on Debian and Ubuntu at least, the executable /usr/bin/ssh-agent has group ssh and has the sgid bit set. So, when you run it, it automatically runs as group ssh via file permissions, denying you the ability to debug it, precisely because you're not a member of group ssh.
"being setgid to group ssh" and "calling the setgid system call to become group ssh" are two pretty different things, and it's unfortunate that UNIX uses the same terminology "setgid" to describe these two. (They don't even have the same end result; the system call changes the real group ID, and the permission bit changes the effective group ID.)
I don't think ptracing yourself is even possible (also how would you restart the process once stopped?):
$ cat src/main.rs
extern crate nix;
use nix::unistd::*;
use nix::sys::ptrace;
fn main() {
ptrace::attach(getpid()).unwrap();
}
$ cargo run
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Sys(EPERM)', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
Starting it under a debugger means that you have to re-load the encrypted file from disk and re-enter the password. The attack we're worried about seems to be that the system is secure when the key is initially loaded, but at some later point some malware tries to steal the key. If you have access to the password, you can just copy the key and decrypt it on some other machine.
I see what you mean about being setgid; I did not think to check for that.
That said, I still don't think the processes group is what stops you from debugging it (it's the undumpable flag). The group check wouldn't matter and would never take effect, since your uid matches that of the process, that would be sufficient to allow you access to the process, would it not?
No - the debugging check pays attention to more than just UID, specifically because the point of being setgid is that a binary can be allowed to access files that the calling user isn't permitted to access. For instance, games are traditionally setgid games to update high scores, which users in general shouldn't be able to do. Being able to attach a debugger to a game would let you update high scores without actually playing the game.
titan:~ geofft$ ls -ld /usr/games/battlestar
-rwxr-sr-x 1 root games 213272 Jul 8 2014 /usr/games/battlestar
titan:~ geofft$ battlestar
[...]
^Z
[1]+ Stopped battlestar
titan:~ geofft$ jobs -p
6343
titan:~ geofft$ strace -p 6343
strace: attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted
titan:~ geofft$ fg
^Cbye.
Your rating was novice.
titan:~ geofft$ ls -l /var/games/bsdgames/battlestar.log
-rw-rw-r-- 1 root games 58 May 23 15:50 /var/games/bsdgames/battlestar.log
titan:~ geofft$ cat /var/games/bsdgames/battlestar.log
Wed May 23 15:50:51 2018 geofft novice
One subtler thing is that, as 'tedunangst points out, ssh-agent changes back to your gid with the setgid syscall. But (at least on Linux, and I think on most UNIXes) that doesn't re-enable debug access, because there might be restricted data still in memory, or mmappings of restricted files, or whatever. You have to do an exec, which dumps the contents of memory, to re-enable debugging.
- allow debugging another thread from the same process (because threads share memory anyway)
- allow if the debugger is privileged to debug anything (CAP_SYS_PTRACE)
- require that real, effective, and saved UIDs and GIDs all match
- require that the dumpable flag isn't set
and, if you go over and read the prctl manpage http://man7.org/linux/man-pages/man2/prctl.2.html , it points out that the dumpable flag is implicitly set to undumpable if the process changes euid/egid or exec a setuid/setgid/fscaps binary, and the execve manpage says it's set back to dumpable if you exec a normal binary.
Yep, you're correct. Not a vulnerability or an exploit. It's always going to be possible with the right privileges, I was just wanted to see and show the "how"
The author of this blog must have uploaded an image without the big red block to mask the private key, realized their error, and replaced it with an image of it blocked. However they didn't remove the unblocked image first. Ghost (the blog engine here) just appends a number to the image when you replace it without changing the filename, so it's easy to find. See the two URLs below:
With people discussing reverse-engineering the pixelated images to access the keys, the merits of masks, security, etc it seemed like a lesson worth sharing for everyone's benefit here that an email wouldn't have accomplished.
The only reason I blurred and obfuscated where I could was just for "best practice" not for real security. I knew if I didn't people would comment that I should've ;)
> I knew if I didn't people would comment that I should've ;)
That and following good practise even when not actually necessary due to other mitigations, you obviously hint to less experienced readers what good practise is.
Even just the half of the key in that secreenshot is likely to be sufficient to recover the whole thing as well - RSA private key formats have a ton of redundant data.
With Linux if I'm a program running under target user, I can use unlocked ssh-agent to perform crypto operations with private key, but I can't extract the key itself. With Windows I can just steal the key itself. I think Windows is worse here. Am I misunderstanding something? What's the point of password protection if key is stored unprotected by this password in the registry?
The keys are protected in the registry with the current user context. You need administrator permissions on Windows to get the private keys, comparable to OSX or Linux
The private key is stored password-protected in the registry. DPAPI, the API used to protect the private key, encrypted based on the user's Windows account password, and allows decryption without further password entry by the already-logged-on user. There isn't an equivalent API in the Unix world that I'm aware of. When you fire-up the Windows SSH agent no password entry is necessary, because the password used to logon to Windows is also used to decrypt the stored private key. In a Unix environment you'd need to enter a passphrase to allow the SSH agent to decrypt the key.
I don't know if I missed your point but right now I can export a private key using seahorse, a key manager program, very easily not using its password.
You can read them with or without admin access on the same user. On the other hand a different user's admin account wouldn't help unless you can dump the first user's password.
1. You can choose to have the keys encrypted with a password (same for Windows as for Linux)
2. The key, whether encrypted or unencrypted, are for both platforms stored on disk in the user profile (see first screenshot)
3. This talks about ssh-agent, which you can use to cache the the unencrypted key so that you don't have to type the encryption password every time you want to use the key. On Linux, this is just stored in memory, whereas in Windows, it's stored (encrypted) in the registry as well.
66 comments
[ 2.9 ms ] story [ 166 ms ] thread[0] https://msdn.microsoft.com/en-us/library/ms995355.aspx
Other non-administrator users can't read these registry keys, it's encrypted with the login password (as is common with macOS Keychain and GNOME/KDE's credential stores) so even other administrators can't decrypt it.
On Linux, administrators (root) can extract the keys from ssh-agent. This is actually no less secure and usually more secure.
This is a cool demo of how to do it on Windows, and there's a reason the author didn't call it a vulnerability - it's working as designed and this form of attack is outside the intended threat model.
I don't understand how the situation is different. Of course you can extract the keys from a running ssh-agent since the whole point is not having to provide your password every time so they have to have access to the private key one way or an other. How is the situation different on Windows? Surely when the user is logged an administrator with access to the full RAM and storage will be able to piece everything together (like TFA does for instance)?
On the other hand if you really can't trust your admin you have a huge problem anyway, even with a HSM you could be phished very easily.
Actually overall I'd say that this Windows method is slightly less secure because it means that the Windows keychain thingy is a single point of failure, if somebody compromises it they have access to everything including the ssh keys in the registry.
Of course there may be ways to get an even more advanced level of access than administrator, such as the system account, but honestly Windows does lock some things down really hard at the kernel level and Data Protection decryption based on in-RAM credentials might be one. I don't know modern Windows internals to that level.
Are you sure? Typically root has access to the full RAM on an unx system. Unless this is linked to a hardware TPM module I'm not sure why and how it would be protected. Maybe I'm wrong to assume that Windows Administrator == unx root?
Anyway, if the OS has a way to hide some of its state from even the admin then surely it could use it to hide the unencrypted SSH key in RAM instead of hiding the key-to-the-registry-key? My main argument is that at some point if the OS doesn't want to prompt the user for a password it must have access to the private key one way or an other, so I'm not convinced that Windows is more (or less) secure than Linux in this situation.
Caveat: you're still trapped in your hypervisor partition. Enclaves (e.g. SGX) are also protected from admin/root snooping. IIRC, this is the same as on Linux.
> To do that, we simply start the ssh-agent service (as Administrator) and use ssh-add to store our private key.
Did Microsoft do some major surgery on the ssh-agent program or am I missing something else? If the agent is started as Administrator, why can I connect to it with my user privileges? And if I do, can other users on the same system do so, too, accessing the same set of keys?
[1] https://blogs.msdn.microsoft.com/powershell/2017/12/15/using...
No, that's what DPAPI handles. His DPAPI call works because he's decrypting his own credentials.
The service itself sometimes controls which user can access which data, but in this case since the encrypted keys are stored in the Current User Registry Hive (NTUSER.DAT) it likely doesn't need to, filesystem permissions handle that.
Plus even if another user gained access to your registry hive, the data is encrypted with your context via the Data Protection APIs.
If somebody finds a flaw in their admin ssh-agent process they potentially have a way to access other people's key or maybe even escalate their privileges.
I actually don't know. I was thinking the same thing. Hopefully they have a good reason, because you're right about the attack surface issue.
Sure, but ssh-agent does not. That's what I was alluding to with "major surgery".
Also, while the encrypted keys are stored in the file system or registry, the agent process necessarily has them in unencrypted form. That's the reason for loading keys into the agent in the first place.
To have an ssh-agent that can run as a privileged system service with multiple unprivileged clients, you need to extend it to have some notion of client identity and per-user key space. The standard OpenSSH ssh-agent doesn't have that. Users run their own instance each and if you can connect to it, you can use the keys loaded into it. All of them.
The agent code at github.com/PowerShell/openssh-portable doesn't look any different to me, at least from a cursory glance.
Thus, the decision to run it as a system service seems odd to me.
edit: are they hooking into the agent as a PKCS11 provider/"smartcard" and the plaintext keys never even hit the agent's in-memory table, to be queried by all connected clients?
PS: Also one agent process for all users on machine vs each user running a ssh-agent process
Stick to the block-of-constant-colour method used in the first few screenshots. It's ugly but safer!
There's nothing that seems architecturally unsound about how Microsoft implemented this. DPAPI is a reasonable way to protect the keys "at rest" in the registry. The OP was able to extract the keys because he has the credentials for the user from whom he is extracting the keys.
Short of storing the keys in the memory of a dedicated crypto-processor outside the host computer (and performing the cryptographic operations there) the plaintext of the private keys will have to be recoverable to the user.
ssh-agent signs requests, tokens, etc on your behalf. You never see the private key.
Edit: If your point was specifically about this from EvanAnderson's comment
>A user needs to be able to retrieve the plaintext of their SSH private keys.
then the "user" there is the abstract identity used to locate and decrypt the private key, not the human invoking ssh-agent.
It is helpful for post-exploitation toolkits to have this functionality.
https://man.openbsd.org/ssh-agent:
> The agent will never send a private key over its request channel. Instead, operations that require a private key will be performed by the agent, and the result will be returned to the requester. This way, private keys are not exposed to clients using the agent.
This sounds like a pretty gaping security hole by Microsoft. I would not assume loading private keys to an "ssh-agent" means giving any process (browser, email client etc.) running on the same machine access to the unencrypted values!
But can't just any program do that as soon as you're logged in? (Since your login password basically unlocks the DP-API which is protected at rest.)
It doesn't.
> AFAIK the whole point of ssh-agent is that the private keys are NOT extractable by other processes.
Any process with sufficient privileges (i.e., root) can extract the private key from ssh-agent on Linux as well.
So it's not a vulnerability in the sense of an unintended exposure, but, it's certainly true that Microsoft's design gives the private key much more exposure than the design used on most Linux distros. (And it's unclear whether MS intended to deviate from this behavior.)
I don't think this is correct. ssh-agent typically will be run under your user/group; it shouldn't have the necessary privileges to setgid to ssh. Further, I have ssh-agent running on a machine, and it is still my gid. Last, that machine doesn't even have an "ssh" group.
Rather, I think ssh-agent likely protects itself from being debugged (ptrace'd) by ptrace'ing itself. My understanding is that a process can only be ptraced by one process at a time, and by ptrace'ing yourself, you deny the ability for anything else to attach to you.
For example, my uid & gid:
ssh-agent running as those: but not debuggable: Perhaps this is just my machine however, and if I did have a `ssh` group, and I were a member of it, it would setgid to it. I don't think that's foolproof, however: something running under your uid could kill ssh-agent, and restart it under a debugger, skip or elide the setgid() and ptrace() calls, then continue to allow it to execute normally, and now be attached as a debugger.I'm also not sure if ptrace()'ing yourself prevents you from reading out the process's memory from /proc.
Edit: so, on Linux, it seems this is what it does[1]:
That makes the process "undumpable", which means it won't leave behind core files, /proc/pid is root:root, and it can't be ptrace()'d. I still think the caveat about starting it under a debugger applies, but that certainly makes it less trivial.[1]: https://github.com/openssh/openssh-portable/blob/5ee3fb5affd...
"being setgid to group ssh" and "calling the setgid system call to become group ssh" are two pretty different things, and it's unfortunate that UNIX uses the same terminology "setgid" to describe these two. (They don't even have the same end result; the system call changes the real group ID, and the permission bit changes the effective group ID.)
I don't think ptracing yourself is even possible (also how would you restart the process once stopped?):
Starting it under a debugger means that you have to re-load the encrypted file from disk and re-enter the password. The attack we're worried about seems to be that the system is secure when the key is initially loaded, but at some later point some malware tries to steal the key. If you have access to the password, you can just copy the key and decrypt it on some other machine.That said, I still don't think the processes group is what stops you from debugging it (it's the undumpable flag). The group check wouldn't matter and would never take effect, since your uid matches that of the process, that would be sufficient to allow you access to the process, would it not?
The dumpable flag also blocks debugging on Linux, yes. The full algorithm is way at the bottom of the ptrace manpage http://man7.org/linux/man-pages/man2/ptrace.2.html#NOTES , but it's basically:
- allow debugging another thread from the same process (because threads share memory anyway)
- allow if the debugger is privileged to debug anything (CAP_SYS_PTRACE)
- require that real, effective, and saved UIDs and GIDs all match
- require that the dumpable flag isn't set
and, if you go over and read the prctl manpage http://man7.org/linux/man-pages/man2/prctl.2.html , it points out that the dumpable flag is implicitly set to undumpable if the process changes euid/egid or exec a setuid/setgid/fscaps binary, and the execve manpage says it's set back to dumpable if you exec a normal binary.
https://blog.ropnop.com/content/images/2018/05/base64_decode...
https://blog.ropnop.com/content/images/2018/05/base64_decode...
This is probably a good reason to use burner keys for proof of concepts.
With people discussing reverse-engineering the pixelated images to access the keys, the merits of masks, security, etc it seemed like a lesson worth sharing for everyone's benefit here that an email wouldn't have accomplished.
All keys used were burner keys anyway.
The only reason I blurred and obfuscated where I could was just for "best practice" not for real security. I knew if I didn't people would comment that I should've ;)
That and following good practise even when not actually necessary due to other mitigations, you obviously hint to less experienced readers what good practise is.
https://en.wikipedia.org/wiki/Coppersmith_method
Good time to point out that we open sourced [0] all of this so I have some guesses as to how soleblaze might have "reverse engineered" it :-)
0. https://github.com/PowerShell/openssh-portable
https://msdn.microsoft.com/en-us/library/ms995355.aspx#winda...
1. You can choose to have the keys encrypted with a password (same for Windows as for Linux)
2. The key, whether encrypted or unencrypted, are for both platforms stored on disk in the user profile (see first screenshot)
3. This talks about ssh-agent, which you can use to cache the the unencrypted key so that you don't have to type the encryption password every time you want to use the key. On Linux, this is just stored in memory, whereas in Windows, it's stored (encrypted) in the registry as well.