【问题标题】:How can I create a PKCS12 p12 file with selfsigned certificate for DSA keypair in C#?如何在 C# 中为 DSA 密钥对创建带有自签名证书的 PKCS12 p12 文件?
【发布时间】:2015-09-11 06:09:25
【问题描述】:

我需要生成我自己的 DSA 密钥对,并使用 C# 将其作为私钥和证书包存储在 .p12 文件中。

这个问题

How do I create a PKCS12 .p12 file in C#?

似乎非常相似,但不幸的是,它对我没有帮助,因为存在一些显着差异(RSA 与 DSA 等)

我正在尝试使用 System.Security.Cryptography.DSACryptoServiceProvider 生成密钥对,然后使用 Bouncy Castle 生成 X509 证书:

using (DSACryptoServiceProvider csp = new DSACryptoServiceProvider(1024))
{
       privKeyDSA = csp.ExportParameters(true);
       pubKeyDSA = csp.ExportParameters(false);
       var keypair = DotNetUtilities.GetDsaKeyPair(privKeyDSA);

       var gen = new X509V3CertificateGenerator();

       var CN = new X509Name("CN=" + "TEST");
       var SN = BigInteger.ProbablePrime(120, new Random());

       gen.SetSerialNumber(SN);
       gen.SetSubjectDN(CN);
       gen.SetIssuerDN(CN);
       gen.SetNotAfter(DateTime.MaxValue);
       gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
       gen.SetSignatureAlgorithm("sha1WithDSA");
       gen.SetPublicKey(DotNetUtilities.GetDsaPublicKey(pubKeyDSA));
       var newCert = gen.Generate(keypair.Private);


       certificateDSA = new X509Certificate2(DotNetUtilities.ToX509Certificate((Org.BouncyCastle.X509.X509Certificate)newCert));

       certificateDSA.PrivateKey = csp;
       StringBuilder builder = new StringBuilder();

        builder.AppendLine("-----BEGIN CERTIFICATE-----");
        builder.AppendLine(Convert.ToBase64String(certificateDSA.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
        builder.AppendLine("-----END CERTIFICATE-----");

        string result = builder.ToString();
        byte[] pkcsData = certificateDSA.Export(X509ContentType.Pfx, "changeit");
}

但是,certificateDSA.PrivateKey = csp; 行会抛出带有消息的CryptographicUnexpectedOperationException"The public key of the certificate does not match the value specified."

我真的不明白发生了什么。我究竟做错了什么?谢谢!

【问题讨论】:

    标签: c# security cryptography x509certificate bouncycastle


    【解决方案1】:

    对此感兴趣,这是我的小调查。当您设置 certificateDSA 的 PrivateKey 时,.NET 代码大致执行以下操作:

    byte[] numArray1 = ((ICspAsymmetricAlgorithm) certificateDSA.PublicKey.Key).ExportCspBlob(false);
    byte[] numArray2 = csp.ExportCspBlob(false);
    // And then those two blobs are compared byte by byte
    

    这些 blob 从位置 420 开始是不同的(它们的长度为 444)。所以 csp 参数有问题。比较原始字节并不容易,所以让我们将它们转换为可读的 xml:

    var xml1 = certificateDSA.PublicKey.Key.ToXmlString(false);
    var xml2 = csp.ToXmlString(false);
    

    我们会得到这样的:

    <DSAKeyValue> <!--this is parameters of cert public key-->
        <P>2arEQPD3/tKm7pJF1y4gN0/4WzSGfkgFwdmtmoUf/gHoXpdBetRH/5j98qo4k1ybePxM4om4y6n9vhxijocMw5LaeQPceGyNOEScWXXrNKAcUsK74klQmiPOoI2qI1zU5v2HrilKmkOELH81U8/Qmmjmg7ouOdOHqlZAxW9Sv8M=</P>
        <Q>lzRdUtp56eZHIgxRemvdHciGIfc=</Q>
        <G>Z/2T+jXvv0ZLswbuMd9DxrHldakJxZ8JNGRf1QzN09B2VO9WYAzUy0S+J8hbYQjP/jzWbmL5LaK57v+MUOmOHzFwNqfVMe9OUglUfF3nN990ur9hp6csu8+vCEQt3EoI8Wmh/b2yqhtKRN6U494vf33WKo1NCNQapB+iWVQ/egQ=</G>
        <Y>ykcPXFIxWvYDDbbY05oD3hD6LsM5rk76FakUY8YiCo8ZwWbMIlQw+v5nOYS9vpQaZAzUqxx9OXIGSTUGItruTARkDqZ0nGKL0r94Zhog1Y0wU2AVKJh8Vjq/dLFyDDGZZsxBZtmI8TDyKGJbZqvzGbdGLhoRxRFmNi1fVsADv+U=</Y>
    </DSAKeyValue>
    
    <DSAKeyValue> <!-- this is paramteres of original DSACryptoServiceProvider-->
        <P>2arEQPD3/tKm7pJF1y4gN0/4WzSGfkgFwdmtmoUf/gHoXpdBetRH/5j98qo4k1ybePxM4om4y6n9vhxijocMw5LaeQPceGyNOEScWXXrNKAcUsK74klQmiPOoI2qI1zU5v2HrilKmkOELH81U8/Qmmjmg7ouOdOHqlZAxW9Sv8M=</P>
        <Q>lzRdUtp56eZHIgxRemvdHciGIfc=</Q>
        <G>Z/2T+jXvv0ZLswbuMd9DxrHldakJxZ8JNGRf1QzN09B2VO9WYAzUy0S+J8hbYQjP/jzWbmL5LaK57v+MUOmOHzFwNqfVMe9OUglUfF3nN990ur9hp6csu8+vCEQt3EoI8Wmh/b2yqhtKRN6U494vf33WKo1NCNQapB+iWVQ/egQ=</G>
        <Y>ykcPXFIxWvYDDbbY05oD3hD6LsM5rk76FakUY8YiCo8ZwWbMIlQw+v5nOYS9vpQaZAzUqxx9OXIGSTUGItruTARkDqZ0nGKL0r94Zhog1Y0wU2AVKJh8Vjq/dLFyDDGZZsxBZtmI8TDyKGJbZqvzGbdGLhoRxRFmNi1fVsADv+U=</Y>
        <Seed>1hiZoCQFivF9xDZdQEGue65oObA=</Seed>
        <PgenCounter>Og==</PgenCounter>
    </DSAKeyValue>
    

    您看到原来的 DSACryptoServiceProvider 包含 Seed 和 PgenCounter,而使用 Bouncy Castle 生成证书后,证书的公钥不包含它们。这些参数是可选的(从某种意义上说,公钥可能不包含),但如果它们存在,它们应该存在于双方(私有和公共)。我们如何解决这个问题?代码如下:

    using (DSACryptoServiceProvider csp = new DSACryptoServiceProvider(1024)) {
                var parameters = csp.ExportParameters(true);                
                var keypair = DotNetUtilities.GetDsaKeyPair(parameters);
                var gen = new X509V3CertificateGenerator();
                var CN = new X509Name("CN=" + "TEST");
                var SN = BigInteger.ProbablePrime(120, new Random());
                gen.SetSerialNumber(SN);
                gen.SetSubjectDN(CN);
                gen.SetIssuerDN(CN);
                gen.SetNotAfter(DateTime.Now.AddDays(1));
                gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
                gen.SetSignatureAlgorithm("sha1WithDSA");
                gen.SetPublicKey(keypair.Public);
                var newCert = gen.Generate(keypair.Private);
    
                var certificateDSA = new X509Certificate2(DotNetUtilities.ToX509Certificate(newCert));
                // added block
                parameters.Seed = new byte[20];
                unchecked {
                    parameters.Counter = (int) 0xFFFFFFFF;
                }
                csp.ImportParameters(parameters);
                // end of added block
                certificateDSA.PrivateKey = csp;
                StringBuilder builder = new StringBuilder();
    
                builder.AppendLine("-----BEGIN CERTIFICATE-----");
                builder.AppendLine(Convert.ToBase64String(certificateDSA.Export(X509ContentType.Pkcs12), Base64FormattingOptions.InsertLineBreaks));
                builder.AppendLine("-----END CERTIFICATE-----");
    
                string result = builder.ToString();                
            }
    

    我们在这里所做的是在生成所有内容之后,但在将私钥分配给证书之前,我们从 DSACryptoServiceProvider 参数中“删除”种子和计数器。此代码不会引发错误并且可以正常完成。在此解决方法中可能有一些警告,但即使它没有完全解决问题,进一步调查该问题也可能有用。

    【讨论】:

    • 现在可以了,证书看起来不错,我会测试是否可以。做得好!谢谢!
    猜你喜欢
    • 2012-02-25
    • 2011-01-03
    • 1970-01-01
    • 2012-12-31
    • 2021-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    相关资源
    最近更新 更多