How do I store and retrieve credentials from the Windows Vault credential manager?
-
28-04-2021 - |
Question
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?
Solution
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
void 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);
// must free memory allocated by CredRead()!
::CredFree (pcred);
}
}
A generic credential is stored in Windows Vault, as can be seen on the screenshot:
OTHER TIPS
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 anyone is interested in reading and writing to it from PowerShell or C#, here's a link to a script that does it:
PowerShell Credentials Manager: CredMan.ps1
The PowerShell script accesses the API via inline C# that utilizes Pinvoke.