如何使用NCryptDecrypt解密使用RSA_PKCS1_OAEP_PADDING由OpenSSL加密的数据?

时间:2018-07-13 20:15:05

标签: encryption cryptography

我很难解密使用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);

注意:为了便于阅读,所有错误检查已从代码中删除。

有什么想法我做错了吗?

谢谢。

2 个答案:

答案 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中看到。

在我们的案例中,prvblbtypLEGACY_RSAPRIVATE_BLOBhere描述了prvblbbufprvblbblen

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;
}