简介
我正在尝试执行以下操作来检查证书的 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 key 对 encryptedDigest 进行 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/