如何从天蓝色的密钥库中获取作为受密码保护的pfx的Byte []的私钥

问题描述

我正在使用GetSecretAsync()方法从Azure密钥保管库中获取证书,然后期望最终获得私钥的byte []和证书。

我在.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”的异常和“不支持请求的操作。”

我不确定接下来如何获取私钥和​​证书的字节[]。

解决方法

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

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

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

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

此代码段使用.NET Core 3.0+ ExportPkcs8PrivateKey()方法,因为这是您希望数据使用的格式,并且使用新的.NET 5 PemEncoding类来简化将DER编码的输出转换为PEM + DER输出。如果您的导出器在.NET Framework上,则为more complex problem。对于.NET Standard 2.0,实际上不是一个干净的解决方案(是否可以调用.NET Core / .NET 5的方法,否则可以使用Windows专用的.NET Framework版本?)。

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