では、プログラムを見てみましょう。
メニューのリソース・スクリプトです。別にどうということもありません。// initcpt.rc の一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "初期化(&I)" BEGIN MENUITEM "初期化する", IDM_INIT END END
最初に_WIN32_WINNTを0x0500と定義している点に注意してください。 (Windows95,NT4.0の時は0x0400) VC++のヘルプによるとWindows95/NT4.0以降の新機能を使う時 ソースコードに最初にこれを定義しなさいと書いてあります。 これを定義しないとエラーが山ほど出てきます。 wincrypt.hを見てみると// initcpt.cpp #define _WIN32_WINNT 0x0500 #ifndef STRICT #define STRICT #endif #include <windows.h> #include <wincrypt.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL InitCrypt(HWND); char szClassName[] = "initcpt"; //ウィンドウクラス
#if(_WIN32_WINNT >= 0x0400)
これが真でないとこのヘッダファイルのほとんどすべてが無効になることが わかります。
これは、いつもと同じです。int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかる暗号化", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }
メニューからIDM_INITが選択されるとInitCrypt関数が呼ばれて、デフォルトのCSPとキーの組が 作られます。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_INIT: InitCrypt(hWnd); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
最初にデフォルトのキーコンテナハンドル取得を試みます。これはCryptAcquireContextの 3番目の引数をMS_DEF_PROVにします。取得できない場合は作成します。 同じ関数で最後の引数をCRYPT_NEWKEYSETにします。BOOL InitCrypt(HWND hWnd) { HCRYPTPROV hProv; HCRYPTKEY hKey; DWORD dwUserNameLen = 256; //デフォルトキーコンテナのハンドルを取得する if(!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0)) { // デフォルトキーコンテナを作る if(!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { MessageBox(hWnd, "デフォルトキーコンテナ作成失敗", "Error", MB_OK); return FALSE; } } //署名キーのハンドルを取得する if(!CryptGetUserKey(hProv, AT_SIGNATURE, &hKey)) { if(GetLastError() == NTE_NO_KEY) { // 署名キーのペアを作る MessageBox(hWnd, "署名キーのペアを作ります" , "OK", MB_OK); if(!CryptGenKey(hProv, AT_SIGNATURE, 0, &hKey)) { MessageBox(hWnd, "CryptGenKey失敗", "Error", MB_OK); return FALSE; } else { CryptDestroyKey(hKey); } } else { MessageBox(hWnd, "CryptGetUserKey失敗", "Error", MB_OK); return FALSE; } } //交換キーのハンドルを取得する if(!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKey)) { if(GetLastError() == NTE_NO_KEY) { // 交換キーのペアを作る MessageBox(hWnd, "交換キーのペアを作ります", "OK", MB_OK); if(!CryptGenKey(hProv, AT_KEYEXCHANGE, 0, &hKey)) { MessageBox(hWnd, "CryptGenKey失敗", "Error", MB_OK); return FALSE; } else { CryptDestroyKey(hKey); } } else { MessageBox(hWnd, "CryptGetUserKey失敗", "Error", MB_OK); return FALSE; } } CryptReleaseContext(hProv,0); MessageBox(hWnd, "OK", "OK", MB_OK); return TRUE; }
次に署名キーのハンドル取得を試みます。CryptGetUserKey関数の2番目の引数を AT_SIGNATUREにします。GetLastError関数がNTE_NO_KEYを返したら、署名キーを 作ります。CryptGenKey関数の2番目の引数をAT_SIGNATUREにします。
次に交換キーのハンドル取得を試みます。CryptGetUserKey関数の2番目の引数を AT_KEYEXCHANGEにします。キーがない場合はCryptGenKey関数の2番目の引数を AT_KEYEXCHANGEにして交換キーを作ります。
最後にCryptRelease関数で後始末をします。
これで、前準備は完了です。このプログラムを1度だけ実行しておいてください。
Update 09/Apr/2000 By Y.Kumei