You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 18:42:32