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