簡體   English   中英

如何在 C# 中為 DSA 密鑰對創建帶有自簽名證書的 PKCS12 p12 文件?

[英]How can I create a PKCS12 p12 file with selfsigned certificate for DSA keypair in C#?

我需要生成我自己的 DSA 密鑰對,並使用 C# 將其作為私鑰和證書包存儲在 .p12 文件中。

這個問題

如何在 C# 中創建 PKCS12 .p12 文件?

似乎非常相似,但不幸的是,它對我沒有幫助,因為存在一些顯着差異(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."

我真的不明白發生了什么。 我究竟做錯了什么? 謝謝!

對此感興趣,這是我的小調查。 當您設置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 參數中“刪除”種子和計數器。 此代碼不會拋出錯誤並且可以正常完成。 也許這個變通方法有一些注意事項,但即使它沒有完全修復它,進一步調查這個問題也可能是有用的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM