CryptDecrypt 函数失败并出现 C 中的 NTE_BAD_DATA

问题描述 投票:0回答:1

我正在尝试解密 .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;
}
c winapi cryptography
1个回答
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()
之后)。

通过这些更改,加密和解密对我有用。

© www.soinside.com 2019 - 2024. All rights reserved.