I want to securely store a plaintext password on Windows PC. I am currently using DPAPI CryptProtectData
to encrypt it, then store the encrypted blob in a file in user's local AppData.
In Windows 7, there is Windows Vault, a credential manager (Control Panel\User Accounts and Family Safety\Credential Manager) that stores logon data for a variety of logon types, including "generic credential". On the surface this looks like the right place for a program to store credentials. However, I was not able to find any API for it. I read Authentication function reference in MSDN, but frankly got lost in it.
Is there an API to Windows Vault to store and retrieve credentials from a program, and, if yes, where can I find documentation?
Many thanks to @Luke for the hint: Windows API functions to store credentials to and read them from Windows Vault are CredWrite()
and CredRead()
. Here is a code sample that may be compiled and run, that I used to confirm that these functions indeed do the expected thing:
#include <windows.h> #include <wincred.h> #include <tchar.h> #pragma hdrstop int main () { { //--- SAVE char* password = "brillant"; DWORD cbCreds = 1 + strlen(password); CREDENTIALW cred = {0}; cred.Type = CRED_TYPE_GENERIC; cred.TargetName = L"FOO/account"; cred.CredentialBlobSize = cbCreds; cred.CredentialBlob = (LPBYTE) password; cred.Persist = CRED_PERSIST_LOCAL_MACHINE; cred.UserName = L"paula"; BOOL ok = ::CredWriteW (&cred, 0); wprintf (L"CredWrite() - errno %d\n", ok ? 0 : ::GetLastError()); if (!ok) exit(1); } { //--- RETRIEVE PCREDENTIALW pcred; BOOL ok = ::CredReadW (L"FOO/account", CRED_TYPE_GENERIC, 0, &pcred); wprintf (L"CredRead() - errno %d\n", ok ? 0 : ::GetLastError()); if (!ok) exit(1); wprintf (L"Read username = '%s', password='%S' (%d bytes)\n", pcred->UserName, (char*)pcred->CredentialBlob, pcred->CredentialBlobSize); // Memory allocated by CredRead() must be freed! ::CredFree (pcred); } }
A generic credential is stored in Windows Vault, as can be seen on the screenshot:
The answer appears to be quite popular, and is upvoted regularly for nearly 6 years since I wrote it. There were questions raised in the comments about the difference between storing credentials in the vault and encrypting a credential blob with the ::CryptProtectData()
API and storing it whenever one pleases. Here's my understanding, possibly non-exhaustive, of the key differences.
cred.Persist = CRED_PERSIST_ENTERPRISE;
makes the encrypted credential part of the user's roaming profile, and thus available to the user logged on any domain computer. CryptProtectData()
only encrypts data; the keeping of the ciphertext is the user's responsibility. Storing ciphertext under %APPDATA%
possibly makes it roaming also, depending on the domain's roaming setup, but setting a proper ACL on the file and enforcing encryption-at-rest with the EFS is, again, the caller's responsibility. Vault data are encrypted at rest by the system.CryptProtectData()
is fully controlled by the application. The visibility feature must be taken into account in the target software design.cred.Persist = CRED_PERSIST_SESSION;
). An implementation of such a feature with the generic API is relatively hard to get right, as it involves either authenticated IPC or correctly protected shared memory mapping with synchronization, etc.CryptProtectData()
, the caller may provide additional salt (that has to be provided again during decryption, thus have means to store it). Vault takes care of it internally.CryptProtectData()
has control over creating an audit record when a blob is decrypted (the CRYPTPROTECT_AUDIT
bit flag). I cannot see anything like this in the Vault API (wincred.h
). I do not know whether auditing Vault access is possible; if it's always done, never done, or controlled by a GPO; in fact, I'm drawing a blank here.CryptProtectData()
necessarily crosses this boundary when the ciphertext blob is handed back to the calling program (also, I'm not sure if CryptProtectData()
is backed by CNG or not). Vault-encrypted data stay within the protected boundary; only cleartext crosses it.In summary, Vault is a higher-level, narrowly-targeted API for keeping user-visible, user-managed credentials and other identity-related secrets, managed through the system UI. CryptProtectData()
is a general use encryption API, with more flexibility and more code needed to be written and audited to manage persisted ciphertext safely.
The question which of the two is "more secure" is ill-posed. There is no definition of "more or less secure" that could apply to any use of encryption across the board.
For people joining the thread late, there is a new library to interact with this store in Windows 8 called: Windows.Security.Credentials.PasswordVault
In fact it only takes two lines of powershell to use the class to view all user names and passwords stored under the current users account:
[void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime] (new-object Windows.Security.Credentials.PasswordVault).RetrieveAll() | % { $_.RetrievePassword(); $_ }
Update: It looks like Microsoft (thankfully) restricted this api more in Windows 10 and it will no longer dump all your passwords so trivially. This is only indication of the change that I have seen:
The contents of the locker are specific to the app or service. Apps and services don't have access to credentials associated with other apps or services.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With