第266章 ファイルの復号


今回は、前章で作った暗号化ファイルの復号を行います。 復号したファイルを作るのと同時に、可能で有ればエディットコントロール に表示するようにもします。



復号する手順は

1.CryptAcquireContext関数でCSPのハンドルを取得します 2.CryptImportKey関数でCSPに暗号キーを転送します   暗号キーは暗号化ファイルの最初の方に書いてあります 3.CryptImportKey関数で復号します 4.後始末

と、こんな感じになります。

BOOL WINAPI CryptImportKey( HCRYPTPROV hProv, // in BYTE *pbData, // in DWORD dwDataLen, // in HCRYPTKEY hPubKey, // in DWORD dwFlags, // in HCRYPTKEY *phKey // out );

キープロッブからCSPに暗号キーを転送します。

hProvは、CSPのハンドルです。

pbDataは、キープロッブを含むバッファです。

dwDataLenはキープロップの長さです。

hPubKeyはインポートされたキープロッブの種類やCSPのタイプによって異なる意味を持ちます。
もし、署名キーがインポートされているならば、このキーは署名キープロッブを有効にするのに使われます。
もし、キープロッブが交換キーのペアで暗号化されていれば、このパラメーターは交換キーのハンドルで なくてはなりません。
もし、キープロッブがセッションキーで暗号化されているならばこのパラメーターはセッションキーの ハンドルでなくてはいけません。
もし、このキープロッブが暗号化されていないならば、0を指定します。

dwFlagsは、フラグ値を指定します。このパラメーターはpublic/privateキーペアがCSPにインポートされる場合のみ 使われます。

phKeyは、キーハンドルのアドレスです。

BOOL WINAPI CryptDecrypt( HCRYPTKEY hKey, // in HCRYPTHASH hHash, // in BOOL Final, // in DWORD dwFlags, // in BYTE *pbData, // in/out DWORD *pcbData // in/out );

CryptEncrypt関数で暗号化されたデータを復号します。

hKeyは復号に使うキーハンドルです。CryptGenKeyまたはCryptImportKey関数で取得します。

hHashは、ハッシュオブジェクトのハンドルです。ハッシュを使わない場合は0を指定します。

Finalは、このセクションが復号の最後であるかどうかを指定するプール値です。最後のブロックで有れば TRUEをそうでなければFALSEを指定します。

dwFlagsは、予約されています。0を指定します。

pbDataは、復号されるデータを入れるバッファです。復号後テキストがこのバッファにおかれます。

pcbDataは、データの長さのアドレスです。呼び出し側は復号されるデータの長さをセットします。 戻ってくるときは生成されたテキストの長さのアドレスが入ります。

では、プログラムを見てみましょう。

// encrypt02.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)...", IDM_END END POPUP "暗号(&C)" BEGIN MENUITEM "暗号化(&E)", IDM_ENCRYPT MENUITEM "復号(&D)", IDM_DECRYPT END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDECRYPTFILENAME DIALOG DISCARDABLE 0, 0, 187, 51 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "復号後のファイル名" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,30,50,14 PUSHBUTTON "キャンセル",IDCANCEL,130,30,50,14 EDITTEXT IDC_EDIT1,7,7,173,16,ES_AUTOHSCROLL END

メニューと簡単なダイアログボックスのリソース・スクリプトです。

メニューでは前章に比べて「復号」が増えました。

ダイアログボックスは復号したファイルのファイル名を入力するものです。

// encrypt02.cpp #define _WIN32_WINNT 0x0500 #define ID_EDIT 100 #ifndef STRICT #define STRICT #endif #include <windows.h> #include <wincrypt.h> #include <windowsx.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDecryptFileNameProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL MyEncrypt(void); BOOL MyDecrypt(HWND); char szClassName[] = "encrypt02"; //ウィンドウクラス HINSTANCE hInst;

エディットコントロール関連のマクロを使うのでwindows.hをインクルードするのを 忘れないでください。

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; 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; }

これは、いつもと同じです。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HWND hEdit; switch (msg) { case WM_CREATE: hEdit = CreateWindow("EDIT", "", WS_VISIBLE | WS_CHILD | ES_MULTILINE | ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_HSCROLL | WS_VSCROLL, 0, 0, 0, 0, hWnd, (HMENU)ID_EDIT, hInst, NULL); break; case WM_SIZE: MoveWindow(hEdit, 0, 0, LOWORD(lp), HIWORD(lp), TRUE); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_ENCRYPT: if (MyEncrypt()) MessageBox(hWnd, "暗号化が成功しました。\n" "暗号化したファイルは元ファイルの拡張子に「0」が付加されます", "暗号化の完了", MB_OK); else MessageBox(hWnd, "暗号化に失敗しました", "Error", MB_OK); break; case IDM_DECRYPT: MyDecrypt(hEdit); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hEdit); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

WM_CREATEメッセージが来たらエディットコントロールを作ります。

WM_SIZEメッセージが来たらエディットコントロールのサイズを調整して 親ウィンドウのクライアント領域にちょうどぴったりとなるようにします。

メニューからIDM_DECRYPTが選択されたら自作関数MyDecryptを呼びます。

BOOL MyEncrypt() { HANDLE hOrg, hAfter; BYTE pbBuf[1024 * 4]; BOOL bEnd = FALSE; HCRYPTPROV hCryptprov; HCRYPTKEY hExKey, hKey; DWORD dwByte, dwResult; static char szOrgFile[MAX_PATH], szAfterFile[MAX_PATH]; static char szOrgTitle[MAX_PATH], szAfterTitle[MAX_PATH]; OPENFILENAME ofn; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.lpstrFilter = "テキスト(*.txt)\0*.txt\0すべて(*.*)\0*.*\0\0"; ofn.lpstrFile = szOrgFile; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = szOrgTitle; ofn.nMaxFileTitle = MAX_PATH; ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrTitle = "暗号化するファイルを開く"; if (!GetOpenFileName(&ofn)) return FALSE; strcpy(szAfterFile, szOrgFile); strcat(szAfterFile, "0"); strcpy(szAfterTitle, szOrgTitle); strcat(szAfterTitle, "0"); if (!CryptAcquireContext(&hCryptprov, NULL, NULL, PROV_RSA_FULL, 0)) { MessageBox(NULL, "CryptAcquireContext Error", "Error", MB_OK); return FALSE; } if (!CryptGetUserKey(hCryptprov, AT_KEYEXCHANGE, &hExKey)) { MessageBox(NULL, "CryptGetUserKey Error", "Error", MB_OK); return FALSE; } if (!CryptGenKey(hCryptprov, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) { MessageBox(NULL, "CryptGenKey Error", "Error", MB_OK); return FALSE; } CryptExportKey(hKey, hExKey, SIMPLEBLOB, 0, NULL, &dwByte); if (!CryptExportKey(hKey, hExKey, SIMPLEBLOB, 0, pbBuf, &dwByte)) { MessageBox(NULL, "CryptExportKey Error", "Error", MB_OK); return FALSE; } hOrg = CreateFile(szOrgFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); hAfter = CreateFile(szAfterFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); WriteFile(hAfter, &dwByte, sizeof(dwByte), &dwResult, NULL); WriteFile(hAfter, pbBuf, dwByte, &dwResult, NULL); while (1) { ReadFile(hOrg, pbBuf, sizeof(pbBuf), &dwByte, NULL); if (dwByte < sizeof(pbBuf)) bEnd = TRUE; CryptEncrypt(hKey, 0, bEnd, 0, pbBuf, &dwByte, sizeof(pbBuf)); WriteFile(hAfter, pbBuf, dwByte, &dwResult, NULL); if (bEnd) break; } CryptDestroyKey(hKey); CryptDestroyKey(hExKey); CryptReleaseContext(hCryptprov, 0); CloseHandle(hOrg); CloseHandle(hAfter); return TRUE; }

前章と同じです。

BOOL MyDecrypt(HWND hEdit) { int id; DWORD dwSize, dwWritten; HANDLE hEncryptFile, hDecryptFile; BYTE pbBuffer[1024 * 2 + 1]; BOOL bEnd = FALSE, bEdit; OPENFILENAME ofn; static char szEncryptFile[MAX_PATH], szEncryptTitle[MAX_PATH]; static char szDecryptFile[MAX_PATH]; HCRYPTPROV hProvider; HCRYPTKEY hKey; static char szEditTxt[1024 * 64]; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.lpstrFilter = "すべて(*.*)\0*.*\0\0"; ofn.lpstrFile = szEncryptFile; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = szEncryptTitle; ofn.nMaxFileTitle = MAX_PATH; ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrTitle = "復号するファイルを開く"; if (!GetOpenFileName(&ofn)) return FALSE; id = MessageBox(NULL, "エディットコントロールに表示しますか?", "テキスト表示", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) bEdit = TRUE; else bEdit = FALSE; strcpy(szDecryptFile, szEncryptFile); id = DialogBoxParam(hInst, "MYDECRYPTFILENAME", hEdit, (DLGPROC)MyDecryptFileNameProc, (LPARAM)szDecryptFile); if (id == IDCANCEL) return FALSE; if (!CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_FULL, 0)) { MessageBox(NULL, "CryptAcquireContext Error", "Error", MB_OK); return FALSE; } hEncryptFile = CreateFile(szEncryptFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); hDecryptFile = CreateFile(szDecryptFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); ReadFile(hEncryptFile, &dwSize, sizeof(dwSize), &dwWritten, NULL); ReadFile(hEncryptFile, pbBuffer, dwSize, &dwWritten, NULL); if (!CryptImportKey(hProvider, pbBuffer, dwSize, 0, 0, &hKey)) { MessageBox(NULL, "CryptImportKey Error", "Error", MB_OK); CryptReleaseContext(hProvider, 0); CloseHandle(hEncryptFile); return FALSE; } while (1) { ReadFile(hEncryptFile, pbBuffer, 1024 * 2, &dwSize, NULL); if (dwSize < 1024 * 2) bEnd = TRUE; else bEnd = FALSE; if (!CryptDecrypt(hKey, 0, bEnd, 0, pbBuffer, &dwSize)) { MessageBox(NULL, "CryptDecrypt Error", "Error", MB_OK); return FALSE; } WriteFile(hDecryptFile, pbBuffer, dwSize, &dwWritten, NULL); if (bEdit) { *(pbBuffer + dwSize) = '\0'; strcat(szEditTxt, (char *)pbBuffer); SetWindowText(hEdit, szEditTxt); } if (bEnd) break; } CryptDestroyKey(hKey); CryptReleaseContext(hProvider, 0); CloseHandle(hEncryptFile); CloseHandle(hDecryptFile); MessageBox(NULL, "復号を完了しました", "完了", MB_OK); return TRUE; }

復号する関数です。

ファイルの先頭からキーの大きさを読み込んで、その後キーを読み込みます。 そして、CryptImportKey関数でCSPにキーを転送します。

あとは、CryptDecrypt関数で復号します。エディットコントロールに表示するとき pbBufferは(char *)型ではないので、データの最後にヌル文字を追加している点に注意してください。

また、復号後のファイル名を訪ねるダイアログボックスを出すときDialogBoxParamを使っている点に 注意してください。

LRESULT CALLBACK MyDecryptFileNameProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static char *lpszF; static HWND hDlgEdit; switch (msg) { case WM_INITDIALOG: lpszF = (char *)lp; hDlgEdit = GetDlgItem(hDlg, IDC_EDIT1); Edit_SetText(hDlgEdit, (char *)lp); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: Edit_GetText(hDlgEdit, lpszF, MAX_PATH); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return TRUE; } return FALSE; }

復号後のファイル名を訪ねるダイアログボックスのプロシージャです。 WM_INITDIALOGでszDecryptFile[0]のアドレスをコピーしています。

OKボタンが押されたらエディットコントロールの文字列を取得します。

さて、このプログラムで暗号化したファイルを他のコンピュータにコピーして 持っていったとします。そこで、そのコンピュータにもこのプログラムが 有ったとして、これでファイルの復号ができるでしょうか。 いろいろ実験してみてください。


[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 17/Apr/2000 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。