如何在C#中通过CSR文件生成符合要求的RSA公钥?
问题解决:C#生成的RSA公钥与OpenSSL输出不兼容
核心问题分析
- 私钥格式差异:OpenSSL生成的是PKCS#8无加密私钥(头部
-----BEGIN PRIVATE KEY-----),而你的BouncyCastle代码默认输出PKCS#1格式RSA私钥(头部-----BEGIN RSA PRIVATE KEY-----),格式不匹配会导致API验证失败。 - 公钥格式差异:OpenSSL从CSR导出的公钥是SPKI(SubjectPublicKeyInfo)格式(头部
-----BEGIN PUBLIC KEY-----),你的代码直接写入RsaPublicKey会生成PKCS#1格式公钥,这是API不认的关键原因。 - 编码细节:OpenSSL用
-utf8参数处理特殊字符(比如[Stamp]),需要确保C#代码的DN字段也用UTF-8编码。
修正后的BouncyCastle代码
1. 私钥输出改为PKCS#8格式
通过PrivateKeyInfoFactory转换格式后写入:
using (var fw = File.CreateText("fa.key")) { var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private); var writer = new PemWriter(fw); writer.WriteObject(privateKeyInfo); }
2. 公钥输出改为SPKI格式
用SubjectPublicKeyInfoFactory转换后写入,匹配OpenSSL的公钥格式:
var publicKey = csr.GetPublicKey(); var publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey); using (var fw = File.CreateText("publickey.pem")) { var writer = new PemWriter(fw); writer.WriteObject(publicKeyInfo); }
3. 对齐UTF-8编码与签名算法
显式指定UTF-8处理DN特殊字符,确保和OpenSSL的-utf8参数一致:
// 用UTF-8编码创建Subject,避免特殊字符乱码 var subject = new X509Name(X509Name.DefaultStyle, Encoding.UTF8.GetBytes(subjectName));
完整修正代码
var subjectName = "CN=MyCompany [Stamp],O=Non-Governmental,serialNumber=12345678910,C=US"; // 显式用UTF-8编码处理Subject中的特殊字符 var subject = new X509Name(X509Name.DefaultStyle, Encoding.UTF8.GetBytes(subjectName)); // 生成2048位RSA密钥对 var randomGenerator = new CryptoApiRandomGenerator(); var random = new SecureRandom(randomGenerator); const int strength = 2048; var keyGenerationParameters = new KeyGenerationParameters(random, strength); var keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); var subjectKeyPair = keyPairGenerator.GenerateKeyPair(); // 写入PKCS#8格式私钥(和OpenSSL输出一致) using (var fw = File.CreateText("fa.key")) { var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private); var writer = new PemWriter(fw); writer.WriteObject(privateKeyInfo); } // 生成PKCS#10 CSR,签名算法保持SHA1WITHRSA var csr = new Pkcs10CertificationRequest("SHA1WITHRSA", subject, subjectKeyPair.Public, null, subjectKeyPair.Private); // 导出CSR到文件 var csrPem = new StringBuilder(); var csrPemWriter = new PemWriter(new StringWriter(csrPem)); csrPemWriter.WriteObject(csr); csrPemWriter.Writer.Flush(); using (StreamWriter f = new StreamWriter(@"fa.csr")) { f.Write(csrPem.ToString()); } // 生成SPKI格式公钥(匹配OpenSSL导出的公钥) var publicKey = csr.GetPublicKey(); var publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey); using (var fw = File.CreateText("publickey.pem")) { var writer = new PemWriter(fw); writer.WriteObject(publicKeyInfo); }
替代库推荐
如果嫌BouncyCastle API繁琐,可考虑:
- OpenSSL.NET:直接调用OpenSSL原生接口,行为和手动执行命令完全一致,无需担心格式匹配问题。
- Certes:API简洁,专注证书相关操作,支持生成标准格式的CSR、密钥对和公钥。
内容的提问来源于stack exchange,提问作者Nima Ghomri
相关产品推荐
相关产品推荐

