为了账号安全,请及时绑定邮箱和手机立即绑定

C#将私有/公共RSA密钥从RSACryptoServiceProvider导出到PEM字符串

C#将私有/公共RSA密钥从RSACryptoServiceProvider导出到PEM字符串

C#
侃侃无极 2019-11-28 14:16:05
我有一个System.Security.Cryptography.RSACryptoServiceProvider的实例,我需要将它的密钥导出到PEM字符串-像这样:-----BEGIN RSA PRIVATE KEY-----MIICXAIBAAKBgQDUNPB6Lvx+tlP5QhSikADl71AjZf9KN31qrDpXNDNHEI0OTVJ1OaP2l56bSKNo8trFne1NK/B4JzCuNP8x6oGCAG+7bFgkbTMzV2PCoDCRjNH957Q4Gxgx1VoS6PjD3OigZnx5b9Hebbp3OrTuqNZaK/oLPGr5swxHILFVeHKupQIDAQABAoGAQk3MOZEGyZy0fjQ8eFKgRTfSBU1wR8Mwx6zKicbAotq0CBz2v7Pj3D+higlXLYp7+rUOmUc6WoB8QGJEvlb0YZVxUg1yDLMWYPE7ddsHsOkBIs7zIyS6cqhn0yZDVTRFjVST/EduvpUOL5hbyLSwuq+rbv0iPwGW5hkCHNEhx2ECQQDfLS5549wjiFXFgcio8g715eMT+20we3YmgMJDcviMGwN/mArvnBgBQsFtCTsMoOxm68SfIrBYlKYyBsFxn+19AkEA82q83pmcbGJRJ3ZMC/Pv+/+/XNFOvMkfT9qbuA6Lv69Z1yk7I1ieFTH6tOmPUu4WsIOFtDuYbfV2pvpqx7GuSQJAK3SnvRIyNjUAxoF76fGgGh9WNPjbDPqtSdf+e5Wycc18w+Z+EqPpRK2T7kBC4DWhcnTsBzSA8+6V4d3Q4ugKHQJATRhwa3xxm65kD8CbA2omh0UQQgCVFJwKy8rsaRZKUtLh/JC1h1No9kOXKTeUSmrYSt3NOjFp7OHCy84ihc8T6QJBANe+9xkN9hJYNK1pL1kSwXNuebzcgk3AMwHh7ThvjLgOjruxbM2NyMM5tl9NZCgh1vKc2v5VaonqM1NBQPDeTTw=-----END RSA PRIVATE KEY-----但是根据MSDN文档,没有这种选择,只有某种XML导出。我不能使用BouncyCastle之类的任何第三方库。有什么方法可以产生这个字串吗?
查看完整描述

3 回答

?
ibeautiful

TA贡献1993条经验 获得超5个赞

请注意:以下代码用于导出私钥。如果您要导出公共密钥,请参考我在此处给出的答案。


PEM格式只是转换为Base64 的密钥(按PKCS#1)的ASN.1 DER编码。鉴于表示密钥所需的字段数量有限,创建快捷的DER编码器以输出适当的格式然后进行Base64编码非常简单。因此,下面的代码并不是特别优雅,但是可以做到:


private static void ExportPrivateKey(RSACryptoServiceProvider csp, TextWriter outputStream)

{

    if (csp.PublicOnly) throw new ArgumentException("CSP does not contain a private key", "csp");

    var parameters = csp.ExportParameters(true);

    using (var stream = new MemoryStream())

    {

        var writer = new BinaryWriter(stream);

        writer.Write((byte)0x30); // SEQUENCE

        using (var innerStream = new MemoryStream())

        {

            var innerWriter = new BinaryWriter(innerStream);

            EncodeIntegerBigEndian(innerWriter, new byte[] { 0x00 }); // Version

            EncodeIntegerBigEndian(innerWriter, parameters.Modulus);

            EncodeIntegerBigEndian(innerWriter, parameters.Exponent);

            EncodeIntegerBigEndian(innerWriter, parameters.D);

            EncodeIntegerBigEndian(innerWriter, parameters.P);

            EncodeIntegerBigEndian(innerWriter, parameters.Q);

            EncodeIntegerBigEndian(innerWriter, parameters.DP);

            EncodeIntegerBigEndian(innerWriter, parameters.DQ);

            EncodeIntegerBigEndian(innerWriter, parameters.InverseQ);

            var length = (int)innerStream.Length;

            EncodeLength(writer, length);

            writer.Write(innerStream.GetBuffer(), 0, length);

        }


        var base64 = Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length).ToCharArray();

        outputStream.WriteLine("-----BEGIN RSA PRIVATE KEY-----");

        // Output as Base64 with lines chopped at 64 characters

        for (var i = 0; i < base64.Length; i += 64)

        {

            outputStream.WriteLine(base64, i, Math.Min(64, base64.Length - i));

        }

        outputStream.WriteLine("-----END RSA PRIVATE KEY-----");

    }

}


private static void EncodeLength(BinaryWriter stream, int length)

