如何在MAUI C#8.0(Android)生成与OpenSSL一致的PEM格式RSA公私钥
问题:MAUI Android生成的RSA公钥PEM格式与OpenSSL不一致
在Windows环境下,通过调用OpenSSL的C#代码生成2048位RSA公私钥及CSR时,得到的公钥是451字符、9行的标准PEM格式(见Section 1);但在MAUI Android中使用.NET内置API生成时,得到的公钥为419字符、8行(见Section 2),格式无法匹配。以下是具体代码及示例,附解决方案:
1. Windows下调用OpenSSL的实现代码及标准公钥示例
生成逻辑代码
string[] textArray1 = new string[] { "req -new -utf8 -nameopt multiline,utf8 -config \"", this.CNF_FILEPATH, "\" -newkey rsa:2048 -nodes -keyout \"", this.PRIVATEKEY_FILEPATH, "\" -out \"", this.CSR_FILEPATH, "\"" }; if (this.RunOpenSslWithArguments(string.Concat(textArray1)) == 0) { string[] textArray2 = new string[] { "rsa -in \"", this.PRIVATEKEY_FILEPATH, "\" -out \"", this.PUBLICKEY_FILEPATH, "\" -pubout -outform PEM" }; if (this.RunOpenSslWithArguments(string.Concat(textArray2)) == 0) { string CSRKey = File.ReadAllText(this.CSR_FILEPATH); string PrivateKey = File.ReadAllText(this.PRIVATEKEY_FILEPATH); string PublicKey = File.ReadAllText(this.PUBLICKEY_FILEPATH); MessageBox.Show("The certificate request was successfully generated"); } }
OpenSSL调用封装代码
private int RunOpenSslWithArguments(string args) { int exitCode; string path = @"C:\Program Files\OpenSSL-Win64\bin\openssl.exe"; if (!Environment.Is64BitOperatingSystem) { path = @"C:\Program Files\OpenSSL-Win32\bin\openssl.exe"; } if (!File.Exists(path)) { MessageBox.Show("The path to the certificate request generation tool is not valid" ); exitCode = -1; } else { System.Diagnostics.Process process = new System.Diagnostics.Process { StartInfo = { WindowStyle =System.Diagnostics.ProcessWindowStyle.Hidden, CreateNoWindow = true, UseShellExecute = false, FileName = path, Arguments = args } }; process.Start(); process.WaitForExit(); exitCode = process.ExitCode; } return exitCode; }
Section 1 标准公钥示例
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAph0TLX18fyIdj5e52yT1 rC1REhkotx5zKCbwMm0lKAjWEFDbDK6weNGBEnlIekS6h8wez7GHr65GckWqLPn0 9XqmMuVkXaBQFLhben+KC/j9Z89QZE4wE7PcOuUqzx8ZvfiTo2d1C89lYFuVS5xe /RSL8YzqK2TpPm37j0TUXCOv8t4l5T7iZZsye9UxgqYXebBesCnM94GOUvoLvcTh cRAMnsDKm9uXEh3/jzRZf6s0mUbSaqnoArUZwi+Ndao6h0MNVrH7vFMV4Ierznr9 5RPCMBh3n+rVlYAETU5FpMgRNbDk7s0E7ruX4QSl/WlhXoE75m2JZegzvQAqaCgI LwIDAQAB -----END PUBLIC KEY----- *451 characters with 9 lines*
2. MAUI Android的实现代码及非标准公钥示例
生成逻辑代码
public static void GenerateKeys() { using (RSA rsa = RSA.Create(2048)) { // Export the private key var privateKey = rsa.ExportRSAPrivateKey(); var privateKeyPem = $"-----BEGIN PRIVATE KEY-----\n{Convert.ToBase64String(privateKey, Base64FormattingOptions.InsertLineBreaks)}\n-----END PRIVATE KEY-----"; // Export the public key var publicKey = rsa.ExportRSAPublicKey(); var publicKeyPem = $"-----BEGIN PUBLIC KEY-----\n{Convert.ToBase64String(publicKey, Base64FormattingOptions.InsertLineBreaks)}\n-----END PUBLIC KEY-----"; Console.WriteLine("Private Key:\n" + privateKeyPem); Console.WriteLine("Public Key:\n" + publicKeyPem); } }
Section 2 非标准公钥示例
-----BEGIN PUBLIC KEY----- MIIBCgKCAQEAyTF/BTWz7BfvJwspprK22sVljBA1AcRBbCgpQUeyMBZtl4GDmgHs0IhTLRembdC/ alVNYbZqv6v3ptorTnUp2MfuI3Ffd0kge3X7yKWH3FUz/wXnu2hzJTd7Jf8NTCq429YgrVlE45Y5 GsKithqUZI9tMDyY/v76b7l6fHKkfRU/Mp3YuvcaRfqy7P7jzBXo69sB9qRPwg4Qn1XxwPCot4br qF+xcekPb+N4lOEKKiepDg/8MEuyeJ6j1pfnzeL1ZtnMJLiAwq7lCn3mwt3qux1OIzlDbEGVExoT sin3wWdB5KGDmoz8LqIgrq+UjmkNCT/ptbCsLJ+ZFAPksNClrwIDAQAB -----END PUBLIC KEY----- *419 characters with 8 lines*
解决方案
格式差异原因
OpenSSL的rsa -pubout命令默认导出的是PKCS#8格式的公钥(即SubjectPublicKeyInfo结构,包含完整的ASN.1包装);而MAUI代码中使用的ExportRSAPublicKey()方法导出的是PKCS#1格式的原始RSA公钥(仅包含模数和指数,无外层包装),因此两者的Base64内容长度和分行数不一致。
修改MAUI代码实现匹配
将公钥导出方法替换为ExportSubjectPublicKeyInfo(),该方法会导出完整的PKCS#8格式公钥,与OpenSSL生成的格式完全一致。同时如果需要私钥格式也匹配,需将私钥导出方法替换为ExportPkcs8PrivateKey()(OpenSSL生成的私钥为PKCS#8格式)。
修改后的MAUI代码:
public static void GenerateKeys() { using (RSA rsa = RSA.Create(2048)) { // 导出PKCS#8格式私钥,匹配OpenSSL生成的私钥格式 var privateKey = rsa.ExportPkcs8PrivateKey(); var privateKeyPem = $"-----BEGIN PRIVATE KEY-----\n{Convert.ToBase64String(privateKey, Base64FormattingOptions.InsertLineBreaks)}\n-----END PRIVATE KEY-----"; // 导出PKCS#8格式公钥,匹配OpenSSL生成的公钥格式 var publicKey = rsa.ExportSubjectPublicKeyInfo(); var publicKeyPem = $"-----BEGIN PUBLIC KEY-----\n{Convert.ToBase64String(publicKey, Base64FormattingOptions.InsertLineBreaks)}\n-----END PUBLIC KEY-----"; Console.WriteLine("Private Key:\n" + privateKeyPem); Console.WriteLine("Public Key:\n" + publicKeyPem); } }
修改后生成的公钥会和Section 1示例一致:包含完整的ASN.1头部,总字符数约451,分为9行。
内容的提问来源于stack exchange,提问作者Mehdi Agazadeh
相关产品推荐
相关产品推荐

