今、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でコーディングしてます。

以下、サンプルソース。

#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;
}

コメント

最新の日記 一覧

<<  2025年6月  >>
1234567
891011121314
15161718192021
22232425262728
293012345

お気に入り日記の更新

この日記について

日記内を検索