c++ - 使用 Windows Crypto API 和 C++ 的 PKCS #7 encryptedDigest 解密和验证

标签 c++ windows encryption cryptoapi

简介

我正在尝试执行以下操作来检查证书的 SignedData.SignerInfo.encryptedDigest:

1) Read
SignedData.contentInfo +
SignedData.SignerInfo.authenticatedAttributes

2) Calculate Hash of contentInfo and authenticatedAttributes
using SignedData.digestAlgorithm

3) Read SignerInfo.encryptedDigest and certificate's PUBLIC key

4) Decrypt encryptedDigest using the acquired key
(it is the problem, and the question is about this)

5) Compare decryptedDigest's hash
with hash of contentInfo and authenticatedAttributes (STEP 2)

问题

我尝试了不同的方法来使用 Windows Crypto API 使用证书的 public keyencryptedDigest 进行 RSA 解密,但每种方法都会出错.

尝试#1 解决

尝试使用CryptDecrypt
结果:错误2148073485( key 不存在)
请查看下面的失败代码(示例 #1)。
简单搜索发现,API 不允许使用公钥 进行解密
如果错了,请提示我该怎么做。

尝试 #2 解决

尝试使用CryptVerifySignature
结果:错误87(参数不正确)
请查看下面的失败代码(示例 #2)。
尝试了多种方式改代码,还是没找到invalid parameter错误返回的原因
示例 #2 有什么问题?

其他

我不需要高级功能,由于性能要求,除了所需的 RSA 解密之外,它还执行许多其他操作。
也不希望使用 OpenSSL 或其他加密库

代码示例 #1 (CryptDecrypt)

// certPublicKey = certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData[.cbData]
const size_t StructSize = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + certPublicKey.size();
boost::scoped_array<uint8_t> arr(new uint8_t[StructSize]);
BLOBHEADER* pHeader = (BLOBHEADER*)&arr[0];
pHeader->bType = PUBLICKEYBLOB;
pHeader->bVersion = CUR_BLOB_VERSION;
pHeader->reserved = 0;
pHeader->aiKeyAlg = CALG_RSA_KEYX;

RSAPUBKEY* pPubKey = (RSAPUBKEY*)&arr[sizeof(BLOBHEADER)];
pPubKey->magic = 0x31415352;
pPubKey->bitlen = certPublicKey.size() * 8;
pPubKey->pubexp = 65537; // ?? is it correct for RSA ?

uint8_t* pKeyData = &arr[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)];
memcpy(pKeyData, &certPublicKey[0], certPublicKey.size());

HCRYPTKEY hKey;
BOOL res = CryptImportKey(g_hProv, (const BYTE*)&arr[0], StructSize, NULL, 0, &hKey);
PRINT_RES("CryptImportKey", res);
if (res)
{
    blob_t decryptedData = encryptedText;
    DWORD decryptedLength = encryptedText.size();
    res = CryptDecrypt(hKey, NULL, TRUE, 0, decryptedData.data(), &decryptedLength);
    PRINT_RES("CryptDecrypt", res); // err = 2148073485 (Key does not exist)
    if (res)
    {
        ...
    }

    res = CryptDestroyKey(hKey);
    PRINT_RES("CryptDestroyKey", res);
}

代码示例 #2 (CryptVerifySignature)

// hashInput = SignedData.contentInfo + SignedData.SignerInfo[0].authenticatedAttributes
HCRYPTHASH hHash;
blob_t hashValue;

BOOL res = CryptCreateHash(g_hProv, CALG_SHA1, NULL, 0, &hHash);
PRINT_RES("CryptCreateHash", res);

if (res)
{
    res = CryptHashData(hHash, hashInput.data(), hashInput.size(), 0);
    PRINT_RES("CryptHashData", res);

    PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, certData.data(), certData.size());
    PRINT_RES("CertCreateCertificateContext", certContext ? TRUE : FALSE);
    if (certContext)
    {
        HCRYPTKEY hCertPubKey;
        res = CryptImportPublicKeyInfo(g_hProv, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &certContext->pCertInfo->SubjectPublicKeyInfo, &hCertPubKey);
        PRINT_RES("CryptImportPublicKeyInfo", res);
        if (res)
        {
            res = CryptVerifySignatureA(hHash, encryptedText.data(), encryptedText.size(), hCertPubKey, NULL, 0);
            PRINT_RES("CryptVerifySignature", res); // err = 87 (The parameter is incorrect)

            res = CryptDestroyKey(hCertPubKey);
            PRINT_RES("CryptDestroyKey", res);
        }

        CertFreeCertificateContext(certContext);
    }
}

最佳答案

encryptedDigest 包含一个签名,您不解密它而是验证签名,因此您的第二个途径 CryptVerifySignature 是有前途的。

这里可能有很多地方会出错,例如,您实际上并没有告诉我们有关证书的任何信息。请关注Example C Program: Encoding and Decoding a Countersigned Message在 MSDN 上,您可能会对步骤 #2 中的 CryptVerifyMessageSignature 感兴趣,

...
// From the recipient's point of view, the following code 
// completes these steps: 
//     1.  Decodes the message
//     2.  Verifies the signature on the message
//     3.  Adds a countersignature to the signed message
//
...

转到示例的第二部分。

关于c++ - 使用 Windows Crypto API 和 C++ 的 PKCS #7 encryptedDigest 解密和验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21454545/

相关文章:

c# - RijndaelManaged 返回空结果

c++ - 如何在 C++ 中返回我自己的结构?

c++ - 为什么当一个模板类继承另一个模板类时,需要重新指定typedefs和函数调用限定?

windows - Windows 版 Git 停止工作

c++ - 如何使用 C++ 提高在 Windows 上读取数据的速度

linux - 如何让 Linux VM(在 Windows 主机上)访问共享目录上的 git 工作文件

python - 在 Twisted Python 中使用密码 - 属性错误?

php - 传输时加密的用户凭据

c++ - 正在初始化类型为 "int &"的引用(不是 const 限定的),其值是 "bool"类型的一些 hack?

c++ - 初始化一个固定的 C 数组成员结构