我正在尝试解密 .png 文件,但由于某些原因 CryptDecrypt 返回错误数据错误。 我是 C 语言和密码学的新手,所以如果有人能告诉我为什么会发生这种情况以及如何解决它,那就太棒了。 我还使用了 CryptEncrypt 函数来加密图像,效果很好。
这是来自微软文档的 NTE_BAD_DATA 错误的解密:
要解密的数据无效。例如,当使用分组密码且 Final 标志为 FALSE 时,pdwDataLen 指定的值必须是分组大小的倍数。当发现padding无效时也会返回这个错误。
CryptDecrypt 函数文档的链接:
https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdecrypt
这是完整代码:
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#define BUFFER_SIZE 1024
void displayErrorMessage(DWORD errorCode) {
LPSTR messageBuffer = NULL;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&messageBuffer,
0,
NULL);
if (messageBuffer != NULL) {
printf("Error: %s\n", messageBuffer);
LocalFree(messageBuffer);
}
else {
printf("Error: Unable to get error message for code %d\n", errorCode);
}
}
void decryptFile(const char* filePath, const char* password) {
HANDLE hFile = CreateFileA(filePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Error opening file \n");
return;
}
printf("[+] Succesfully opened the file\n");
HCRYPTPROV hCryptProv;
if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
printf("Error acquiring crypto context\n");
CloseHandle(hFile);
return;
}
printf("[+] Succesfully acquired crypto context\n");
HCRYPTHASH hHash;
if (!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash)) {
printf("Error creating hash\n");
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
printf("[+] Succesfully created hash: %d\n", hHash);
if (!CryptHashData(hHash, (const BYTE*)password, strlen(password), 0)) {
printf("Error hashing data\n");
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
printf("[+] Succesfully hashed the key: %s\n", password);
HCRYPTKEY hKey;
if (!CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey)) {
printf("Error deriving key\n");
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
printf("[+] Succesfully derived AES key: %s\n", hKey);
DWORD dwFileSize = GetFileSize(hFile, NULL);
BYTE* pBuffer = (BYTE*)malloc(dwFileSize);
DWORD dwBytesRead = 0;
if (!ReadFile(hFile, pBuffer, dwFileSize, &dwBytesRead, NULL)) {
printf("Error reading file\n");
free(pBuffer);
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
printf("[+] Succesfully saved encrypted file to a buffer: %s\n", pBuffer);
if (!CryptDecrypt(hKey, 0, TRUE, 0, pBuffer, &dwBytesRead)) {
printf("Error Decrypting data \n");
displayErrorMessage(GetLastError());
free(pBuffer);
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
DWORD dwBytesWritten = 0;
if (!WriteFile(hFile, pBuffer, dwBytesRead, &dwBytesWritten, NULL)) {
printf("Error writing decrypted data to file\n");
}
else {
printf("File decrypted successfully\n");
}
free(pBuffer);
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
}
int main() {
const char* filePath = "C:/Users/mjank/Desktop/a.png";
const char* password = "mysecretkey";
decryptFile(filePath, password);
return 0;
}
正如下面的人建议的,这是加密代码:
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#define BUFFER_SIZE 1024
void encryptFile(const char* filePath, const char* password) {
HANDLE hFile = CreateFileA(filePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Error opening file %d\n", GetLastError());
return;
}
HCRYPTPROV hCryptProv;
if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
printf("Error acquiring crypto context\n");
CloseHandle(hFile);
return;
}
HCRYPTHASH hHash;
if (!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash)) {
printf("Error creating hash\n");
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
if (!CryptHashData(hHash, (const BYTE*)password, strlen(password), 0)) {
printf("Error hashing data\n");
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
HCRYPTKEY hKey;
if (!CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey)) {
printf("Error deriving key\n");
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
DWORD dwFileSize = GetFileSize(hFile, NULL);
BYTE* pBuffer = (BYTE*)malloc(dwFileSize);
DWORD dwBytesRead = 0;
if (!ReadFile(hFile, pBuffer, dwFileSize, &dwBytesRead, NULL)) {
printf("Error reading file\n");
free(pBuffer);
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
printf("[+] Succesfully saved plaintext file to a buffer: %s\n", pBuffer);
DWORD dwBlockLen = 0;
if (!CryptEncrypt(hKey, NULL, TRUE, 0, pBuffer, &dwBlockLen, dwFileSize)) {
printf("Error encrypting data %d\n", GetLastError());
free(pBuffer);
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
return;
}
printf("[+] Succesfully encrypted the buffer: %s\n", pBuffer);
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
DWORD dwBytesWritten = 0;
if (!WriteFile(hFile, pBuffer, dwBytesRead, &dwBytesWritten, NULL)) {
printf("Error writing encrypted data to file\n");
}
else {
printf("File encrypted successfully\n");
}
free(pBuffer);
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
CloseHandle(hFile);
}
int main() {
const char* filePath = "C:/Users/mjank/Desktop/a.png";
const char* key = "mysecretkey";
encryptFile(filePath, key);
return 0;
}
您的加密代码有错误:
CryptEncrypt()
中指定的明文大小不正确(参见参数pdwDataLen
)。dwBufLen
)。当前代码使用明文的大小作为缓冲区大小,因此隐含地假设密文与明文具有相同的大小。然而,这是不正确的,因为由于填充,密文比明文更大。因此,在分配缓冲区之前必须先确定密文的大小(参见参数pbData
)。一个可能的修复(为了简单起见,没有异常处理和内存释放):
...
DWORD dwFileSize = GetFileSize(hFile, NULL);
DWORD dwBytesCt = dwFileSize;
CryptEncrypt(hKey, NULL, TRUE, 0, NULL, &dwBytesCt, dwFileSize); // Fix 1: determine size of ciphertext (dwBytesCt)
BYTE* pBuffer = (BYTE*)malloc(dwBytesCt); // Fix 2: allocate buffer of sufficient size for plaintext AND ciphertext
DWORD dwBytesRead = 0;
ReadFile(hFile, pBuffer, dwFileSize, &dwBytesRead, NULL);
CryptEncrypt(hKey, NULL, TRUE, 0, pBuffer, &dwBytesRead, dwBytesCt); // FIX 3: pass size of plaintext (dwBytesRead) and size of buffer (dwBytesCt)
...
解密时,正如评论中已经提到的,必须删除填充,例如通过致电
SetEndOfFile()
(在 WriteFile()
之后)。
通过这些更改,加密和解密对我有用。