[英]How can I create a PKCS12 p12 file with selfsigned certificate for DSA keypair in C#?
我需要生成我自己的 DSA 密钥对,并使用 C# 将其作为私钥和证书包存储在 .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.