【问题标题】:How to export a password-protected private key using MS CryptoAPI?如何使用 MS CryptoAPI 导出受密码保护的私钥?
【发布时间】:2016-10-09 15:10:56
【问题描述】:

使用 Microsoft CryptoAPI,我生成了一个新的 RSA 密钥对,现在正尝试将私钥导出到 PKCS#8 加密(受密码保护)PEM 文件。

我首先研究了CryptExportPKCS8()和CryptExportPKCS8Ex(),但是前者不支持加密密钥,后者是not exported by crypt32.dll。 MSDN 说这两个功能都已被弃用。

我目前的尝试是将从密码派生的会话密钥传递给 CryptExportKey():

HCRYPTPROV provider;
BOOL result = CryptAcquireContext(&provider, CONTAINER_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_SILENT);
HCRYPTKEY keyPair;
result = CryptGenKey(provider, CALG_RSA_KEYX, (2048 << 16) | CRYPT_EXPORTABLE, &keyPair);

HCRYPTHASH hash;
result = CryptCreateHash(provider, CALG_SHA1, 0, 0, &hash);
const char *password = "password";
result = CryptHashData(hash, (const BYTE *)password, strlen(password), 0);
HCRYPTKEY sessionKey;
result = CryptDeriveKey(provider, CALG_3DES, hash, CRYPT_EXPORTABLE, &sessionKey);

DWORD blobSize;
result = CryptExportKey(keyPair, sessionKey, PRIVATEKEYBLOB, 0, NULL, &blobSize);
BYTE *blobBytes = new BYTE[blobSize];
result = CryptExportKey(keyPair, sessionKey, PRIVATEKEYBLOB, 0, blobBytes, &blobSize);

DWORD derSize;
// This throws "First-chance exception ... Access violation reading ..." and returns FALSE
result = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, blobBytes, 0, NULL, NULL, &derSize);
// error is 3221225477 (0xC0000005)
DWORD error = GetLastError();
BYTE *derBytes = new BYTE[derSize];
result = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, blobBytes, 0, NULL, derBytes, &derSize);

// ... CryptBinaryToString() to convert to PEM

// ... Write PEM to file

在注释掉的 CryptEncodeObjectEx() 之前,所有调用都会成功。

如果我不将会话密钥传递给 CryptExportKey(),那么我可以成功使用 CryptEncodeObjectEx() 对私钥进行编码,但显然它是纯文本的。

如何导出受密码保护的私钥?我派生会话密钥的方式有问题吗? PKCS_RSA_PRIVATE_KEY 是错误的编码类型吗?

我一直在 Windows 7 上的 Visual Studio 2013 中进行测试。

【问题讨论】:

    标签: c++ winapi encryption cryptoapi


    【解决方案1】:

    PKCS_RSA_PRIVATE_KEY 仅在私钥 blob 未加密时使用。当它加密时,您必须使用 PKCS_ENCRYPTED_PRIVATE_KEY_INFO。工作代码示例

    BOOL expKey(PCSTR password)
    {
        BOOL fOk = FALSE;
        HCRYPTPROV hProv;
        if (CryptAcquireContext(&hProv, 0, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
        {
            HCRYPTKEY hKey, hExpKey;
            HCRYPTHASH hHash;
    
            BOOL f = FALSE;
    
            if (CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
            {
                if (CryptHashData(hHash, (PBYTE)password, (ULONG)strlen(password), 0))
                {
                    f = CryptDeriveKey(hProv, CALG_3DES, hHash, 0, &hExpKey);
                }
                CryptDestroyHash(hHash);
            }
    
            if (f)
            {
                if (CryptGenKey(hProv, CALG_RSA_KEYX, RSA1024BIT_KEY*2|CRYPT_EXPORTABLE, &hKey))
                {
                    CRYPT_ENCRYPTED_PRIVATE_KEY_INFO cepki = {{ szOID_RSA_DES_EDE3_CBC}};
                    if (
                        CryptExportKey(hKey, hExpKey, PRIVATEKEYBLOB, 0, 0, &cepki.EncryptedPrivateKey.cbData) &&
                        CryptExportKey(hKey, hExpKey, PRIVATEKEYBLOB, 0, cepki.EncryptedPrivateKey.pbData = (PBYTE)alloca(cepki.EncryptedPrivateKey.cbData), &cepki.EncryptedPrivateKey.cbData)
                        )
                    {
                        ULONG cb;
                        PVOID pvEncoded;
                        if (CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_ENCRYPTED_PRIVATE_KEY_INFO, &cepki, CRYPT_ENCODE_ALLOC_FLAG, 0, &pvEncoded, &(cb = sizeof(PVOID))))
                        {
                            fOk = TRUE;
                            LocalFree(pvEncoded);
                        }
                    }
                }
                CryptDestroyKey(hExpKey);
            }
            CryptReleaseContext(hProv, 0);
        }
    
        return fOk;
    }
    

    【讨论】:

    • pvEncoded 是什么格式? openssl asn1parse -inform DER -in test.der 显示有效的 ASN.1,但 openssl pkcs8 -inform DER -in test.der 给出 unknown pbe algorithm:evp_pbe.c:162:TYPE=des-ede3-cbc
    猜你喜欢
    • 1970-01-01
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    • 1970-01-01
    • 2014-01-04
    • 1970-01-01
    相关资源
    最近更新 更多