Win32API の Cryptography Functions を利用
コード
// EncryptDecryptCR4.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 // #include "stdafx.h" #pragma comment( lib, "Crypt32.lib" ) // CryptBinaryToStringA(), CryptStringToBinaryA() #include <windows.h> #include <wincrypt.h> #include <stdlib.h> // malloc() #include <assert.h> #include <conio.h> // _getch() #define MY_ENCRYPT_ALGORITHM CALG_RC4 #define MY_ENCRYPT_KEYLENGTH 128 // 暗号化/復号化 の後処理 static void PostCryptString( HCRYPTPROV* phCryptProv, HCRYPTKEY* phCryptKey ) { if( *phCryptKey ) { CryptDestroyKey( *phCryptKey ); *phCryptKey = NULL; } if( *phCryptProv ) { CryptReleaseContext( *phCryptProv, 0 ); *phCryptProv = NULL; } } // 暗号化/復号化 の前処理 static bool PreCryptString( const char* pszKey, HCRYPTPROV* phCryptProv, HCRYPTKEY* phCryptKey ) { // アウトプットの初期化 *phCryptProv = NULL; *phCryptKey = NULL; // インプットのチェック if( NULL == pszKey ) { return false; } DWORD dwSizeKey = (DWORD)( strlen( pszKey ) * sizeof( char ) ); if( 0 == dwSizeKey ) { return false; } // 暗号化プロバイダの取得 // 暗号化プロバイダとして、「Microsoft Enhanced RSA and AES Cryptographic Provider」を指定 // 暗号化プロバイダとして、「PROV_RSA_AES」を指定 long errorcode = CryptAcquireContext(phCryptProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0); if (!errorcode && GetLastError() == NTE_BAD_KEYSET) { // キーコンテナが存在しないのでCRYPT_NEWKEYSETフラグを利用して再呼び出し(https://docs.microsoft.com/ja-jp/windows/desktop/api/wincrypt/nf-wincrypt-cryptacquirecontexta) errorcode = CryptAcquireContext(phCryptProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET); } if (!errorcode) { CString mess; mess.Format(_T("errorcode = %d"), GetLastError()); AfxMessageBox(mess); goto LABEL_ERROR; } // ハッシュオブジェクトの作成 HCRYPTHASH hCryptHash = NULL; if( !CryptCreateHash( *phCryptProv, CALG_MD5, 0, 0, &hCryptHash ) ) { goto LABEL_ERROR; } // ハッシュオブジェクトに、ハッシュ値を求める元となるデータの追加 if( !CryptHashData( hCryptHash, (BYTE*)pszKey, dwSizeKey, 0 ) ) { goto LABEL_ERROR; } // ハッシュオブジェクトから暗号キーの取得 // 第4引数は、下位16ビットをゼロにし、上位16ビットでキーのビット数を指定する。 if( !CryptDeriveKey( *phCryptProv, MY_ENCRYPT_ALGORITHM, hCryptHash, MY_ENCRYPT_KEYLENGTH << 16, phCryptKey ) ) { goto LABEL_ERROR; } if( hCryptHash ) { CryptDestroyHash( hCryptHash ); } return true; LABEL_ERROR: if( hCryptHash ) { CryptDestroyHash( hCryptHash ); } PostCryptString( phCryptProv, phCryptKey ); return false; } // 文字列の暗号化 bool EncryptString( const char* pszSource, const char* pszKey, BYTE** ppbyteDest, DWORD* pdwSizeDest ) { // アウトプットの初期化 *ppbyteDest = NULL; *pdwSizeDest = 0; // インプットのチェック if( NULL == pszSource || NULL == pszKey ) { return false; } // 変数 HCRYPTPROV hCryptProv = NULL; HCRYPTKEY hCryptKey = NULL; // 暗号化/復号化 の前処理 if( !PreCryptString( pszKey, &hCryptProv, &hCryptKey ) ) { return false; } // バッファー確保 DWORD dwSizeSource = (DWORD)( strlen( pszSource ) * sizeof( char ) ); if( 0 == dwSizeSource ) { goto LABEL_ERROR; } DWORD dwSizeBuffer = dwSizeSource + 100; // バッファーサイズはソースよりも多少(16以上)多く領域を確保する。 BYTE* pbyteBuffer = (BYTE*)malloc( dwSizeBuffer ); memset( pbyteBuffer, 0x00, dwSizeBuffer ); // ゼロ埋め。 memcpy( pbyteBuffer, pszSource, dwSizeSource ); // 暗号化する文字列のバイト配列化 // 暗号化 DWORD dwSize = dwSizeSource; if( !CryptEncrypt( hCryptKey, 0, TRUE, 0, pbyteBuffer, &dwSize, dwSizeBuffer ) ) { goto LABEL_ERROR; } // アウトプットに代入 *ppbyteDest = pbyteBuffer; *pdwSizeDest = dwSize; // dwSizeは、CryptEncrypt()で、暗号化結果データサイズになっている。 PostCryptString( &hCryptProv, &hCryptKey ); return true; LABEL_ERROR: if( pbyteBuffer ) { free( pbyteBuffer ); } PostCryptString( &hCryptProv, &hCryptKey ); return false; } // 文字列の復号化 bool DecryptString( const BYTE* pbyteSource, const DWORD dwSizeSource, const char* pszKey, char** ppszDest ) { // アウトプットの初期化 *ppszDest = NULL; // インプットのチェック if( NULL == pbyteSource || NULL == pszKey ) { return false; } // 変数 HCRYPTPROV hCryptProv = NULL; HCRYPTKEY hCryptKey = NULL; // 暗号化/復号化 の前処理 if( !PreCryptString( pszKey, &hCryptProv, &hCryptKey ) ) { return false; } // バッファー確保 if( 0 == dwSizeSource ) { goto LABEL_ERROR; } DWORD dwSizeBuffer = dwSizeSource + 100; // バッファーサイズはソースよりも多少(16以上)多く領域を確保する。 char* pszBuffer = (char*)malloc( dwSizeBuffer ); memset( pszBuffer, 0x00, dwSizeBuffer ); // ゼロ埋め。 memcpy( pszBuffer, pbyteSource, dwSizeSource ); // 復号化 DWORD dwSize = dwSizeSource; if( !CryptDecrypt( hCryptKey, 0, TRUE, 0, (BYTE*)pszBuffer, &dwSize ) ) { goto LABEL_ERROR; } // 文字列の終端に「\0」を付加 pszBuffer[dwSize / sizeof( char )] = '\0'; // dwSizeは、CryptEncrypt()で、復号化結果データサイズになっている。 // アウトプットに代入 *ppszDest = pszBuffer; PostCryptString( &hCryptProv, &hCryptKey ); return true; LABEL_ERROR: if( pszBuffer ) { free( pszBuffer ); } PostCryptString( &hCryptProv, &hCryptKey ); return false; } // バイト配列を16進数文字列に変換 char* ByteArray2HexString( BYTE* pbyteSource, DWORD dwSizeSource ) { DWORD dwSizeBuffer = 0; CryptBinaryToStringA( pbyteSource, dwSizeSource, CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF, NULL, &dwSizeBuffer ); char* pszString = (char*)malloc( dwSizeBuffer ); // 終端文字列分多く確保 CryptBinaryToStringA( pbyteSource, dwSizeSource, CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF, pszString, &dwSizeBuffer ); return pszString; } // 16進数文字列をバイト配列に変換 void HexString2ByteArray( char* pszHexString, BYTE** ppbyteDest, DWORD* pdwSizeDest ) { DWORD dwSizeBuffer = 0; CryptStringToBinaryA( pszHexString, strlen( pszHexString ), CRYPT_STRING_HEXRAW, NULL, &dwSizeBuffer, 0, 0 ); BYTE* pbyteBuffer = (BYTE*)malloc( dwSizeBuffer ); CryptStringToBinaryA( pszHexString, strlen( pszHexString ), CRYPT_STRING_HEXRAW, pbyteBuffer, &dwSizeBuffer, 0, 0 ); *ppbyteDest = pbyteBuffer; *pdwSizeDest = dwSizeBuffer; } int main() { // 変数 char szString[] = "abcdあいうえアイウエ亜異迂絵↑↓→←㊤㊦㊨㊧"; char szKey[] = "hiramine.com"; BYTE* pbyteEncrypted = NULL; DWORD dwSizeEncrypted = 0; char* pszDecrypted = NULL; printf( "暗号化前文字列 : %s\n", szString ); // 文字列の暗号化 if( !EncryptString( szString, szKey, &pbyteEncrypted, &dwSizeEncrypted ) ) { assert( !"文字列の暗号化に失敗" ); return -1; } assert( pbyteEncrypted ); // バイト配列を16進数文字列に変換 char* pszEncrypted = ByteArray2HexString( pbyteEncrypted, dwSizeEncrypted ); printf( "暗号化後文字列 : %s\n", pszEncrypted ); // 16進数文字列をバイト配列に変換 BYTE* pbyteEncrypted2 = NULL; DWORD dwSizeEncrypted2 = 0; HexString2ByteArray( pszEncrypted, &pbyteEncrypted2, &dwSizeEncrypted2 ); // 暗号化されたデータの復号化 if( !DecryptString( pbyteEncrypted2, dwSizeEncrypted2, szKey, &pszDecrypted ) ) { free( pbyteEncrypted ); assert( !"暗号化されたデータの復号化に失敗" ); return -1; } assert( pszDecrypted ); free( pbyteEncrypted ); free( pszEncrypted ); free( pbyteEncrypted2 ); printf( "復号化後文字列 : %s\n", pszDecrypted ); if( 0 == strcmp( szString, pszDecrypted ) ) { printf( "暗号化前文字列と復号化後文字列は、一致!\n" ); } else { printf( "暗号化前文字列と復号化後文字列は、不一致!\n" ); } free( pszDecrypted ); _getch(); return 0; }