Как хранить и получать учетные данные из диспетчера учетных данных Windows Vault?
Я хочу надежно хранить незашифрованный пароль на ПК с Windows. Я в настоящее время использую DPAPI CryptProtectData
чтобы зашифровать его, а затем сохранить зашифрованный BLOB-файл в файле в локальных AppData пользователя.
В Windows 7 есть Windows Vault, диспетчер учетных данных (Панель управления \ Учетные записи пользователей и Семейная безопасность \ Диспетчер учетных данных), в котором хранятся данные для входа в систему для различных типов входа, включая "общие учетные данные". На первый взгляд это выглядит как правильное место для программы для хранения учетных данных. Однако я не смог найти API для этого. Я прочитал ссылку на функцию аутентификации в MSDN, но, честно говоря, потерялся в ней.
Существует ли API для Windows Vault для хранения и получения учетных данных из программы, и, если да, где я могу найти документацию?
5 ответов
Большое спасибо @Luke за подсказку: функции Windows API для хранения учетных данных и чтения их из Windows Vault CredWrite()
а также CredRead()
, Вот пример кода, который можно скомпилировать и запустить, который я использовал, чтобы подтвердить, что эти функции действительно выполняют ожидаемые действия:
#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);
}
}
Общие учетные данные хранятся в хранилище Windows, как показано на снимке экрана:
Для тех, кто поздно присоединяется к потоку, в Windows 8 есть новая библиотека для взаимодействия с этим магазином, которая называется: Windows.Security.Credentials.PasswordVault
Фактически для использования класса для просмотра всех имен пользователей и паролей, хранящихся под текущей учетной записью пользователя, требуется всего две строки powershell:
[void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]
(new-object Windows.Security.Credentials.PasswordVault).RetrieveAll() | % { $_.RetrievePassword(); $_ }
Если кому-то интересно читать и писать в него из PowerShell или C#, вот ссылка на скрипт, который это делает:
Диспетчер учетных данных PowerShell: CredMan.ps1
Сценарий PowerShell обращается к API через встроенный C#, который использует Pinvoke.
Для тех, кто попадает сюда и понимает, что приведенные выше ответы относительно Windows Credential Vault больше не работают с .NET 7...
https://www.nuget.org/packages/CredentialVaultManager
использовать:
var credential = new Credential();
credential.Target = "sometargetname";
if(credential.Exists()) {
credential.Load();
}
ответ kkm показывает, как создатьgeneric credential
. Если вам нужно создатьWindows credentials
, вы можете изменить несколько параметров. Конкретный пример кода выглядит следующим образом, в надежде помочь.
#include <windows.h>
#include <wincred.h>
#include <tchar.h>
#include <wchar.h>
#include <iostream>
#pragma hdrstop
int main()
{
{
char* password = "mypassword";
//DO NOT ADD 1
DWORD blobSize = strlen(password);
CREDENTIALW cred = { 0 };
//cred.Type = CRED_TYPE_GENERIC;
cred.Type = CRED_TYPE_DOMAIN_PASSWORD;
//TargetName cannot be in the format "FOO/ Account"
cred.TargetName = L"127.0.0.1";
cred.CredentialBlobSize = blobSize;
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"127.0.0.1", CRED_TYPE_DOMAIN_PASSWORD, 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);
}
}
- Если элемент Type имеет значение , этот элемент содержит незашифрованный пароль Unicode для имени пользователя. Члены CredentialBlob и CredentialBlobSize не содержат завершающий нулевой символ. Вот почему
blobsize
это не длинаpassword
плюс один. CREDENTIALA (wincred.h) — приложения Win32 - Если тип
CRED_TYPE_DOMAIN_PASSWORD
илиCRED_TYPE_DOMAIN_CERTIFICATE
, этот член идентифицирует сервер или серверы, для которых должны использоваться учетные данные. Участником является имя сервера NetBIOS или DNS, суффикс имени хоста DNS, содержащий подстановочный знак, имя домена NetBIOS или DNS, содержащее последовательность подстановочных знаков, или звездочка.