ヒントを提供してくれた @Luke に感謝します。資格情報を Windows Vault に保存して読み取る Windows API 関数はCredWrite()
、CredRead()
. 以下は、これらの関数が実際に期待どおりの動作をすることを確認するために使用した、コンパイルして実行できるコード サンプルです。
#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);
}
}
スクリーンショットに示すように、一般的な資格情報は Windows Vault に保存されます。

補遺: Vault vs Crypto DP API
この回答は非常に人気があるようで、私が書いてから 6 年近く定期的に支持されています。::CryptProtectData()
資格情報をボールトに保存することと、 API を使用して資格情報 BLOB を暗号化し、必要なときにいつでも保存することの違いについて、コメントで提起された質問がありました。主な違いについての私の理解は、おそらく網羅的ではありませんが、次のとおりです。
- ローミング制御。Vault 内のストレージは、システムによって管理されます。ドメイン環境では、この設定
cred.Persist = CRED_PERSIST_ENTERPRISE;
により、暗号化された資格情報がユーザーのローミング プロファイルの一部になるため、任意のドメイン コンピューターにログオンしているユーザーが利用できるようになります。CryptProtectData()
データのみを暗号化します。暗号文の保管はユーザーの責任です。%APPDATA%
ドメインのローミング設定によっては、暗号文を下に保存するとローミングも可能になりますが、ファイルに適切な ACL を設定し、EFS で保存時の暗号化を強制することは、やはり呼び出し元の責任です。ボールト データは、保存時にシステムによって暗号化されます。
- UI の可視性。Vault の資格情報は Vault の UI に表示され、不要になった場合や侵害された疑いがある場合は取り消すことができます。から取得した暗号文
CryptProtectData()
は、アプリケーションによって完全に制御されます。ターゲット ソフトウェアの設計では、可視性機能を考慮する必要があります。
- Vault は、メモリに暗号化されて格納される揮発性のログオン セッションごとのシークレットをサポートします (
cred.Persist = CRED_PERSIST_SESSION;
)。ジェネリック API を使用したこのような機能の実装は、認証された IPC や同期を伴う正しく保護された共有メモリ マッピングなどを含むため、適切に実装するのは比較的困難です。
- 塩漬け。の場合
CryptProtectData()
、呼び出し元は追加のソルトを提供できます (復号化中に再度提供する必要があるため、保存する手段があります)。Vault が内部的に処理します。
- Vault の範囲はより狭いです。ID に関係のないデータの保存に Vault を使用するのは、おそらく設計上の臭いです。
- 監査。
CryptProtectData()
BLOB が復号化されるときの監査レコードの作成を制御できます (CRYPTPROTECT_AUDIT
ビット フラグ)。Vault API でこのようなものを確認できません ( wincred.h
)。Vault アクセスの監査が可能かどうかはわかりません。常に実行されるか、実行されないか、GPO によって制御されるか。実際、私はここで空白を描いています。
- Vault はHVCI (旧称Device Guard ; Windows 10/11 Pro および Enterprise でのみ利用可能、および対応するサーバー SKU) によって保護されます。有効にすると、システムの保護された部分は、別の準仮想化され、ハードウェアでサポートされ、厳密に制御されたアドレス空間で実行されます。このアドレス空間は、通常のアドレス空間には単に「存在しません」 (HVCI で保護された空間は、LSA およびその他の重要なコンポーネントが存在する場所です)。ライブもあります)。これにより、カーネル モード スタックからでもアクセスできなくなります。CNGプロバイダーもそのコンパートメントに住んでいますが
CryptProtectData()
、暗号文ブロブが呼び出し元のプログラムに返されると、結果は必然的にこの境界を越えます(また、CryptProtectData()
CNGによってサポートされているかどうかもわかりません)。Vault で暗号化されたデータは、保護された境界内にとどまります。クリアテキストのみが交差します。
要約すると、Vault は、システム UI を介して管理され、ユーザーに表示され、ユーザーが管理する資格情報やその他の ID 関連の秘密を保持するための、より高レベルで対象を絞った API です。CryptProtectData()
永続化された暗号文を安全に管理するために、より多くの柔軟性とより多くのコードを作成および監査する必要がある汎用暗号化 API です。
どちらが「より安全」であるかという問題は不適切です。全般的な暗号化の使用に適用できる「多かれ少なかれ安全」の定義はありません。