【问题标题】:How to get private key as Byte[] of a password protected pfx fetched from azure key vault如何获取私钥作为从 azure key vault 获取的受密码保护的 pfx 的字节 []
【发布时间】:2020-12-05 09:21:36
【问题描述】:

我正在使用 GetSecretAsync() 方法从 Azure Key Vault 获取我的证书,然后我希望最终获得私钥和证书的字节[]。

我在 .netcore3.1 中有我的应用程序 这就是我的代码的样子:

var certWithPrivateKey = Client.GetSecretAsync(ConfigurationSettings.AppSettings["AKVEndpoint"], ConfigurationSettings.AppSettings["CertName"]).GetAwaiter().GetResult();
var privateKeyBytes = Convert.FromBase64String(certWithPrivateKey.Value);

X509Certificate2 x509Certificate = new X509Certificate2(privateKeyBytes);
var privateKey = x509Certificate.GetRSAPrivateKey() as RSA;

我获得了 RSACng 类型的有效 privateKey,但任何操作(尝试 ExportRSAPrivateKey())都会引发错误“'privateKey.ExportRSAPrivateKey()' 引发了类型为 'Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException'”的异常和“不支持请求的操作。”

我不知道接下来如何继续获取私钥和​​证书的字节[]。

【问题讨论】:

  • 为什么不用密钥而不是秘密?
  • 为什么需要导出私钥?最终目标是什么?
  • 我想最终将该证书安装在我的 kubernetes 集群中作为 tls 机密,所以我希望获得私钥和证书的字节 [] 最终制作一个 .cer 和 .key 文件和使用它们来创建秘密。

标签: c# .net-core cryptography private-key x509certificate2


【解决方案1】:

由于您确实似乎确实需要导出:您当前的代码不会将私钥加载为可导出的,因此无法导出。解决方法是断言可导出性:

X509Certificate2 x509Certificate =
    new X509Certificate2(privateKeyBytes, "", X509KeyStorageFlags.Exportable);

如果这还不够,那么您会遇到 CAPI 可导出性和 CNG 可导出性(Windows 较旧和较新的加密库)之间的差异。如果来自 PFX/PKCS#12 的私钥被加载到 CNG 中,则它只能“加密导出”,但 ExportParameters 是明文导出。

不过有一种解决方法...将其加密导出,然后使用更灵活的导出策略将其导入其他地方,然后再次导出。

此 sn-p 使用 .NET Core 3.0+ ExportPkcs8PrivateKey() 方法,因为这是您希望数据采用的格式,并且新的 .NET 5 PemEncoding 类可简化将 DER 编码输出转换为 PEM+DER 输出.如果您的导出器在 .NET Framework 上,则这是 more complex problem。对于 .NET Standard 2.0,没有真正干净的解决方案(反映调用 .NET Core/.NET 5 的方法,否则使用 .NET Framework 的 Windows 特定版本?)。

byte[] pkcs8PrivateKey;

using (RSA privateKey = x509Certificate.GetRSAPrivateKey())
{
    pkcs8PrivateKey = ExportPrivateKey(privateKey);
}

File.WriteAllText(
    "tls.cer",
    new string(PemEncoding.Write("CERTIFICATE", x509Certificate.RawData));

File.WriteAllText(
    "tls.key",
    new string(PemEncoding.Write("PRIVATE KEY", pkcs8PrivateKey));

...

private static byte[] ExportPrivateKey(RSA privateKey)
{
    try
    {
        // If it's plaintext exportable, just do the easy thing.
        return privateKey.ExportPkcs8PrivateKey();
    }
    catch (CryptographicException)
    {
    }

    using (RSA exportRewriter = RSA.Create())
    {
        // Only one KDF iteration is being used here since it's immediately being
        // imported again.  Use more if you're actually exporting encrypted keys.
        exportRewriter.ImportEncryptedPkcs8PrivateKey(
            "password",
            privateKey.ExportEncryptedPkcs8PrivateKey(
                "password",
                new PbeParameters(
                    PbeEncryptionAlgorithm.Aes128Cbc,
                    HashAlgorithmName.SHA256,
                    1)),
            out _);

        return exportRewriter.ExportPkcs8PrivateKey();
    }
}

【讨论】:

  • 非常感谢@bartonjs 的详细回答。第一个断言可移植性的 sn-p 为我解决了这个问题,我能够直接从 ExportPkcs8PrivateKey() 中获取 byte[] 。我现在跳过了文件创建部分,因为我现在使用 C# 的 kubernetes 客户端来创建 tls 机密,它直接接受 byte[]。
猜你喜欢
  • 2020-02-07
  • 1970-01-01
  • 2016-07-02
  • 2019-01-02
  • 1970-01-01
  • 2022-07-22
  • 2019-01-27
  • 1970-01-01
  • 2017-12-19
相关资源
最近更新 更多