SoFunction
Updated on 2025-03-02

c# RSA asymmetric encryption and decryption and XML&PEM format interchange scheme

Recently, due to the consideration of interface security, I have implemented a unified parameter authentication function for the WEB API to prevent requested parameters from being tampered with or repeated execution. The parameter authentication method is basically the same as the common authentication idea, and uses (timestamp+sign). In order to prevent timestamp from being changed, the sign algorithm (timestamp+related parameter sorting, formatting and splicing and MD5) is also unsafe in the front-end, so the timestamp is used to use asymmetric encryption and decryption to ensure that the generated sign is not easy to be cracked or replaced as much as possible;

RSA encryption and decryption (ie: asymmetric encryption and decryption)

Generate public and private key pair methods (C#). After generation, they are all in XML format by default:

    public static Tuple<string, string> GeneratePublicAndPrivateKeyPair()
    {
      using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
      {
        string publicKey = (false); // Public key        string privateKey = (true); // Private key
        return (publicKey, privateKey);
      }
    }

Use public key encryption: (Stage encryption is supported, ordinary single encryption may cause errors due to too long content)

public static string RSAEncrypt(string publicKey, string rawInput)
    {
      if ((rawInput))
      {
        return ;
      }

      if ((publicKey))
      {
        throw new ArgumentException("Invalid Public Key");
      }

      using (var rsaProvider = new RSACryptoServiceProvider())
      {
        var inputBytes = Encoding.(rawInput);//Convert meaningful strings into byte streams        (publicKey);//Load the public key        int bufferSize = ( / 8) - 11;//Maximum length of a single block        var buffer = new byte[bufferSize];
        using (MemoryStream inputStream = new MemoryStream(inputBytes),
           outputStream = new MemoryStream())
        {
          while (true)
          { //Segmented encryption            int readSize = (buffer, 0, bufferSize);
            if (readSize <= 0)
            {
              break;
            }

            var temp = new byte[readSize];
            (buffer, 0, temp, 0, readSize);
            var encryptedBytes = (temp, false);
            (encryptedBytes, 0, );
          }
          return Convert.ToBase64String(());//Convert to byte stream for easy transmission        }
      }
    }

Use private key to decrypt: (Sectional decryption is supported, ordinary single-time decryption may cause errors due to the long ciphertext)

 public static string RSADecrypt(string privateKey,string encryptedInput)
    {
      if ((encryptedInput))
      {
        return ;
      }

      if ((privateKey))
      {
        throw new ArgumentException("Invalid Private Key");
      }

      using (var rsaProvider = new RSACryptoServiceProvider())
      {
        var inputBytes = Convert.FromBase64String(encryptedInput);
        (privateKey);
        int bufferSize =  / 8;
        var buffer = new byte[bufferSize];
        using (MemoryStream inputStream = new MemoryStream(inputBytes),
           outputStream = new MemoryStream())
        {
          while (true)
          {
            int readSize = (buffer, 0, bufferSize);
            if (readSize <= 0)
            {
              break;
            }

            var temp = new byte[readSize];
            (buffer, 0, temp, 0, readSize);
            var rawBytes = (temp, false);
            (rawBytes, 0, );
          }
          return Encoding.(());
        }
      }
    }

If it is all C# projects, it may be as follows. However, if you need to cooperate with other programming languages ​​such as WEB front-end and JAVA (for example, WEB front-end is encrypted with public keys and decrypted with the back-end C# private key), it may be impossible to connect normally because the formats of the public key and private keys are different. [The front-end, JAVA and other languages ​​use PEM format, while C# uses XML format]. When searching for XML to PEM format schemes online, they are copied from:/micenote/p/In this article, but in fact, this article only wrote about private key XML to PEM format, and did not explain how public key XML to PEM format, and only wrote about supporting content acquisition from the file and then converting it. The solution is incomplete, but it gave me ideas. After various verifications, I finally realized the more friendly mutual conversion method of PEM and XML formats, and it has been verified by unit tests. I will share it with you here.

The following is the complete XML and PEM format converter code; (Note that the BouncyCastle nuget package needs to be introduced)

using ;
using ;
using ;
using System;
using ;
using ;
using ;
using ;
using ;
using ;

namespace 
{
  /// &lt;summary&gt;
  /// RSA public key and private key pair format (XML and PEM) converter  /// author:zuowenjun
  /// date:2020-12-29
  /// &lt;/summary&gt;
  public static class RsaKeysFormatConverter
  {
    /// &lt;summary&gt;
    /// Convert XML public key to Pem public key    /// &lt;/summary&gt;
    /// &lt;param name="xmlPublicKey"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public static string XmlPublicKeyToPem(string xmlPublicKey)
    {
      RSAParameters rsaParam;
      using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
      {
        (xmlPublicKey);
        rsaParam = (false);
      }
      RsaKeyParameters param = new RsaKeyParameters(false, new BigInteger(1, ), new BigInteger(1, ));

      string pemPublicKeyStr = null;
      using (var ms = new MemoryStream())
      {
        using (var sw = new StreamWriter(ms))
        {
          var pemWriter = new (sw);
          (param);
          ();

          byte[] buffer = new byte[];
           = 0;
          (buffer, 0, (int));
          pemPublicKeyStr = Encoding.(buffer);
        }
      }

      return pemPublicKeyStr;
    }

    /// &lt;summary&gt;
    /// Convert Pem public key to XML public key    /// &lt;/summary&gt;
    /// &lt;param name="pemPublicKeyStr"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public static string PemPublicKeyToXml(string pemPublicKeyStr)
    {
      RsaKeyParameters pemPublicKey;
      using (var ms = new MemoryStream(Encoding.(pemPublicKeyStr)))
      {
        using (var sr = new StreamReader(ms))
        {
          var pemReader = new (sr);
          pemPublicKey = (RsaKeyParameters)();
        }
      }

      var p = new RSAParameters
      {
        Modulus = (),
        Exponent = ()
      };

      string xmlPublicKeyStr;
      using (var rsa = new RSACryptoServiceProvider())
      {
        (p);
        xmlPublicKeyStr = (false);
      }

      return xmlPublicKeyStr;
    }

    /// &lt;summary&gt;
    /// Convert XML private key to PEM private key    /// &lt;/summary&gt;
    /// &lt;param name="xmlPrivateKey"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public static string XmlPrivateKeyToPem(string xmlPrivateKey)
    {
      RSAParameters rsaParam;
      using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
      {
        (xmlPrivateKey);
        rsaParam = (true);
      }

      var param = new RsaPrivateCrtKeyParameters(
        new BigInteger(1, ), new BigInteger(1, ), new BigInteger(1, ),
        new BigInteger(1, ), new BigInteger(1, ), new BigInteger(1, ), new BigInteger(1, ),
        new BigInteger(1, ));

      string pemPrivateKeyStr = null;
      using (var ms = new MemoryStream())
      {
        using (var sw = new StreamWriter(ms))
        {
          var pemWriter = new (sw);
          (param);
          ();

          byte[] buffer = new byte[];
           = 0;
          (buffer, 0, (int));
          pemPrivateKeyStr = Encoding.(buffer);
        }
      }

      return pemPrivateKeyStr;
    }

    /// &lt;summary&gt;
    /// Convert Pem private key to XML private key    /// &lt;/summary&gt;
    /// &lt;param name="pemPrivateKeyStr"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public static string PemPrivateKeyToXml(string pemPrivateKeyStr)
    {
      RsaPrivateCrtKeyParameters pemPrivateKey;
      using (var ms = new MemoryStream(Encoding.(pemPrivateKeyStr)))
      {
        using (var sr = new StreamReader(ms))
        {
          var pemReader = new (sr);
          var keyPair = (AsymmetricCipherKeyPair)();
          pemPrivateKey = (RsaPrivateCrtKeyParameters);
        }
      }

      var p = new RSAParameters
      {
        Modulus = (),
        Exponent = (),
        D = (),
        P = (),
        Q = (),
        DP = (),
        DQ = (),
        InverseQ = (),
      };

      string xmlPrivateKeyStr;
      using (var rsa = new RSACryptoServiceProvider())
      {
        (p);
        xmlPrivateKeyStr = (true);
      }

      return xmlPrivateKeyStr;
    }

  }
}

The following is the unit test code:

//Public key (XML, PEM format mutual) teststring srcPublicKey = “SpecificXML Public Key”;
      string pemPublicKeyStr= (publicKey);
      string xmlPublicKeyStr= (pemPublicKeyStr);
      (srcPublicKey, xmlPublicKeyStr);
//Private key (XML, PEM format mutual) teststring srcPrivateKey = “SpecificXML Private Key”;
      string pemPrivateKeyStr = (srcPrivateKey);
      string xmlPrivateKeyStr = (pemPrivateKeyStr);
      (privateKey,xmlPrivateKeyStr)

Of course, you can also do so without having to do so much effort to implement the format conversion yourself. You can use the online website to convert directly:/certificate/, There is also an article that implements similar functions, but the generated PEM format is not a complete format, and there is a lack of comments:/datous/p/

The above is the detailed content of c# RSA asymmetric encryption and decryption and XML&PEM format interchange scheme. For more information about c# RSA asymmetric encryption and decryption, please pay attention to my other related articles!