【问题标题】:How to export RSA Keys generated from CNG API?如何导出从 CNG API 生成的 RSA 密钥?
【发布时间】:2021-12-22 19:21:50
【问题描述】:

我使用以下 CNG API 序列成功生成了 RSA 密钥:

BCryptOpenAlgorithmProvider(.., BCRYPT_RSA_ALGORITHM, ...);
BCryptGenerateKeyPair(..., 2048/*Key size*/, ...);
BCryptFinalizeKeyPair(...);
BCryptExportKey(..., BCRYPT_RSAPRIVATE_BLOB, ...);
BCryptExportKey(..., BCRYPT_RSAPUBLIC_BLOB, ...);

我对生成的缓冲区的哪一部分应该进行 Base64 编码以写出 PEM 文件感到困惑?如果我对现有有效 PEM 文件具有的整个缓冲区进行 Base64 编码,我不会在缓冲区中看到“MIIE”。

非常感谢任何指导。

【问题讨论】:

    标签: windows encryption rsa cng


    【解决方案1】:

    真的不需要从BCryptExportKeyNCryptExportKey 直接对输出进行base64 编码,而是做一些额外的步骤:

    1. 使用BCryptExportKey(或NCryptExportKeyBCRYPT_RSAFULLPRIVATE_BLOB(但不是BCRYPT_RSAPRIVATE_BLOB)或BCRYPT_RSAPUBLIC_BLOB
    2. 编码结果BCRYPT_RSAKEY_BLOB CNG_RSA_PRIVATE_KEY_BLOBCNG_RSA_PUBLIC_KEY_BLOB 并发送至 CRYPT_PRIVATE_KEY_INFO
    3. PKCS_PRIVATE_KEY_INFO编码CRYPT_PRIVATE_KEY_INFO
    4. 致电CryptBinaryToStringA

    只有在此之后,缓冲区内才会出现“MIIE”

    HRESULT bthr(BOOL b)
    {
        return b ? S_OK : HRESULT_FROM_WIN32(GetLastError());
    }
    
    HRESULT ExportToPem(_In_ BCRYPT_KEY_HANDLE hKey, BOOL bPrivate, _Out_ PSTR* ppsz, _Out_ PULONG pcch)
    {
        HRESULT hr;
        CRYPT_PRIVATE_KEY_INFO PrivateKeyInfo = { 0, {const_cast<PSTR>(szOID_RSA_RSA)} };
        ULONG cbKey = 0;
        PUCHAR pbKey = 0;//really PBCRYPT_RSAKEY_BLOB
    
        PCWSTR pszBlobType;
        PCSTR lpszStructType;
    
        if (bPrivate)
        {
            pszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB;
            lpszStructType = CNG_RSA_PRIVATE_KEY_BLOB;
        }
        else
        {
            pszBlobType = BCRYPT_RSAPUBLIC_BLOB;
            lpszStructType = CNG_RSA_PUBLIC_KEY_BLOB;
        }
    
        while (0 <= (hr = BCryptExportKey(hKey, 0, pszBlobType, pbKey, cbKey, &cbKey, 0)))
        {
            if (pbKey)
            {
                if (0 <= (hr = bthr(CryptEncodeObjectEx(X509_ASN_ENCODING, 
                    lpszStructType, pbKey, CRYPT_ENCODE_ALLOC_FLAG, 0, 
                    &PrivateKeyInfo.PrivateKey.pbData, &PrivateKeyInfo.PrivateKey.cbData))))
                {
                    hr = bthr(CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, 
                        &PrivateKeyInfo, CRYPT_ENCODE_ALLOC_FLAG, 0, 
                        &pbKey, &cbKey));
    
                    LocalFree(PrivateKeyInfo.PrivateKey.pbData);
    
                    if (0 <= hr)
                    {
                        PSTR psz = 0;
                        ULONG cch = 0;
                        while (0 <= (hr = bthr(CryptBinaryToStringA(
                            pbKey, cbKey, CRYPT_STRING_BASE64, psz, &cch))))
                        {
                            if (psz)
                            {
                                *ppsz = psz, *pcch = cch;
                                break;
                            }
    
                            if (!(psz = (PSTR)LocalAlloc(0, cch)))
                            {
                                hr = HRESULT_FROM_WIN32(GetLastError());
                                break;
                            }
                        }
    
                        LocalFree(pbKey);
                    }
                }
                break;
            }
    
            pbKey = (PUCHAR)alloca(cbKey);
        }
    
        return hr;
    }
    

    并使用它:

        PSTR psz;
        ULONG cch;
        if (0 <= ExportToPem(hKey, bPrivate, &psz, &cch))
        {
            PSTR pc = psz;
            ULONG cb;
            do 
            {
                cb = min(cch, 0x100);
                DbgPrint("%.*s", cb, pc);
            } while (pc += cb, cch -= cb);
            LocalFree(psz);
        }
    

    【讨论】:

    • 谢谢!我能够使用它生成 Base64 密钥。我实际上在往返加密和解密时遇到了麻烦,但我认为这更多是关于我如何调用加密/解密函数的问题。
    • @Unknown1987 我实际上在往返加密和解密时遇到了麻烦 - 有意义吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-16
    • 2018-05-31
    • 1970-01-01
    相关资源
    最近更新 更多