{

    if (length < 0) throw new ArgumentOutOfRangeException("length", "Length must be non-negative");

    if (length < 0x80)

    {

        // Short form

        stream.Write((byte)length);

    }

    else

    {

        // Long form

        var temp = length;

        var bytesRequired = 0;

        while (temp > 0)

        {

            temp >>= 8;

            bytesRequired++;

        }

        stream.Write((byte)(bytesRequired | 0x80));

        for (var i = bytesRequired - 1; i >= 0; i--)

        {

            stream.Write((byte)(length >> (8 * i) & 0xff));

        }

    }

}


private static void EncodeIntegerBigEndian(BinaryWriter stream, byte[] value, bool forceUnsigned = true)

{

    stream.Write((byte)0x02); // INTEGER

    var prefixZeros = 0;

    for (var i = 0; i < value.Length; i++)

    {

        if (value[i] != 0) break;

        prefixZeros++;

    }

    if (value.Length - prefixZeros == 0)

    {

        EncodeLength(stream, 1);

        stream.Write((byte)0);

    }

    else

    {

        if (forceUnsigned && value[prefixZeros] > 0x7f)

        {

            // Add a prefix zero to force unsigned if the MSB is 1

            EncodeLength(stream, value.Length - prefixZeros + 1);

            stream.Write((byte)0);

        }

        else

        {

            EncodeLength(stream, value.Length - prefixZeros);

        }

        for (var i = prefixZeros; i < value.Length; i++)

        {

            stream.Write(value[i]);

        }

    }

}


查看完整回答
反对 回复 2019-11-28
?
GCT1015

TA贡献1827条经验 获得超4个赞

要导出,请PublicKey使用以下代码:


public static String ExportPublicKeyToPEMFormat(RSACryptoServiceProvider csp)

{

    TextWriter outputStream = new StringWriter();


    var parameters = csp.ExportParameters(false);

    using (var stream = new MemoryStream())

    {

        var writer = new BinaryWriter(stream);

        writer.Write((byte)0x30); // SEQUENCE

        using (var innerStream = new MemoryStream())

        {

            var innerWriter = new BinaryWriter(innerStream);

            EncodeIntegerBigEndian(innerWriter, new byte[] { 0x00 }); // Version

            EncodeIntegerBigEndian(innerWriter, parameters.Modulus);

            EncodeIntegerBigEndian(innerWriter, parameters.Exponent);


            //All Parameter Must Have Value so Set Other Parameter Value Whit Invalid Data  (for keeping Key Structure  use "parameters.Exponent" value for invalid data)

            EncodeIntegerBigEndian(innerWriter, parameters.Exponent); // instead of parameters.D

            EncodeIntegerBigEndian(innerWriter, parameters.Exponent); // instead of parameters.P

            EncodeIntegerBigEndian(innerWriter, parameters.Exponent); // instead of parameters.Q

            EncodeIntegerBigEndian(innerWriter, parameters.Exponent); // instead of parameters.DP

            EncodeIntegerBigEndian(innerWriter, parameters.Exponent); // instead of parameters.DQ

            EncodeIntegerBigEndian(innerWriter, parameters.Exponent); // instead of parameters.InverseQ


            var length = (int)innerStream.Length;

            EncodeLength(writer, length);

            writer.Write(innerStream.GetBuffer(), 0, length);

        }


        var base64 = Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length).ToCharArray();

        outputStream.WriteLine("-----BEGIN PUBLIC KEY-----");

        // Output as Base64 with lines chopped at 64 characters

        for (var i = 0; i < base64.Length; i += 64)

        {

            outputStream.WriteLine(base64, i, Math.Min(64, base64.Length - i));

        }

        outputStream.WriteLine("-----END PUBLIC KEY-----");


        return outputStream.ToString();


    }

}


private static void EncodeIntegerBigEndian(BinaryWriter stream, byte[] value, bool forceUnsigned = true)

{

    stream.Write((byte)0x02); // INTEGER

    var prefixZeros = 0;

    for (var i = 0; i < value.Length; i++)

    {

        if (value[i] != 0) break;

        prefixZeros++;

    }

    if (value.Length - prefixZeros == 0)

    {

        EncodeLength(stream, 1);

        stream.Write((byte)0);

    }

    else

    {

        if (forceUnsigned && value[prefixZeros] > 0x7f)

        {

            // Add a prefix zero to force unsigned if the MSB is 1

            EncodeLength(stream, value.Length - prefixZeros + 1);

            stream.Write((byte)0);

        }

        else

        {

            EncodeLength(stream, value.Length - prefixZeros);

        }

        for (var i = prefixZeros; i < value.Length; i++)

        {

            stream.Write(value[i]);

        }

    }

}


private static void EncodeLength(BinaryWriter stream, int length)

{

    if (length < 0) throw new ArgumentOutOfRangeException("length", "Length must be non-negative");

    if (length < 0x80)

    {

        // Short form

        stream.Write((byte)length);

    }

    else

    {

        // Long form

        var temp = length;

        var bytesRequired = 0;

        while (temp > 0)

        {

            temp >>= 8;

            bytesRequired++;

        }

        stream.Write((byte)(bytesRequired | 0x80));

        for (var i = bytesRequired - 1; i >= 0; i--)

        {

            stream.Write((byte)(length >> (8 * i) & 0xff));

        }

    }

}


查看完整回答
反对 回复 2019-11-28
  • 3 回答
  • 0 关注
  • 1818 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信