我很难解密使用OpenSSL和RSA_PKCS1_OAEP_PADDING填充选项加密的数据。
我正在做的是:
BCRYPT_ALG_HANDLE hCryptAlg = NULL;
BCRYPT_OAEP_PADDING_INFO paddingInfo = { 0 };
DWORD cbDecryptedMessage;
BYTE* pbDecryptedMessage = NULL;
paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
// Open an algorithm handle.
BCryptOpenAlgorithmProvider(&hCryptAlg, BCRYPT_RSA_ALGORITHM, NULL, 0);
// Calculate the required buffer
NCryptDecrypt(m_hKeyContextFull, (LPBYTE)pEncrypted, encryptedLenInBytes, &paddingInfo, NULL, cbDecryptedMessage, &outputDataLen, NCRYPT_PAD_OAEP_FLAG | NCRYPT_SILENT_FLAG);
// After required buffer is allocated...
NCryptDecrypt(m_hKeyContextFull, (LPBYTE)pEncrypted, encryptedLenInBytes, &paddingInfo, pbDecryptedMessage, cbDecryptedMessage, &outputDataLen, NCRYPT_PAD_OAEP_FLAG | NCRYPT_SILENT_FLAG);
失败,并显示NTE_INVALID_PARAMETER(0x80090027)。我尝试了不同的标志,但是没有一个起作用。
注意:已经使用CryptAcquireCertificatePrivateKey函数调用来检索m_hKeyContextFull:
m_hSystemStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, m_storeName.c_str());
m_pCertWithKeys = CertFindCertificateInStore(m_hSystemStore, SupportedEncodings, 0, CERT_FIND_SUBJECT_STR, m_certName.c_str(), NULL);
// Obtain the private key from the certificate.
DWORD m_KeyContextSpec = 0;
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE m_hKeyContextFull;
CryptAcquireCertificatePrivateKey(m_pCertWithKeys, CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG, NULL, &m_hKeyContextFull, &m_KeyContextSpec, &m_KeyContextMustBeReleased);
注意:为了便于阅读,所有错误检查已从代码中删除。
有什么想法我做错了吗?
谢谢。
答案 0 :(得分:1)
首先让paddingInfo有效:
BCRYPT_OAEP_PADDING_INFO paddingInfo;
paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
paddingInfo.pbLabel = NULL;
paddingInfo.cbLabel = 0;
当前标准具有空字符串标签(请参见RFC 3447)。
此外,关于pbDecryptedMessage
:
如果此参数为NULL,则此函数将计算解密数据所需的大小,并在pcbResult参数所指向的位置返回该大小。
所以它不会解密。您需要先将缓冲区分配给正确的大小; Windows API的许多工作方式是:首先使用输出缓冲区NULL调用它,然后以某种方式获取所需的大小,在这种情况下,使用outputDataLen
(您应声明!)。然后将outbufbuffer分配到该大小,并使用新鲜的缓冲区和正确的长度cbDecryptedMessage
再次调用该函数。使用后,当然请再次释放缓冲区。但是您的评论声称这样做了吗?
另一个可疑的事实:您使用NCryptDecrypt,因此第一个参数应该
是正确类型的hKey,而m_hKeyContextFull
似乎没有该类型。 CryptAcquireCertificatePrivateKey
将为您提供旧式的键柄。
您不能混合使用这些不同的Windows CryptoAPI。
也许要查看NcryptImportKey函数以进行传输。
答案 1 :(得分:0)
我对NCrypt
系列接口不熟悉,但是最近我们在库中使用BCrypt
系列接口实现了类似的功能。这是有问题的函数,可以在更大的上下文here中看到。
在我们的案例中,prvblbtyp
是LEGACY_RSAPRIVATE_BLOB
,here描述了prvblbbuf
和prvblbblen
。
static
int
asymmetric_decrypt(
const wchar_t * const prvblbtyp,
const void * const prvblbbuf, const size_t prvblblen,
const void * const ctbuf, const size_t ctlen,
void ** const ptbuf, size_t * const ptlen)
{
BCRYPT_ALG_HANDLE halg;
int res;
res = INT_MIN;
if (BCryptOpenAlgorithmProvider(
&halg, BCRYPT_RSA_ALGORITHM, NULL, 0) == STATUS_SUCCESS) {
BCRYPT_KEY_HANDLE hkey;
if (BCryptImportKeyPair(
halg,
NULL, prvblbtyp, &hkey,
(void *)prvblbbuf, prvblblen,
0) == STATUS_SUCCESS) {
BCRYPT_OAEP_PADDING_INFO inf;
ULONG len;
inf.pszAlgId = BCRYPT_SHA1_ALGORITHM;
inf.pbLabel = NULL;
inf.cbLabel = 0;
/*
* decrypt first with a NULL output buffer.
* this returns the size necessary for the buffer.
*/
if (BCryptDecrypt(
hkey,
(void *)ctbuf, ctlen,
&inf,
NULL, 0,
NULL, 0, &len,
BCRYPT_PAD_OAEP) == STATUS_SUCCESS) {
void * buf;
/*
* allocate the required buffer
* and decrypt again
*/
res = -ENOMEM;
buf = malloc(len);
if (buf) {
res = INT_MIN;
if (BCryptDecrypt(
hkey,
(void *)ctbuf, ctlen,
&inf,
NULL, 0,
buf, len, &len,
BCRYPT_PAD_OAEP) == STATUS_SUCCESS) {
*ptbuf = buf;
*ptlen = len;
res = 0;
} else {
free(buf);
}
}
}
BCryptDestroyKey(hkey);
}
BCryptCloseAlgorithmProvider(halg, 0);
}
return res;
}