EternalWindows
CSP / CSPの列挙

CSPを利用するにあたり、まずはシステムにどれだけのCSPがインストールされているのかを確認したいと思います。 次に示すCryptEnumProvidersは、CSPの名前とそのCSPのプロバイダタイプを列挙します。

BOOL WINAPI CryptEnumProviders(
  DWORD dwIndex, 
  DWORD *pdwReserved,
  DWORD dwFlags,
  DWORD *pdwProvType, 
  LPTSTR pszProvName,
  DWORD *pcbProvName
);

dwIndexは、列挙したいCSPのゼロベースのインデックスを指定します。 pdwReservedは、予約されているためNULLを指定します。 dwFlagsも、予約されているためNULLを指定します。 pdwProvTypeは、列挙されたCSPのプロバイダタイプを受け取る変数のアドレスを指定します。 pszProvNameは、列挙されたCSPの名前を受け取るバッファを指定します。 pcbProvNameは、バッファのサイズを格納した変数のアドレスを指定します。 advapi32.dllからエクスポートされる全てのCryptoAPIの名前はCryptから始まり、 戻り値も全てBOOL型となります。

プロバイダタイプとは、暗号化やハッシュ等の各技術にどのようなアルゴリズムを用いるかを表す値です。 CryptoAPIでは暗号化の実装方法などをアプリケーションから隠蔽しているわけですが、 どのようなアルゴリズムを使用するかは選択できることになっているので、 特定のアルゴリズムを利用したい場合は、それをサポートするプロバイダタイプを選択することになります。 次に、定義されているプロバイダタイプの一部を示します。

プロバイダタイプ 鍵交換 署名 暗号化 ハッシュ
PROV_RSA_FULL(1) RSA RSA RC2
RC4
MD5
SHA
PROV_DSS(3) なし DSS なし MD5
SHA
PROV_MS_EXCHANGE(5) RSA RSA CAST MD5
PROV_RSA_SCHANNEL(12) RSA RSA RC4
DES
3DES
MD5
SHA
PROV_DSS_DH(13) DH DSS CYLINK_MEK MD5
SHA
PROV_DH_SCHANNEL(18) DH DSS DES
3DES
MD5
SHA
PROV_RSA_AES(24) RSA RSA RC2
RC4
AES
MD5
SHA

たとえば、RC2という暗号化アルゴリズムを利用したい場合、 RC2はPROV_RSA_FULLとPROV_RSA_AESでサポートされているため、 この2つのいずれかのプロバイダタイプを選択することになります。 一方、AESという暗号化アルゴリズムはPROV_RSA_AESのみサポートしていますから、 このようなときは必ずPROV_RSA_AESを選択することになります。

今回のプログラムは、CryptEnumProvidersで取得したCSPの名前と プロバイダタイプをリストボックスに表示します。

#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndListBox = NULL;

	switch (uMsg) {

	case WM_CREATE: {
		DWORD i;
		DWORD dwSize;
		DWORD dwProvType;
		TCHAR szProvName[256];
		TCHAR szBuf[256];

		hwndListBox = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);

		for (i = 0;; i++) {
			dwSize = sizeof(szProvName);
			if (!CryptEnumProviders(i, NULL, 0, &dwProvType, szProvName, &dwSize))
				break;
			wsprintf(szBuf, TEXT("%s : (type %d)"), szProvName, dwProvType);
			SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		}

		return 0;
	}
	
	case WM_SIZE:
		MoveWindow(hwndListBox, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

CryptEnumProvidersのpdwProvTypeにはプロバイダタイプが格納されるため、 この値を確認すればそのCSPが実装するアルゴリズムを知ることができます。 たとえば、プロバイダタイプがPROV_RSA_FULLのCSPは、 RC2とRC4の各暗号化アルゴリズムを実装しているということになります。

デフォルトCSPについて

CSPを利用するためには、CSPの名前とプロバイダタイプの両方を指定する方法と、 プロバイダタイプのみを単一で指定する方法があります。 後者の場合、指定したプロバイダタイプをサポートするCSPのうち、 デフォルトに設定されているCSPが対象となることになっています。 各プロバイダタイプのデフォルトCSPを確認するべく、次のコードを検討します。

#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndListBox = NULL;

	switch (uMsg) {

	case WM_CREATE: {
		DWORD i;
		DWORD dwSize;
		DWORD dwProvType;
		CHAR  szTypeName[256];
		TCHAR szProvName[256];
		TCHAR szBuf[256];

		hwndListBox = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);

		for (i = 0;; i++) {
			dwSize = sizeof(szTypeName);
			if (!CryptEnumProviderTypesA(i, NULL, 0, &dwProvType, szTypeName, &dwSize))
				break;
			dwSize = sizeof(szProvName);
			CryptGetDefaultProvider(dwProvType, NULL, CRYPT_USER_DEFAULT, szProvName, &dwSize);

			wsprintf(szBuf, TEXT("%d, %s"), dwProvType, szProvName);
			SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		}

		return 0;
	}

	case WM_SIZE:
		MoveWindow(hwndListBox, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

CryptEnumProviderTypesは、システムにインストールされているCSPによって サポートされているプロバイダタイプを列挙します。 第3引数にはプロバイダタイプの値が返り、第4引数にはプロバイダタイプの意味を示す文字列が格納されます。 明示的にANSI版の関数を呼び出しているのは、何故かUNICODE版では関数が成功しないからであり、 今回の場合は第4引数で取得した文字列を利用するつもりもないので、特に不都合はありません。 CryptGetDefaultProviderの第1引数にプロバイダタイプを指定すると、 第4引数にそのプロバイダタイプのデフォルトCSPの名前が格納されます。 デフォルトCSPはユーザー単位とマシン単位というように個別に設定することができ、 CRYPT_USER_DEFAULTの場合は、コードを実行しているユーザーのデフォルトCSPが取得されます。 しかし、ユーザー単位でデフォルトCSPが設定されていることは滅多にないため、 デフォルトCSPが存在しなかった場合は、マシン単位のCSPが参照されることになっています。 CryptSetProviderExを呼び出せば、ユーザー単位やマシン単位にデフォルトCSPを設定することができます。



戻る