如何在C#/。net中保留RSAParameter的私钥

时间:2018-12-04 10:17:15

标签: c# .net rsa x509certificate2

从.Net 4.7.2(.Net Standard 2.0)开始,可以仅使用C#/。Net创建自签名证书和证书签名请求,请参见MS Documentation

虽然可以直接创建一个自签名证书来声明HasPrivateKey(您只需致电CreateSelfSigned(notBefore, notAfter)),但是我很难弄清楚如何获得私钥一般而言,例如如果我要创建由CA签名的证书,然后要将证书作为PFX文件持久保存,或者要将私钥保存在.PEM文件中,或者要将其与证书一起存储在MS证书存储中,私钥,或者当我只想在内存中同时声明HasPrivateKey时。

我所拥有的是一个“ RSAParameters”实例,该实例拥有相关的私人信息,但是我无法弄清楚如何(轻松地)将其用于相关目的(创建PFX文件或PEM文件或MS证书存储条目),而不必通读所有相关RFC并自己编写程序。 (该RSAParameter实例包含DExponentModulus,因此我可以尝试将它们修补在一起(希望在this answer的帮助下),但我希望的C#方法将为我执行这些任务(目前我还找不到)。

当然,我们的想法是单独使用.Net功能。

关于如何实现这一目标的每条提示都值得赞赏。

2 个答案:

答案 0 :(得分:1)

如果只有ModulusExponentD,则必须首先恢复CRT参数(PQ,{{1} },DPDQ)。

与其他问题一样,您主要缺少InverseQ扩展方法和cert.CopyWithPrivateKey(key)

  

如果我想创建由CA签名的证书,然后想将该证书作为PFX文件持久保存

rsa.ImportParameters(RSAParameters)
  

或想将私钥保留在.PEM文件中

.NET Core 3.0每日内部版本中提供了此版本:

using (RSA rsa = RSA.Create())
{
    rsa.ImportParameters(rsaParameters);

    using (X509Certificate2 caSigned = GetCASignedCert(rsa))
    using (X509Certificate2 withKey = caSigned.CopyWithPrivateKey(rsa))
    {
        File.WriteAllBytes("some.pfx", withKey.Export(X509ContentType.Pkcs12, "and a password"));
    }
}

PKCS#8和加密的PKCS#8也可用。

在现有版本上,这需要使用RSAParameters和ITU-T X.690 DER编码器。

  

或要将其与私钥一起存储在MS证书存储中

RSAParameters rsaParameters = default(RSAParameters);

using (StreamWriter writer = new StreamWriter("rsa.key"))
using (RSA rsa = RSA.Create())
{
    rsa.ImportParameters(rsaParameters);

    writer.WriteLine("-----BEGIN RSA PRIVATE KEY-----");

    writer.WriteLine(
        Convert.ToBase64String(
            rsa.ExportRSAPrivateKey(),
            Base64FormattingOptions.InsertLineBreaks));

    writer.WriteLine("-----END RSA PRIVATE KEY-----");
}
  

或者当我只想在内存中同时声明HasPrivateKey时。

using (RSA rsa = RSA.Create())
{
    rsa.ImportParameters(rsaParameters);

    using (X509Certificate2 caSigned = GetCASignedCert(rsa))
    using (X509Certificate2 withKey = caSigned.CopyWithPrivateKey(rsa))
    using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
    {
        X509Certificate2 persisted = new X509Certificate2(
            withKey.Export(X509ContentType.Pkcs12, ""),
            "",
            X509KeyStorageFlags.PersistKeySet);

        using (persisted)
        {
            store.Open(OpenFlags.ReadWrite);
            store.Add(persisted);
        }
    }
}

答案 1 :(得分:0)

例如,如果您正在使用USB密钥之类的证书硬件安全模块(HSM),则不可能“获取”私有密钥,因为HSM仅提供使用私有密钥的接口。这是出于安全性考虑,因为一旦私钥在文件或内存中,它就有可能由​​第三方获得。

.NET历来没有提供足够灵活的界面,尽管它正在改进。因此,许多软件供应商都使用更完整和维护得更好的Bouncy Castle API(http://www.bouncycastle.org/csharp/),您会在网上找到很多文档。通常,如果.NET无法做到这一点,那么充气城堡就可以了。具有讽刺意味的是,HSM需要.NET加密访问,这是Windows上的私钥功能,但是您通常会以某种方式对其进行封装。

通常,使用加密API的学习曲线非常陡峭,如果没有想要编写的代码示例,您不太可能会获得很多帮助。