我正在尝试使用 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 的倍数,这不会改变结果。
感谢您提供的任何帮助!