2015-09-11 52 views
2

我需要生成我自己的DSA密鑰對,並使用C#將它作爲一組私鑰和證書存儲在.p12文件中。如何在C#中爲DSA密鑰對創建帶有自簽名證書的PKCS12 p12文件?

這個問題

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

似乎非常相似,但它並不能幫助我,不幸的是,因爲有一些顯著的差異(RSA VS 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."

我真的不明白髮生了什麼事。我究竟做錯了什麼?謝謝!

回答

2

對此感興趣,這裏是我的小調查。當您設置certificateDSA的專用密鑰,.NET代碼的功能大致是這樣的:

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

這些斑點是在位置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包括種子和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參數種子和計數器。此代碼不會拋出錯誤並完成正常。也許在這個解決方法中有一些警告,但儘管它沒有完全解決它,但它可能對進一步調查問題有用。

+0

它現在有效,證書看起來不錯,我會測試它是否可以。做得好!謝謝! – vojta

相關問題