使用Windows CryptoAPI使用AES 256位密钥解密的简单代码有什么问题?

学习者X

我有一个使用AES-256密钥加密文件的小程序。用于加密文件的密钥是随机生成的。

加密程序如下所示:

  • 获取加密上下文- CryptAcquireContext
  • 使用以下命令生成AES-256密钥 CryptGenKey
  • 使用此密钥加密文件- CryptEncrypt
  • 释放Cryto上下文- CryptReleaseContext

加密的文件是一个小的test.txt文件,其中包含字符串:“ just a test”。因此,文件中的原始十六进制字节为:

6A 75 73 74 20 61 20 74 65 73 74

用于十六进制格式加密的AES-256密钥为:

3f10e23bb1a5dfd9c8ca06195e43043386a9ba4c63c35ac518f463ba768f001b

然后,加密文件test.enc将具有以下字节:

C8 B5 92 51 22 53 75 A1 34 80 EC AA 37 1C 6C BE 

题:

如何编写ac / c ++程序,以使用Windows CryptoAPI的CryptDecrypt功能使用十六进制AES-256密钥解密这些字节

我试过的

我已经编写了以下解密程序(这里要点的略微修改。)

#include <Windows.h>
#include <wincrypt.h>
#include <stdio.h>
#pragma comment(lib, "crypt32.lib")

#define BLOCK_LEN 128

HCRYPTPROV hCryptProv;

int wmain(int argc, wchar_t* argv[])
{
    wchar_t default_key[] = L"PxDiO7Gl39nIygYZXkMEM4apukxjw1rFGPRjunaPABs";
    wchar_t* key_str = default_key;
    size_t len = lstrlenW(key_str);



    if (!CryptAcquireContext(
        &hCryptProv,
        NULL,
        MS_ENH_RSA_AES_PROV,
        PROV_RSA_AES,
        NULL))
    {
        /*std::cout << "error acquiring context\n";
        std::cout << GetLastErrorAsString();*/
        exit(1);
    }

    HCRYPTKEY hKey;


    wchar_t* filename = argv[1];
    wchar_t* filename2 = argv[2];

    printf("Key: %S\n", key_str);
    printf("Key len: %#x\n", len);
    printf("Input File: %S\n", filename);
    printf("Output File: %S\n", filename2);
    printf("----\n");

    HANDLE hInpFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    if (hInpFile == INVALID_HANDLE_VALUE) {
        printf("Cannot open input file!\n");
        system("pause");
        return (-1);
    }
    printf("\nEncrypted file read.");

    HANDLE hOutFile = CreateFileW(filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hOutFile == INVALID_HANDLE_VALUE) {
        printf("Cannot open output file!\n");
        system("pause");
        return (-1);
    }
    printf("\nDecryption file created.");

    DWORD dwStatus = 0;
    BOOL bResult = FALSE;
    wchar_t info[] = L"Microsoft Enhanced RSA and AES Cryptographic Provider";

    /*BOOL CryptDeriveKey(
        HCRYPTPROV hProv,
        ALG_ID     Algid,
        HCRYPTHASH hBaseData,
        DWORD      dwFlags,
        HCRYPTKEY * phKey
    );*/

    HCRYPTHASH hHash;
    if (!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash)) {
        dwStatus = GetLastError();
        printf("CryptCreateHash failed: %x\n", dwStatus);
        CryptReleaseContext(hCryptProv, 0);
        system("pause");
        return dwStatus;
    }

    if (!CryptHashData(hHash, (BYTE*)key_str, len, 0)) {
        DWORD err = GetLastError();
        printf("CryptHashData Failed : %#x\n", err);
        system("pause");
        return (-1);
    }
    printf("[+] CryptHashData Success\n");

    if (!CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey)) {
        dwStatus = GetLastError();
        printf("CryptDeriveKey failed: %x\n", dwStatus);
        CryptReleaseContext(hCryptProv, 0);
        system("pause");
        return dwStatus;
    }
    printf("[+] CryptDeriveKey Success\n");


    const size_t chunk_size = BLOCK_LEN;
    BYTE chunk[chunk_size] = { 0 };
    DWORD out_len = 0;

    BOOL isFinal = FALSE;
    DWORD readTotalSize = 0;

    DWORD inputSize = GetFileSize(hInpFile, NULL);

    while (bResult = ReadFile(hInpFile, chunk, chunk_size, &out_len, NULL)) {
        if (0 == out_len) {
            break;
        }
        printf("\nFile read.");
        readTotalSize += out_len;
        if (readTotalSize == inputSize) {
            isFinal = TRUE;
            printf("\nFinal chunk set.\n");
        }

        printf("\n Now calling decryption routine...");
        if (!CryptDecrypt(hKey, NULL, isFinal, 0, chunk, &out_len)) {
            printf("[-] CryptDecrypt failed\n");
            break;
        }
        printf("CryptDecrypt succeeded.");

        DWORD written = 0;
        if (!WriteFile(hOutFile, chunk, out_len, &written, NULL)) {
            printf("writing failed!\n");
            break;
        }
        memset(chunk, 0, chunk_size);

    }
    CryptReleaseContext(hCryptProv, 0);
    CryptDestroyKey(hKey);
    CryptDestroyHash(hHash);

    CloseHandle(hInpFile);
    CloseHandle(hOutFile);
    printf("Finished. Processed %#x bytes.\n", readTotalSize);
    system("pause");
    return 0;
}

