前のBinaryクラスを使用して文字列(unicode)とバイナリデータ(ansi文字列を含む)のややこしいやり取りを極限まで簡素化してみた。



// utf8とunicodeの変換
Binary utf8( std::wstring& s );
std::wstring utf8( const Binary& b );

// バイナリーデータのbase64変換
Binary base64( std::wstring& s );
std::wstring base64( const Binary& b );

// バイナリのハッシュ関数, typ is 0:md5, 1:sha1, 2:sha2
Binary hash( const Binary& b, int typ );

// ハッシュ関数結果の文字列化
std::wstring hex( const Binary& b );

// 共通キーによる暗号、復号
bool aes256( bool IsEncrypt, const Binary& password, const Binary& src, Binary& dst );

// ファイルへ書き出し、読み込み
bool BinaryRead( LPCWSTR filename, Binary& b );
bool BinaryWrite( LPCWSTR filename, Binary& b );




Binary utf8( std::wstring& s )
{
int cchMultiByte = ::WideCharToMultiByte(CP_UTF8, 0, s.c_str(),s.length(), NULL, 0, NULL, NULL);
Binary r(0,cchMultiByte);
int result = ::WideCharToMultiByte(CP_UTF8, 0, s.c_str(), s.length(), (LPSTR)r.get(), cchMultiByte, NULL, NULL);
_ASSERT( result == cchMultiByte );

return r;
}
std::wstring utf8( const Binary& b )
{
std::wstring r;
int charcnt = ::MultiByteToWideChar(CP_UTF8, 0, (LPSTR)b.get(), b.length(), NULL, 0);
r.resize( charcnt );
int result = ::MultiByteToWideChar(CP_UTF8, 0, (LPSTR)b.get(), b.length(), (LPWSTR)r.c_str(), charcnt);
_ASSERT( result == charcnt );
return r;
}

Binary base64( std::wstring& s )
{
DWORD len;
int srclen = s.length();

BOOL bl = CryptStringToBinary(s.c_str(), srclen,CRYPT_STRING_BASE64, NULL, &len, NULL, NULL);
_ASSERT(bl);
Binary ret(0,len);
bl = CryptStringToBinary(s.c_str(), srclen,CRYPT_STRING_BASE64, ret.get(), &len, NULL, NULL);

_ASSERT(bl);

return ret;
}
std::wstring base64( const Binary& b )
{
std::wstring r;

DWORD len;

BOOL bl = CryptBinaryToString((const BYTE*)b.get(), b.length(),CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &len );
_ASSERT(bl);
r.resize(len);
bl = CryptBinaryToString((const BYTE*)b.get(), b.length(),CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, (LPWSTR)r.c_str(), &len );
_ASSERT(bl);
return r;
}

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


Binary hash( const Binary& b, int typ )
{
Binary ret;
HCRYPTPROV hprov;

ALG_ID hash_type[] = { CALG_MD5,CALG_SHA1,CALG_SHA_256 };
DWORD len[] = { 16,20,32 };

_ASSERT(0 < b.length());
_ASSERT(typ==0|| typ==1|| typ==2);

if ( CryptAcquireContext(&hprov, NULL, MS_ENH_RSA_AES_PROV_W, PROV_RSA_AES, CRYPT_VERIFYCONTEXT ))
{
HCRYPTHASH hHash;
if ( CryptCreateHash(hprov, hash_type[typ],0,0,&hHash))
{
if ( CryptHashData(hHash,(BYTE*)b.get(), b.length(),0))
{
DWORD dwHashLen=len[typ];
Binary r(0,dwHashLen);
if ( CryptGetHashParam(hHash,HP_HASHVAL,r.get(),&dwHashLen,0))
{
ret = r;
}
}
CryptDestroyHash(hHash);
}
CryptReleaseContext(hprov, 0);
}
return ret;
}


