I'm attempting to encrypt/decrypt a single buffer using the CryptoAPI.
I've been successful in encrypting/decrypting a key and
Importing/Exporting the key BLOB. I've also (only in the apparent sense)
been successful with the Encryption (only) of data.
The following code sucessfully Encrypts the data. On decryption, it successfully decrypts the data, but reports "NTE_BAD_DATA".
globals in header:
HCRYPTPROV cryptprov; HCRYPTKEY pubenckey; HCRYPTKEY cryptprivkey; LPVOID keystore;
Creating a session key:
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;Generating a key, exporting the blob, encrypting it with the session key, and writing to file:
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;Another application reads the file and imports the key:
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;Encryption of buffer (buffer pointer is passed in as a LONG and the
first twelve bytes are used for encrypted/unencrypted data lengths):
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;Decryption of data:
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;The last code block consistently returns -2146893819 (NTE_BAD_DATA). Upon inspection of the buffer, however, it is decrypted.
It is important to note, that I pass in buffers with data amounts that are multiples of 32, and that doesn't change the result.
Thanks for any help you may have!