这只是告诉我CryptDecrypt失败了。因此,我猜测密钥没有以正确的格式指定。我不知道如何使用十六进制格式的AES-256密钥解密数据。该密钥当前base64在程序中以某种格式进行了硬编码,但是我猜这是不正确的。

我所做的另一件事是,我使用了CryptoTester工具来指定我具有的十六进制格式的AES密钥,并且它实际上能够成功解密该文件。而且,此在线解密工具还能够使用密钥来解密数据,如下所示因此,我知道我拥有正确的十六进制密钥以及所有内容,并且文件可以解密,但是如何在上面重写程序以正确解密文件?

请注意,此处使用或显示的所有键只是示例。

如何使用上面的AES-256密钥更正此程序以成功地解密数据?

斯蒂芬·巴德

简单演示程序

这是一个小型C程序,它使用您的密钥和随附的加密数据,并再次解密原始文本。我试图使其简约。

为了简单起见,它不从文件系统读取文件,而是将C程序中的数据定义为十六进制字符串。

结果

运行程序时,以下输出将输出到控制台:

decrypted result: 'just a test'

C代码

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>

void error(const char* what) {
    fprintf(stderr, "%s failed with last error 0x%x\n", what, GetLastError());
    exit(1);
}

#define AES_KEY_SIZE 32
typedef struct {
    BLOBHEADER hdr;
    DWORD dwKeySize;
    BYTE rgbKeyData[AES_KEY_SIZE];
} AES256KEYBLOB;

BYTE *hex2byte(const char *hex) {
    int len = strlen(hex) / 2;
    BYTE* bytes = malloc(len);
    if (bytes == NULL) { 
        error("malloc");  
        return NULL; 
    }
    unsigned char val[2];

    for (int i = 0; i < len; i++) {
        sscanf_s(&hex[i * 2], "%2hhx", &val);
        bytes[i] = val[0];
    }
    return bytes;
}

int main() {
    BYTE *key = hex2byte("3F10E23BB1A5DFD9C8CA06195E43043386A9BA4C63C35AC518F463BA768F001B");

    AES256KEYBLOB aes256KeyBlob;
    aes256KeyBlob.hdr.bType = PLAINTEXTKEYBLOB;
    aes256KeyBlob.hdr.bVersion = CUR_BLOB_VERSION;
    aes256KeyBlob.hdr.reserved = 0;
    aes256KeyBlob.hdr.aiKeyAlg = CALG_AES_256;
    aes256KeyBlob.dwKeySize = AES_KEY_SIZE;
    memcpy(aes256KeyBlob.rgbKeyData, key, AES_KEY_SIZE);

    HCRYPTPROV hProv;
    if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
        error("CryptAcquireContext");
    }

    HCRYPTKEY hKey;
    if (!CryptImportKey(hProv, (BYTE*)& aes256KeyBlob, sizeof(AES256KEYBLOB), 0, CRYPT_EXPORTABLE, &hKey)) {
        CryptReleaseContext(hProv, 0);
        error("CryptImportKey");
    }

    const char *encodedHex = "C8B59251225375A13480ECAA371C6CBE";
    DWORD numBytes = strlen(encodedHex) / 2;
    BYTE *encoded = hex2byte(encodedHex);

    if (CryptDecrypt(hKey, 0, TRUE, 0, encoded, &numBytes)) {
        printf("decrypted result: '");
        for (DWORD i = 0; i < numBytes; i++) {
            printf("%c", encoded[i]);
        }
        printf("'\n");
    } else {
        CryptDestroyKey(hKey);
        CryptReleaseContext(hProv, 0);
        error("CryptDecrypt");
    }


    free(key);
    free(encoded);

    CryptDestroyKey(hKey); 
    CryptReleaseContext(hProv, 0);
    return 0;
}

微软文档

KEYBLOB结构记录在这里:https ://docs.microsoft.com/zh-cn/previous-versions/windows/desktop/legacy/jj650836(v%3Dvs.85

而在这里您将找到有关BLOBHEADER结构的信息:https ://docs.microsoft.com/zh-cn/windows/desktop/api/wincrypt/ns-wincrypt-publickeystruc

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章