Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I store and retrieve credentials from the Windows Vault credential manager?

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?

like image 398
kkm Avatar asked Feb 10 '12 00:02

kkm


2 Answers

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:

A generic credential stored in Windows Vault

Addendum: Vault vs Crypto DP API

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.

  • Roaming control. Storage in the Vault is managed by the system. In a domain environment, setting 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.
  • UI visibility. A Vault credential is shown in the Vault UI, and may be revoked when no longer needed or suspected to be compromised. Ciphertext obtained from CryptProtectData() is fully controlled by the application. The visibility feature must be taken into account in the target software design.
  • Vault supports volatile per-logon-session secrets, stored encrypted in memory (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.
  • Salting. In case of 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.
  • Vault has a narrower scope. Using Vault for storing of non-identity-related data is likely a design smell.
  • Audit. 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.
  • Vault is protected by HVCI (née Device Guard; available in Windows 10/11 Pro and Enterprise only, and corresponding Server SKUs). When enabled, the protected part of system runs in a separate paravirtualized, hardware-supported, tightly-controlled address space, which simply "does not exist" in the regular address space (the HVCI-protected space is where the LSA and other critical components also live). This makes it inaccessible even from a kernel mode stack. While CNG providers also live in that compartment, the result of 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.

like image 184
kkm Avatar answered Sep 20 '22 10:09

kkm


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.

like image 41
Tim Avatar answered Sep 17 '22 10:09

Tim