C++、C#、秘密鍵、公開鍵、RSA


RSAの鍵作成(C++)->暗号化(C#)->復号化(C++)の例

RSAの鍵作成(C++)

int _tmain(int argc, _TCHAR* argv[])
{
// RSA 秘密鍵と公開鍵を作成し、両方をファイル化

HCRYPTPROV hCryptprov;
BOOL bl = CryptAcquireContext(&hCryptprov, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0 );
ATLASSERT( bl );

HCRYPTKEY hKey;

bl = CryptGenKey(hCryptprov, CALG_RSA_KEYX, KEYLENGTH<<16 | CRYPT_EXPORTABLE, &hKey);
ATLASSERT( bl );

DWORD dwPrivateKeySize;
bl = CryptExportKey( hKey, 0, PRIVATEKEYBLOB,0, NULL, &dwPrivateKeySize); // サイズ取得
BYTE* privateKey = new BYTE[dwPrivateKeySize];
bl = CryptExportKey( hKey, 0, PRIVATEKEYBLOB,0, privateKey, &dwPrivateKeySize); // 596
ATLASSERT( bl );

DWORD dwPublicKeySize;
bl = CryptExportKey( hKey, 0, PUBLICKEYBLOB,0, NULL, &dwPublicKeySize); // サイズ取得
BYTE* publicKey = new BYTE[dwPublicKeySize];
bl = CryptExportKey( hKey, 0, PUBLICKEYBLOB,0, publicKey, &dwPublicKeySize); // 148
ATLASSERT( bl );

FILE* pf = fopen( "privatekey.bin", "wb" );
fwrite( privateKey, 1, dwPrivateKeySize, pf );
fclose(pf);

pf = fopen( "publickey.bin", "wb" );
fwrite( publicKey, 1, dwPublicKeySize, pf );
fclose(pf);


delete [] privateKey;
delete [] publicKey;

CryptDestroyKey( hKey );
CryptReleaseContext(hCryptprov, 0);

return 0;
}

暗号化(C#)

{
// RSA 1024bit
var rsa = new System.Security.Cryptography.RSACryptoServiceProvider();

// 公開鍵を受け取る
BinaryReader sr = new BinaryReader( File.OpenRead("publickey.bin"));
long len = sr.BaseStream.Length;
Byte [] blob = new Byte[len];
sr.Read( blob, 0, (int)len );
sr.Close();

// 公開鍵をインポート
rsa.ImportCspBlob( blob );

// 公開鍵で暗号化
byte[] data = rsa.Encrypt( Encoding.ASCII.GetBytes("password"), false ); // パスワードは英数字が普通なので、ASCIIエンコード

// ファイル化
BinaryWriter wr = new BinaryWriter( File.OpenWrite("encrypt.bin"));
wr.Write( data, 0, data.Length );
wr.Close();
}

復号化(C++)

BYTE* MyFileRead( LPCSTR fnm, DWORD* plen );
BYTE* ByteArraySwap( BYTE* buffer, int len );

int _tmain(int argc, _TCHAR* argv[])
{
HCRYPTPROV hCryptprov;
HCRYPTKEY hkey;

BOOL bl = CryptAcquireContext(&hCryptprov, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0 );
ATLASSERT( bl );

DWORD prlen,dlen;

// 秘密鍵
BYTE* privatekey = MyFileRead( "privatekey.bin" , &prlen);

// 暗号化されたデータ
BYTE* data = MyFileRead( "encrypt.bin", &dlen );

// 復号化のため、秘密鍵をインポート
bl = CryptImportKey( hCryptprov, privatekey, prlen, 0 ,0, &hkey );
ATLASSERT( bl );

BYTE* ctext = ByteArraySwap( data, dlen ); // to big endian

// 復号化
bl = ::CryptDecrypt( hkey, 0, TRUE,0, ctext, &dlen );
ATLASSERT( bl );

CStringA str((LPCSTR)ctext, dlen); // 元がEncoding.ASCII.GetBytesなのでそのままLPCSTRになる

ATLASSERT( str == "password" );

delete [] privatekey;
delete [] ctext;

CryptDestroyKey( hkey );
CryptReleaseContext(hCryptprov, 0);

return 0;
}

BYTE* MyFileRead( LPCSTR fnm, DWORD* plen )
{
FILE* pf = ::fopen( fnm, "rb" );
::fseek( pf, 0, SEEK_END );
DWORD len = ::ftell(pf);
::fseek( pf, 0, SEEK_SET );

BYTE* buf = new BYTE[len];
::fread( buf,1,len,pf);
fclose(pf);

*plen = len;

return buf;

}

static BYTE* ByteArraySwap( BYTE* buffer, int len )
{
BYTE* buffer2 = new BYTE[ len ];
for(int i = 0; i < len; i++)
buffer2[i] = buffer[len-i-1];

delete [] buffer;
return buffer2;
}