std::wstring hex( const Binary& b )
{
_ASSERT(b.length());

DWORD len=0;
CryptBinaryToString((const BYTE*)b.get(), b.length(),CRYPT_STRING_HEXRAW|CRYPT_STRING_NOCRLF, NULL, &len );
std::wstring r1;
r1.resize(len);
CryptBinaryToString((const BYTE*)b.get(), b.length(),CRYPT_STRING_HEXRAW|CRYPT_STRING_NOCRLF, (LPWSTR)r1.c_str(), &len );
return r1;
}

bool aes256( bool IsEncrypt, const Binary& pwd, const Binary& src, Binary& dst )
{
bool ret = false;
HCRYPTPROV hProv;

_ASSERT( pwd.length() == 32 ); // 32:AES256 , 16:AES128

struct AesKeyBlob
{
BLOBHEADER hdr;
DWORD keySize;
BYTE bytes[32];
};

AesKeyBlob blob;
memset( &blob, 0, sizeof(blob));
blob.hdr.bType = PLAINTEXTKEYBLOB;
blob.hdr.bVersion = CUR_BLOB_VERSION;
blob.hdr.aiKeyAlg = CALG_AES_256;
blob.keySize = pwd.length();
memcpy(blob.bytes, pwd.get(), pwd.length());


if ( CryptAcquireContext(&hProv, NULL, MS_ENH_RSA_AES_PROV_W, PROV_RSA_AES, CRYPT_VERIFYCONTEXT ))
{
HCRYPTHASH hHash;
HCRYPTKEY hKey;

if ( CryptCreateHash(hProv,CALG_SHA_256,0,0,&hHash ))
{
if (CryptHashData(hHash, pwd.get(),pwd.length(),0 ))
{
if (CryptImportKey(hProv, (BYTE*)&blob, sizeof(AesKeyBlob), NULL, 0, &hKey))
{
DWORD mode = CRYPT_MODE_CBC; // 暗号モード
DWORD padding_mode = PKCS5_PADDING; // パディングモード

BOOL bl = CryptSetKeyParam(hKey, KP_PADDING, (BYTE*)&padding_mode, 0);
_ASSERT(bl);
bl = CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&mode, 0);
_ASSERT(bl);


// IV
BYTE iv[ENCRYPT_BLOCK_SIZE] = {0};
memcpy( iv, pwd.get(), min(pwd.length(), ENCRYPT_BLOCK_SIZE) );
bl = CryptSetKeyParam( hKey, KP_IV, iv, 0 );
_ASSERT(bl);

DWORD dwLen = src.length();

if ( IsEncrypt )
{
DWORD dwNewLen = ((dwLen-1)/ENCRYPT_BLOCK_SIZE + 1) * ENCRYPT_BLOCK_SIZE;
Binary xdst(0,dwNewLen);
memcpy( xdst.get(), src.get(), dwLen );
if (CryptEncrypt(hKey,0,TRUE,0, xdst.get() ,&dwLen, dwNewLen ))
{
dst = xdst;
ret = true;
}
}
else
{
Binary x = src.clone();
if (CryptDecrypt(hKey,0,TRUE,0, x.get(),&dwLen))
{
dst = x.shrink(dwLen);
ret = true;
}
}
CryptDestroyKey(hKey);
}
CryptDestroyHash(hHash);
}
CryptReleaseContext(hProv, 0);
}
}
return ret;
}



bool BinaryRead( LPCWSTR filename, Binary& b )
{
bool ret = false;
HANDLE pf = CreateFile( filename, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL );
if ( INVALID_HANDLE_VALUE != pf )
{
DWORD len = GetFileSize( pf, NULL );
DWORD lx=0;

Binary x(0,len);
if (::ReadFile( pf, x.get(), len, &lx,0) && lx > 0 )
{
b = x;
ret = true;
}
CloseHandle(pf);
}
return ret;
}

bool BinaryWrite( LPCWSTR filename, const Binary& b )
{
bool ret = false;
HANDLE pf = CreateFile( filename, GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL );
if ( INVALID_HANDLE_VALUE != pf )
{
DWORD len = b.length();
DWORD lx=0;

if (::WriteFile( pf, b.get(), len, &lx,0) && lx > 0 )
{
ret = true;
}
CloseHandle(pf);
}
return ret;
}