サーバ上にパスワードを登録する時、サーバは秘密鍵と公開鍵を作成し公開鍵をネットを使ってクライアントへ送出する。
クライアントはパスワードをこの公開鍵を用いて暗号化し、サーバへ送る。
サーバは暗号化されたパスワードを秘密鍵で復号し、パスワードを安全に取得する。
公開鍵を盗み見しても、パスワードは解凍できない。(公開している鍵というより、覗かれても大丈夫な鍵の方が正しい表現と思う。)

この流れを作るためにに、C#秘密鍵と公開鍵を作成し、C++でパスワードを公開鍵で暗号化するサンプルを作成してみた。
暗号化されたパスワードは無事、C#上で復号化できていることを確認した。

このプログラムの難解な点は、なんだかよくわからいのByteArraySwap。ビッグエディアンとリトルエディアンの話にあるようだ。

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

#include "stdafx.h"
#include // crypt32.lib
#include // for BASE64

#pragma comment(lib, "crypt32.lib")

bool XmlLoad( CString uri, IXMLDOMDocument** pxml );
bool ParseXml( IXMLDOMDocument* xml, CStringA& Modulus, CStringA& Exponent );
BYTE* ByteArraySwap( BYTE* buffer, int len );
BYTE* Base64toBinaryWihSwap( CStringA key, int* plen );
CStringA Base64toString( BYTE* data, int dlen );
bool CreatePublicKeyBlob( BYTE* pModulus, int mlen, BYTE* pExponent, int elen, BYTE** ppBlob, DWORD* pcbKeyBlob );

#define OUT

                                                                                          • -

// C#
System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
string seckey = rsa.ToXmlString(true);
string publickey = rsa.ToXmlString(false);

                                                                                              • -

The publickey xml is under.


1wP1k52...............
AQAB

CStringA RSAEncryptPassword( CStringA Password, CString PublicKeyXml )
{
// 1.Create public key Blob from public key xml.-------------------

BYTE *pBlob;
DWORD cbKeyBlob;

CComPtr xml;
XmlLoad( PublicKeyXml, &xml );

CStringA Modulus; int mlen;
CStringA Exponent; int elen;

ParseXml( xml, OUT Modulus, OUT Exponent );

xml.Release();

BYTE* pModulus = Base64toBinaryWihSwap( Modulus, OUT &mlen );
BYTE* pExponent = Base64toBinaryWihSwap( Exponent, OUT &elen );

CreatePublicKeyBlob( pModulus, mlen, pExponent, elen, OUT &pBlob, OUT &cbKeyBlob );

delete pModulus;
delete
pExponent;


// 2.Encrypt passowrd. ------------------------------------------------

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

HCRYPTKEY hPublicKey;
bl = CryptImportKey( hCryptprov, pBlob, cbKeyBlob, 0, 0, &hPublicKey);
ATLASSERT( bl );

DWORD dwCalcLen = 0;
bl = CryptEncrypt( hPublicKey, 0,TRUE,0, NULL, &dwCalcLen,0 );
ATLASSERT( bl );

BYTE* pwdData = new BYTE[ dwCalcLen ];
ZeroMemory( pwdData, dwCalcLen );

DWORD dwTextLength = Password.GetLength();

ATLASSERT( dwTextLength < dwCalcLen );

CopyMemory( pwdData, (LPCSTR)Password, dwTextLength );

bl = CryptEncrypt( hPublicKey, 0,TRUE,0, pwdData, &dwTextLength, dwCalcLen );
ATLASSERT( bl );

BYTE* ctext = ByteArraySwap( pwdData, dwTextLength ); // big endian

CStringA en_pwd = Base64toString( ctext, dwTextLength );

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

delete pBlob;
delete
ctext;

return en_pwd;
}

static bool CreatePublicKeyBlob( BYTE* pModulus, int mlen, BYTE* pExponent, int elen, BYTE** ppBlob, DWORD* pcbKeyBlob )
{
DWORD dwExponent = 0;

for( int i = 0; i < elen; i++ )
CopyMemory( (LPBYTE)&dwExponent+i, &pExponent[i], 1);

ATLASSERT(dwExponent == 0x10001 ); // equat to AQAB

DWORD cbModulus = mlen;

DWORD& cbKeyBlob = *pcbKeyBlob;

cbKeyBlob = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + cbModulus;
BYTE *pBlob = new BYTE[cbKeyBlob];

PUBLICKEYSTRUC *pPublicKey = (PUBLICKEYSTRUC*)pBlob;
pPublicKey->bType = PUBLICKEYBLOB;
pPublicKey->bVersion = CUR_BLOB_VERSION;
pPublicKey->reserved = 0;
pPublicKey->aiKeyAlg = CALG_RSA_KEYX;

RSAPUBKEY *pRsaPubKey = (RSAPUBKEY*)(pBlob + sizeof(PUBLICKEYSTRUC));
pRsaPubKey->magic = 0x31415352; // RSA1: 0x31415352
pRsaPubKey->bitlen = cbModulus * 8;
pRsaPubKey->pubexp = dwExponent;

BYTE *pKey = (BYTE*)pRsaPubKey + sizeof(RSAPUBKEY);
CopyMemory( pKey, pModulus, cbModulus );


*ppBlob = pBlob;

return true;

}

bool ParseXml( IXMLDOMDocument* xml, CStringA& Modulus, CStringA& Exponent )
{
CComPtr el;
xml->get_documentElement( &el);
CComPtr nd;
el->selectSingleNode( CComBSTR(L"Modulus"), &nd);
CComBSTR key1;
nd->get_text(&key1);
nd.Release();

el->selectSingleNode( CComBSTR(L"Exponent"), &nd);
CComBSTR key2;
nd->get_text(&key2);

Modulus = key1;
Exponent = key2;

return true;
}
bool XmlLoad( CString uri, IXMLDOMDocument** pxml )
{
CLSID clsid;
CLSIDFromProgID( L"MSXML2.DOMDocument.6.0", &clsid );

if ( S_OK !=CoCreateInstance( clsid, NULL,CLSCTX_ALL,IID_IXMLDOMDocument,(void**)pxml ) )
return false;
(*pxml)->put_async(VARIANT_FALSE);
VARIANT_BOOL vbl;
if ( S_OK != (*pxml)->load( CComVariant(uri), &vbl ))
return false;

return true;
}


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

static BYTE* Base64toBinaryWihSwap( CStringA key, int* plen )
{
// The base64-encoded array is in big-endian order,
// CryptoAPI expects the number in little-endian order,

int& len = *plen;
len = ATL::Base64DecodeGetRequiredLength( key.GetLength());
BYTE* buffer = new BYTE[len];
ATL::Base64Decode( key, key.GetLength(), buffer, &len ); // You may use CryptStringToBinary function.
return ByteArraySwap( buffer, len );
}

CStringA Base64toString( BYTE* data, int dlen )
{
int len = ATL::Base64EncodeGetRequiredLength( dlen, ATL_BASE64_FLAG_NOCRLF );
CStringA r( (char)0, len );
ATL::Base64Encode( data, dlen, (LPSTR)(LPCSTR)r, &len, ATL_BASE64_FLAG_NOCRLF );
return r;
}