【问题标题】:Windows CAPI CryptDecrypt error key not workingWindows CAPI CryptDecrypt 错误密钥不起作用
【发布时间】:2022-01-09 14:36:18
【问题描述】:

我正在尝试从 openssl 生成的私钥解密数据。我已将公钥从 PEM 转换为 DER 格式,但是当我使用 CryptDecrypt 时,它会抛出错误key does not exist。我以前使用相同的方法加密数据和使用 openssl 解密,我也知道 openssl 和 wincrypto 的 Endianess 差异。如果有人能指出我哪里出错了,这是代码。

#include <Windows.h>
#include <wincrypt.h>

#include <stdio.h>

#pragma comment(lib, "Crypt32.lib")


char default_pub_key[] =
"-----BEGIN PUBLIC KEY-----"
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVTOXB/Ti8SFvP42Z1XFB6GQ+R"
"jnqs42XiTFRXWpsSTlSPMRHi8aXpf1KYzzKHMC+4hU3rrgdbOu8bl7FekDoy38No"
"PX8ACoEmRhdn8mXs+ftmIRCuEE44mtgWUme65A1nTyT8nRmAVF6roo/rry+Xkbe9"
"iC6vRBRbVzprmCv7jwIDAQAB"
"-----END PUBLIC KEY-----";

HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
DWORD dwKeySize = 0;

void SwapBytes(char* pv, size_t n) {
    char* p = pv;
    size_t lo, hi;
    for (lo = 0, hi = n - 1; hi > lo; lo++, hi--)
    {
        char tmp = p[lo];
        p[lo] = p[hi];
        p[hi] = tmp;
    }
}

int init_crypto()
{
    LPBYTE pbBuffer;
    DWORD dwKeyBlob, dw_pub_key_len = 0;
    unsigned int offset = 22; // 22 = 1024, 24 = 2048 and so on
    DWORD dwParamSize = sizeof(DWORD);
    CERT_PUBLIC_KEY_INFO* publicKeyInfo;

    
    CryptStringToBinaryA(default_pub_key, 0, CRYPT_STRING_ANY, NULL, &dw_pub_key_len, NULL, NULL);

    pbBuffer = (LPBYTE)GlobalAlloc(GPTR, dw_pub_key_len);
    CryptStringToBinaryA(default_pub_key, 0, CRYPT_STRING_ANY, pbBuffer, &dw_pub_key_len, NULL, NULL);

    dwKeyBlob = 0;
    CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, pbBuffer, dw_pub_key_len, 0, NULL, NULL, &dwKeyBlob);

    publicKeyInfo = (CERT_PUBLIC_KEY_INFO*)GlobalAlloc(GPTR, dwKeyBlob);
    CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, pbBuffer, dw_pub_key_len, 0, NULL, publicKeyInfo, &dwKeyBlob);
    


    CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);


    CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING, publicKeyInfo, &hKey);


    CryptGetKeyParam(hKey, KP_KEYLEN, (BYTE*)&dwKeySize, &dwParamSize, 0);


    char da[16];
    memset(da, 0, sizeof(da));
    wsprintfA(da, "%d", dwKeySize);
    MessageBoxA(NULL, da, NULL, MB_OK);

    dwKeySize /= 8;

    return 0;
}


int main(int argc, char** argv)
{
    
    // start rsa crypto key
    init_crypto();


    // Read encrypted data
    DWORD junk;
    HANDLE hEncFile = CreateFile(L"test_enc.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD EncFileSize = GetFileSize(hEncFile, 0);
    char* EncFileBuf = (char*)GlobalAlloc(GPTR, EncFileSize + 1);
    ReadFile(hEncFile, EncFileBuf, EncFileSize, &junk, NULL);
    CloseHandle(hEncFile);


    // convert for win32
    SwapBytes((char*)EncFileBuf, EncFileSize);

    CryptDecrypt(hKey, 0, TRUE, 0,(PBYTE)EncFileBuf, &EncFileSize);

    
    hEncFile = CreateFile(L"test_dec.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    WriteFile(hEncFile, EncFileBuf, EncFileSize, &junk, NULL);
    CloseHandle(hEncFile);
    

    GlobalFree(EncFileBuf);



    // Do proper cleanup

    return 0;
    

}

【问题讨论】:

  • 因为使用公钥你只能加密数据。要解密,您需要完整的密钥-公共+私有
  • 更好地使用 CNG。
  • 是的,更好。但结果是一样的

标签: c++ c windows cryptography cryptoapi


【解决方案1】:

CryptDecrypt

[in] hKey

用于解密的密钥句柄。应用程序通过使用CryptGenKeyCryptImportKey 函数获取此句柄。

您将错误的 hKey 传递给 CryptDecrypt。在 CryptImportPublicKeyInfo 之后使用 CryptImportKey 获取预期的 hKey 并将其传递给 CryptDecrypt。

【讨论】:

  • 不,这是错误的。使用CryptImportPublicKeyInfo 可以获取密钥
  • @RbMm 怎么了? CryptDecrypt 需要一个私钥句柄,CryptImportPublicKeyInfo 返回一个对 CryptDecrypt 无效的公钥句柄。可以使用传递给 CryptImportKey 的公钥句柄从存储中检索私钥。
  • 是的,CryptDecrypt 需要一个私钥句柄。我也在有问题的评论中这么说。 CryptImportPublicKeyInfo 返回对 CryptDecrypt 无效的公钥句柄 - 也是如此。但你没有从一开始就解释这一点。
  • 我正在尝试建立端到端加密通信,而不与另一端共享私钥,这是使用公钥而不使用 openssl 解密数据的任何可靠方法
猜你喜欢
  • 2022-01-28
  • 1970-01-01
  • 1970-01-01
  • 2018-03-18
  • 2016-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多