マシン キー コンテナー内のキーを列挙する必要があります。これは通常、オプションのプロバイダー関数ですが、 と の両方MS_STRONG_PROV
でMS_ENH_RSA_AES_PROV
サポートされています。私は何か間違ったことや異常なことをしているとは思いません: まず、 でコンテキスト ハンドルを取得し、列挙が使い果たされるまで繰り返しCryptAcquireContext(... CRYPT_MACHINE_KEYSET | CRYPT_VERIFYCONTEXT ...)
呼び出します。CryptGetProvParam(... PP_ENUMCONTAINERS ...)
void enum_keys(HCRYPTPROV hprov) {
BYTE buf[1024]; // Max key name length we support.
for (DWORD first_next = CRYPT_FIRST; 1; first_next = CRYPT_NEXT) {
DWORD buf_len = sizeof buf;
if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, buf, &buf_len, first_next)) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
else exit(1);
}
}
}
void do_benchmark(DWORD enum_flags) {
enum_flags |= CRYPT_VERIFYCONTEXT;
HCRYPTPROV hprov;
if (!CryptAcquireContext(&hprov, NULL, MS_ENH_RSA_AES_PROV_A,
PROV_RSA_AES, enum_flags))
exit(1);
int K = 100;
ClockIn(); // Pseudocode
for (int i = 0; i < K; ++i)
enum_keys (hprov);
ClockOut(); // Pseudocode.
printf(" %f ms per pass\n", TimeElapsed() / K);
CryptReleaseContext(hprov, 0);
}
void main() {
printf("--- User key store access performance test... ");
do_benchmark(0);
printf("--- Machine key store access performance test... ");
do_benchmark(CRYPT_MACHINE_KEYSET);
}
列挙のベンチマークを行うために、コンテキストの取得と解放をループの外に残し、列挙のみを記録し、列挙を 100 回繰り返します。私が気付いたのは、管理者よりも通常のユーザーの方が列挙が大幅に遅いことです。自分自身 (UAC が有効になっている管理者のメンバー) としてテストを実行すると、
--- User key store access performance test... 3.317211 ms per pass
--- Machine key store access performance test... 78.051593 ms per pass
ただし、昇格したプロンプトから同じテストを実行すると、結果は劇的に異なります。
--- User key store access performance test... 3.279580 ms per pass
--- Machine key store access performance test... 1.499939 ms per pass
内部では、管理者以外のユーザーよりも多くのキーが管理者に報告されますが、これは予想されることであり、正常です。私が理解していないのは、管理者以外のユーザーの列挙が約 40 倍遅い理由です。ポインタはありますか?
テストの完全なソースを Gist に入れています。このテストは、暗号化ハードウェアのない非常に一般的な Windows 7 マシンで実行されます。
追加: Server 2012 HyperV ホスト上の Server 2012 仮想マシンでは、スローダウン係数はさらに大きく、130 を超えました: 440 対 3.3 ミリ秒。確かに、440ms は私にとってパフォーマンスの問題です。