WinCryptAPIの怪
2010年7月29日 コンピュータ今、UNIXで開発されたプログラムをWindowsに移植するための事前調査をしています。
その中の調査項目に、AES暗号データを復号するというものがあります。
UNIX側がAES128/MD5またはAES256/SHA256で暗号化したデータ(ライブラリはOpenSSLを使用)を、Windows側ではOpenSSLを使用せずにWindows標準のWinCryptAPIでやってみるのが課題。
実際に暗号化されたデータ(AES128/256で2種類)を試して見ると、AES256はOKなのにAES128だとBAD_DATAになってしまう。
でも、WindowsにOpenSSLを入れてそっちでやってみると、AES128もちゃんと復号できるんです。どうなってんだよ…… Microsoftの罠なのか?
開発環境はWindows XP(SP3) + Visual Studio 2010。UNIX側がC言語なので、それに付き合ってCでコーディングしてます。
以下、サンプルソース。
その中の調査項目に、AES暗号データを復号するというものがあります。
UNIX側がAES128/MD5またはAES256/SHA256で暗号化したデータ(ライブラリはOpenSSLを使用)を、Windows側ではOpenSSLを使用せずにWindows標準のWinCryptAPIでやってみるのが課題。
実際に暗号化されたデータ(AES128/256で2種類)を試して見ると、AES256はOKなのにAES128だとBAD_DATAになってしまう。
でも、WindowsにOpenSSLを入れてそっちでやってみると、AES128もちゃんと復号できるんです。どうなってんだよ…… Microsoftの罠なのか?
開発環境はWindows XP(SP3) + Visual Studio 2010。UNIX側がC言語なので、それに付き合ってCでコーディングしてます。
以下、サンプルソース。
#include "test.h"
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "advapi32.lib")
#define KEYLENGTH_128 128 * 0x10000 // 128-bit長
#define KEYLENGTH_256 256 * 0x10000 // 256-bit長
//// OpenSSL
//#define __WINCRYPT_H__
//#include "opensslaes.h"
//#include "opensslmd5.h"
//#pragma comment(lib, "libeay32md.lib")
BYTE *AES_decrypt(char *pswd, char *src_buff, size_t src_size)
{
BYTE *w_aes = NULL; // AES変換領域
BYTE w_iv[16]; // 初期化ベクタ(IV)
HCRYPTPROV hProv = 0; // キーコンテナ
HCRYPTHASH hHash = 0; // ハッシュのインスタンス
HCRYPTKEY hKey = 0; // 鍵
DWORD mode = CRYPT_MODE_CBC; // 暗号モード
DWORD padding_mode = PKCS5_PADDING; // パディングモード
DWORD dwDataLen = 0; // 暗号化データのバイト長データ
// 引数の復号前データの先頭16バイトは初期化ベクタ(IV)
memcpy(w_iv, src_buff, 16);
// IV以降が本物の復号前データ
dwDataLen = src_size - 16;
w_aes = (BYTE*)malloc(dwDataLen + 1); // NULLストッパーのため+1で確保
memset(w_aes, 0, dwDataLen + 1); // NULLクリア
memcpy((void*)w_aes, src_buff + 16, dwDataLen); // IV以降をコピー
//// OpenSSL start
//unsigned char w_digest[33];
//AES_KEY w_aeskey;
//MD5_CTX w_ctx;
//
//memset(&w_ctx, 0, sizeof(w_ctx));
//memset(w_digest, 0, 33);
//
// MD5でハッシュ
//MD5_Init(&w_ctx);
//MD5_Update(&w_ctx, (unsigned char*)pswd, strlen(pswd));
//MD5_Final(w_digest, &w_ctx);
//
//// AES共通鍵を生成
//AES_set_decrypt_key(w_digest, 128, &w_aeskey);
//// AES共通鍵暗号で復号化
//AES_cbc_encrypt( (unsigned char*)w_decode+AES_BLOCK_SIZE, w_aes, dwDataLen, &w_aeskey, w_iv, AES_DECRYPT );
//
//return w_aes;
//// OpenSSL end
// キーコンテナの取得
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, 0)){
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_NEWKEYSET)){
return NULL;
}
}
// ハッシュのインスタンスを生成(MD5)
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)){
CryptReleaseContext(hProv, 0);
return NULL;
}
// ハッシュ値の計算
if(!CryptHashData(hHash, (BYTE*)pswd, (DWORD)strlen(pswd), 0))
{
CryptReleaseContext(hProv, 0);
return NULL;
}
// 鍵の生成(AES128)
if(!CryptDeriveKey(hProv, CALG_AES_128, hHash, KEYLENGTH_128, &hKey)){
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return NULL;
}
// ブロック暗号化のパディングを設定
if(!CryptSetKeyParam(hKey, KP_PADDING, (BYTE*)&padding_mode, 0)){
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return NULL;
}
// 初期化ベクタをセット
if(!CryptSetKeyParam(hKey, KP_IV, w_iv, 0)){
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return NULL;
}
// 暗号モードを設定
if(!CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&mode, 0)){
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return NULL;
}
// 復号
if(!CryptDecrypt(hKey, 0, TRUE, 0, (BYTE*)w_aes, &dwDataLen)){
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return NULL;
}
// 念のためNULLストッパー
w_aes[dwDataLen] = ’ ’;
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return w_aes;
}
コメント