CryptoAPI を使用して単一のバッファを暗号化/復号化しようとしています。
キーの暗号化/復号化と、キー BLOB のインポート/エクスポートに成功しました。また、データの暗号化 (のみ) にも (見かけ上の意味でのみ) 成功しています。
次のコードは、データを正常に暗号化します。復号化では、データを正常に復号化しますが、「NTE_BAD_DATA」を報告します。
ヘッダーのグローバル:
HCRYPTPROV cryptprov;
HCRYPTKEY pubenckey;
HCRYPTKEY cryptprivkey;
LPVOID keystore;
セッション キーの作成:
DWORD ret = 0;
ZeroMemory(&cryptprov,sizeof(cryptprov));
CString cwinver("Windows 7";);
string winver = cwinver.GetBuffer();
wstring provname;
wstring contname = L"Container";
if (winver.compare("Windows XP") == 0) { provname.assign(L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"); } else { provname.assign(L"Microsoft Enhanced RSA and AES Cryptographic Provider"); }
ret = CryptAcquireContextW(&cryptprov,contname.c_str(),provname.c_str(),PROV_RSA_AES,CRYPT_SILENT);
if (ret == FALSE) { ret = CryptAcquireContextW(&cryptprov,contname.c_str(),provname.c_str(),PROV_RSA_AES,CRYPT_SILENT|CRYPT_NEWKEYSET); }
if (ret == FALSE) {
return -1;
}
HCRYPTHASH hashobj;
CStringW cpass("testpass");
wstring pass = cpass.GetBuffer();
ret = CryptCreateHash(cryptprov,CALG_MD5,NULL,NULL,&hashobj);
if (ret == FALSE) {
return -1;
}
ret = CryptHashData(hashobj,(LPBYTE)pass.c_str(),pass.size(),0);
if (ret == FALSE) {
return -1;
}
ret = CryptDeriveKey(cryptprov,CALG_AES_256,hashobj,0x01000000|CRYPT_EXPORTABLE,&cryptprivkey);
if (ret == FALSE) {
return -1;
}
CryptDestroyHash(hashobj);
return ret;
キーを生成し、BLOB をエクスポートし、セッション キーで暗号化し、ファイルに書き込みます。
DWORD ret = 0;
int buflen;
ret = CryptGenKey(cryptprov,CALG_AES_256,0x01000000|CRYPT_EXPORTABLE,&pubenckey);
if (ret == FALSE) {
return -1;
}
DWORD count;
ret = CryptExportKey(pubenckey,0,PLAINTEXTKEYBLOB,0,NULL,&count);
if (ret == FALSE) {
return -1;
}
buflen = count + 100;
keystore = VirtualAlloc(NULL,buflen,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
ret = CryptExportKey(pubenckey,0,PLAINTEXTKEYBLOB,0,(BYTE *)keystore,&count);
if (ret == FALSE) {
return -1;
}
DWORD origkeyblocksize = count;
ret = CryptEncrypt(cryptprivkey,NULL,TRUE,0,NULL,&count,buflen);
if (ret == FALSE) {
return -1;
}
ret = CryptEncrypt(cryptprivkey,NULL,TRUE,0,(BYTE *)keystore,&count,buflen);
if (ret == FALSE) {
return -1;
}
memcpy((void *)((LONG)keystore+count),(void *)&origkeyblocksize,4);
string filen = "C:\\testenc.enc";
if (filen.compare("") != 0) {
HANDLE fileh = CreateFile(filen.c_str(),GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (fileh != INVALID_HANDLE_VALUE) {
ret = WriteFile(fileh, keystore, count+4, &count, NULL);
} else { ret = -1; }
CloseHandle(fileh);
} else { ret = -1; }
if (ret != -1 && ret != FALSE) { ret = (LONG)keystore; }
return ret;
別のアプリケーションがファイルを読み取り、キーをインポートします。
DWORD ret = 0;
DWORD datalen;
DWORD bufsize = 0;
DWORD origkeysize = 0;
string filen = "c:\\testenc.enc";
if (filen.compare("") != 0) {
HANDLE fileh = CreateFile(filen.c_str(),GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (fileh != INVALID_HANDLE_VALUE) {
DWORD fsize = GetFileSize(fileh,0);
bufsize = fsize-4;
keystore = VirtualAlloc(NULL,bufsize,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
ret = ReadFile(fileh, keystore, fsize-4, &datalen, NULL);
ret = ReadFile(fileh, &origkeysize, 4, &datalen, NULL);
CloseHandle(fileh);
if (ret == FALSE) { ret = -1; }
} else { ret = -1; }
} else { ret = -1; }
if (ret == FALSE || ret == -1) {
return -1;
}
datalen = bufsize;
ret = CryptDecrypt(cryptprivkey,NULL,TRUE,0,(BYTE *)keystore,&datalen);
if (ret == FALSE) {
return -1;
}
ret = CryptImportKey(cryptprov,(BYTE *)keystore,origkeysize,0,0,&pubenckey);
if (ret == FALSE) { ret = -1; } else { ret = (LONG)keystore; }
return ret;
バッファの暗号化 (バッファ ポインタは LONG として渡され、最初の 12 バイトは暗号化/非暗号化データ長に使用されます):
DWORD ret = 0;
DWORD buflen;
DWORD count;
memcpy((void *)&count,(void *)((LONG)passedbufferptr),4);
count-=12;
buflen = count + 32;
ret = CryptEncrypt(pubenckey,NULL,TRUE,0,NULL,&count,buflen);
if (ret == FALSE) {
return -1;
}
ret = CryptEncrypt(pubenckey,NULL,TRUE,0,(BYTE *)((LONG)passedbufferptr+12),&count,buflen);
if (ret == FALSE) {
return -1;
}
memcpy((void *)((LONG)passedbufferptr+8),(void *)&count,4);
return ret;
データの復号化:
DWORD ret = 0;
DWORD count;
memcpy((void *)&count,(void *)((LONG)passedbufferptr+8),4);
ret = CryptDecrypt(pubenckey,NULL,TRUE,0,(BYTE *)((LONG)passedbufferptr+12),&count);
if (ret == FALSE) {
return GetLastError();
}
return ret;
最後のコード ブロックは一貫して -2146893819 (NTE_BAD_DATA) を返します。ただし、バッファを検査すると、復号化されます。
32 の倍数のデータ量のバッファーを渡しますが、結果は変わらないことに注意してください。
ご協力いただきありがとうございます。