Crypto APIによる暗号化
Crypto APIによる暗号化は、ちょっとした用途で暗号化強度がさほど必要でない場合に便利だ。
今回は文字列を暗号化・復号化するルーチンのサンプルを提示する。
もっと強度が必要な場合には、Cryptography API: Next Generationを用いるとよいようだ。
こちらについては、「主筆」さんのHPにある記事がわかりやすい。
http://www.syuhitu.org/other/cng/cng.html
まず、カプセル化。なお以下のコードではSHA-256などは用いることができない。
#include <wincrypt.h> class TMyCrypt { private: HCRYPTPROV hProv; HCRYPTHASH hHash; HCRYPTKEY hKey; bool is_init(); public: TMyCrypt() : hProv(0), hHash(0), hKey(0) {}; ~TMyCrypt() { finalize(); } bool init( const TCHAR *pass, ALG_ID hash_alg = CALG_SHA1, ALG_ID enc_alg = CALG_RC4, DWORD keyLen = 0x00800000 ); void finalize(); bool encrypt( BYTE *ret, const TCHAR *src, DWORD &dwLen ); bool decrypt( TCHAR *ret, const BYTE *src, DWORD &dwLen ); }; //---------------------------------------------------------------- bool TMyCrypt::is_init() { return (hKey)? true : false; } //---------------------------------------------------------------- bool TMyCrypt::init( const TCHAR *pass, ALG_ID hash, ALG_ID enc, DWORD dwKeyLen ) { finalize(); // 二重突入対策 if( !CryptAcquireContext( &hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) ) return false; if( CryptCreateHash( hProv, hash, 0, 0, &hHash ) ) { DWORD dwLen = ::lstrlen(pass)*sizeof(TCHAR); if( CryptHashData( hHash, reinterpret_cast<const BYTE*>(pass), dwLen, 0 ) ) return CryptDeriveKey( hProv, enc, hHash, dwKeyLen, &hKey ); } finalize(); return false; } //---------------------------------------------------------------- void TMyCrypt::finalize() { if( hKey ) { CryptDestroyKey( hKey ); hKey = 0; } if( hHash ) { CryptDestroyHash( hHash ); hHash = 0; } if( hProv ) { CryptReleaseContext( hProv, 0 ); hProv = 0; } } //---------------------------------------------------------------- bool TMyCrypt::encrypt( BYTE *ret, const TCHAR *src, DWORD &dwLen ) { if( !is_init() ) return false; dwLen = ::lstrlen(src)*sizeof(TCHAR); memcpy( ret, src, dwLen ); bool bRet = CryptEncrypt( hKey, 0, true, 0, ret, &dwLen, dwLen ); return bRet; } //---------------------------------------------------------------- bool TMyCrypt::decrypt( TCHAR *ret, const BYTE *src, DWORD &dwLen ) { if( !is_init() ) return false; memcpy( ret, src, dwLen ); bool bRet = CryptDecrypt( hKey, 0, true, 0, reinterpret_cast<BYTE*>(ret), &dwLen ); return bRet; }
使用例は、以下のとおり。Crypto自体はバイナリの配列を暗号化するためencryptの返却値はBYTEだ。
バッファサイズについては十分配慮する必要がある。例では手抜きをしている。
今回の例では、カプセル化でパスワードは初期化時に渡しているが、この辺のさじ加減は好み次第だろう。
void test() { TCHAR *src = T_"TESTWORD"; TCHAR *pass = T_"DEBUG2"; TMyCrypt crypt; if( !crypt.init( pass ) ) // crypt.init( pass, CALG_SHA1, CALG_RC4, 0x00800000 )の省略形 return; BYTE buf[100] = {0}; TCHAR ret[100] = {0}; DWORD dwLen; if( crypt.encrypt( buf, src, dwLen ) ) { //・・・ if( crypt.decrypt( ret, buf, dwLen ) ) { //・・・・ } } crypt.finalize(); }
コードでTCHARを用いているので、文字列がcharの場合でもwchar_tの場合でも同じように動作する。
今回の例で選択可能なハッシュ鍵生成アルゴリズムは、認証の不要なハッシュアルゴリズムだ。