.Net Core下使用 RSA 加解密的注意事项

.Net Core 下,以前的RSA加密解密的API有较大的改变,这里记录下 使用过程中的一些区别.

要进行.Net Core下的RSA相关操作, 要用到以下几个包:


    
    

  • RSACryptoServiceProvider
    在Windows 环境下依然可以使用RSACryptoServiceProvider, 但在Linux 环境下编译不过. 参考 dudu 的文章 .net core中使用openssl的公钥私钥进行加解密

  • FromXmlString方法和ToXmlString
    由于不在使用RSACryptoServiceProvider这两个方法不在提供,我们可以通过扩展方法来添加这两个方法,以处理C#生成的密钥.

相关代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Xml;

namespace demo
{
    public class RsaDemo
    {
        #region Fields
        private const string PubKeyXML="yuW8mDcb1+n/fIKqNaT3LQ3qsKNBg4GC7ZD2KXEJqMOyk5x8JOgwgg3mwnie1LfqryzYHSIJLjxR35WznjrCBT+p07IkitGCPY6JuNI/w1KmaoPueb8V/j8YvPQEs6UIXgj/PJdsw1xPgzIxZj9fyxnXOTqbIee4bTOkT28610yKjiq/90dGvWFRmFWPhjTlet02Dt4Qe0nrK/DMCw2dIIcBqrAJyQCMa8dKObbx0Q7+32X71MB3IyzCWZWou8xMBNAxbIYF3Yu6zjLmcBjWpLAAud3tHp72XJ27sNSfZNR1x4Liqo9NnjOivuRnxIxwCpexBh42Qsfx7JSm3aKeZQ==AQAB";
        private const string PrivKeyXml="yuW8mDcb1+n/fIKqNaT3LQ3qsKNBg4GC7ZD2KXEJqMOyk5x8JOgwgg3mwnie1LfqryzYHSIJLjxR35WznjrCBT+p07IkitGCPY6JuNI/w1KmaoPueb8V/j8YvPQEs6UIXgj/PJdsw1xPgzIxZj9fyxnXOTqbIee4bTOkT28610yKjiq/90dGvWFRmFWPhjTlet02Dt4Qe0nrK/DMCw2dIIcBqrAJyQCMa8dKObbx0Q7+32X71MB3IyzCWZWou8xMBNAxbIYF3Yu6zjLmcBjWpLAAud3tHp72XJ27sNSfZNR1x4Liqo9NnjOivuRnxIxwCpexBh42Qsfx7JSm3aKeZQ==AQAB

5LPiWxYbwHe/i/IRKJ84B5PrSPdtPqn1Uj/FUu+4ZMpNw3UEyt0u73MLgXLjwCrx7A484cLS4el5z0eOBAnjw2d1Hm6E/jh8sH5zQHv7u1rFefUMYRMYXSqirTVlj226ccFRE9OZ3lKPuXrodappqNstjlprV1AMDxfLHA1aUXs=

4x1cWbomvGv8JKlginM9GN0sTcM2BeO961dE2K/zBN5CnmW3um7PvDHyb+ntYYoOaW1lx8V/TB3X5w6ywsMiZhe5uXmqiSWaj8vGAyJ+NM+K2AgHDcEqLFUiyTJ/XkqV2k7iMcSLuRO738OECeC/bEu3HGoGGryJWuEC+fEvGZ8=B0Bk5vp2es3RNwC/5ofV4PehuDiQMDJ3Yto+yXhsYlW/zXjCZCRLPrBpJvubmRZDgXaaG5Zv1VXv1NCyAhLGNAXtwr9CXEUyPu5jfSHxQ2mHZWyNre5LEXkum0tcIwYZqU214mkNMe1wPTNWd5SlsQLyGNdpG+Wf3EKm4AbUXE0=Ea8klLwA7iT+YiBqKv2kIT5/h6KOn1DHZf7KlpDEvHlN+KV08+hS9pVxCjPNzw1/58ej6DVBnzynpg8n7jBhik+In5+QntM1wMKeLXpPF2+doQqm+fQzg3Yxmjb7Ye0u0+vWgweJ1aRquZawvlAot5cBsA21YfmSPGhO4gVcpIM=bSssYm1rAcXrZ3G9gDki8Qj0HUUXRrjNJCK2QTHhU5cGY5yiyQE+JVkHOkteKDEaGhaMbGj9cn4D6x22FVV6F9zx+L1RFfrtJpdD9/iYKll6nD3HzpSQ+3AoSE8R8e6bQEWlioW8dICm4A1Acaj7kJyJw1JpJKfjnRrsr05dnQI=KB+GTBOZzfjYLScpwbH9r0sxPf0K15ak7ZXdGBTidB0/EzG+2w2Piih1mb+AqVA1eK7Fjf1NE3eaOTzBaGj2NVOBoft4fnsv5jxpv8LUGSwe/LFaV3kSQFT572PSCjR4kx/0WWcYewmmL6udWTrvFprllMuiIfJQ5kdwFsVIPYrrN7D2A6FOyVuXmmr1DW6+6E/MUjvOWA2UBf4VeybQRsjekaD2ckIM0UK/7+8CWIoNtUzK2ZJ1oqyOk5oVk8Ja0VI3AZSZL1s5Xx/estVZfpmtVGg20T21yXZ7PREpcZQxK67ywNFm12dreZw8sByVvLGKazJfGtijSfHadEPngQ==
"; #endregion #region Methods public byte[] Encrypt(byte[] input) { Func encrypt = sou => { using (var rsa = RSA.Create()) { rsa.FromXmlString(PubKeyXML); int maxBlockSize = rsa.KeySize / 8 - 11; if (sou.Length <= maxBlockSize) { return rsa.Encrypt(sou, RSAEncryptionPadding.Pkcs1); } using (MemoryStream plaiStream = new MemoryStream(sou)) { using (MemoryStream crypStream = new MemoryStream()) { byte[] buffer = new byte[maxBlockSize]; int blockSize = plaiStream.Read(buffer, 0, maxBlockSize); while (blockSize > 0) { byte[] toEncrypt = new byte[blockSize]; Array.Copy(buffer, 0, toEncrypt, 0, blockSize); byte[] cryptograph = rsa.Encrypt(toEncrypt, RSAEncryptionPadding.Pkcs1); crypStream.Write(cryptograph, 0, cryptograph.Length); blockSize = plaiStream.Read(buffer, 0, maxBlockSize); } return crypStream.ToArray(); } } } }; return MarkData(encrypt(input)); } public byte[] Decrypt(byte[] input) { if (IsEncrypt(input)) { Func decrypt = sou => { using (var rsa = RSA.Create()) { rsa.FromXmlString(PrivKeyXml); int maxBlockSize = rsa.KeySize / 8; if (sou.Length <= maxBlockSize) return rsa.Decrypt(sou, RSAEncryptionPadding.Pkcs1); using (MemoryStream crypStream = new MemoryStream(sou)) { using (MemoryStream plaiStream = new MemoryStream()) { byte[] buffer = new byte[maxBlockSize]; int blockSize = crypStream.Read(buffer, 0, maxBlockSize); while (blockSize > 0) { byte[] toDecrypt = new byte[blockSize]; Array.Copy(buffer, 0, toDecrypt, 0, blockSize); byte[] plaintext = rsa.Decrypt(toDecrypt, RSAEncryptionPadding.Pkcs1); plaiStream.Write(plaintext, 0, plaintext.Length); blockSize = crypStream.Read(buffer, 0, maxBlockSize); } return plaiStream.ToArray(); } } } }; return decrypt(ClearDataMark(input)); } return input; } #endregion #region Utilities private byte[] MarkData(byte[] input) { byte[] newBytes = new byte[input.Length + 200]; for (int i = 0; i < newBytes.Length; i++) { if (i < 100 || i > newBytes.Length - 100 - 1) { newBytes[i] = 0; } else { newBytes[i] = input[i - 100]; } } return newBytes; } private byte[] ClearDataMark(byte[] input) { byte[] newBytes = new byte[input.Length - 200]; for (int i = 100; i < input.Length - 100; i++) { newBytes[i - 100] = input[i]; } return newBytes; } private bool IsEncrypt(byte[] input) { for (int i = 0; i < 100; i++) { if (input[i] != 0 || input[input.Length - i - 1] != 0) { return false; } } return true; } #endregion } }

RSA扩展方法

using System;
using System.IO;
using System.Security.Cryptography;
using System.Xml;

namespace demo
{
    public static class RsaExtention
    {

        public static void FromXmlString(this RSA rsa, string xmlString)
        {
            RSAParameters parameters = new RSAParameters();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xmlString);
            if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
            {
                foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
                {
                    switch (node.Name)
                    {
                        case "Modulus": parameters.Modulus = Convert.FromBase64String(node.InnerText); break;
                        case "Exponent": parameters.Exponent = Convert.FromBase64String(node.InnerText); break;
                        case "P": parameters.P = Convert.FromBase64String(node.InnerText); break;
                        case "Q": parameters.Q = Convert.FromBase64String(node.InnerText); break;
                        case "DP": parameters.DP = Convert.FromBase64String(node.InnerText); break;
                        case "DQ": parameters.DQ = Convert.FromBase64String(node.InnerText); break;
                        case "InverseQ": parameters.InverseQ = Convert.FromBase64String(node.InnerText); break;
                        case "D": parameters.D = Convert.FromBase64String(node.InnerText); break;
                    }
                }
            }
            else
            {
                throw new Exception("Invalid XML RSA key.");
            }

            rsa.ImportParameters(parameters);
        }

        public static string ToXmlString(this RSA rsa, bool includePrivateParameters)
        {
            RSAParameters parameters = rsa.ExportParameters(includePrivateParameters);

            if (includePrivateParameters)
            {
                return string.Format("{0}{1}

{2}

{3}{4}{5}{6}{7}
", Convert.ToBase64String(parameters.Modulus), Convert.ToBase64String(parameters.Exponent), Convert.ToBase64String(parameters.P), Convert.ToBase64String(parameters.Q), Convert.ToBase64String(parameters.DP), Convert.ToBase64String(parameters.DQ), Convert.ToBase64String(parameters.InverseQ), Convert.ToBase64String(parameters.D)); } return string.Format("{0}{1}", Convert.ToBase64String(parameters.Modulus), Convert.ToBase64String(parameters.Exponent)); } } }
  • RNGCryptoServiceProvider
    如果以前代码使用RNGCryptoServiceProvider 来生成随机盐值,.Net Core中不在提供该方法,可以使用 RandomNumberGenerator方法替代.
// old
public virtual string CreateSaltKey(int size)
{
    //generate a cryptographic random number
    using (var provider = new RNGCryptoServiceProvider())
    {
        var buff = new byte[size];
        provider.GetBytes(buff);

        // Return a Base64 string representation of the random number
        return Convert.ToBase64String(buff);
    }
}
//new
public virtual string CreateSaltKey(int size)
{
    //generate a cryptographic random number
    using (var random = RandomNumberGenerator.Create())
    {
        var buff = new byte[size];
        random.GetBytes(buff);

        // Return a Base64 string representation of the random number
        return Convert.ToBase64String(buff);
    }
}

相关链接

  • 文中大部分代码来自:ZKEACMS
  • C#中使用OpenSSL的公钥加密/私钥解密
  • .net core中使用openssl的公钥私钥进行加解密

你可能感兴趣的:(.Net Core下使用 RSA 加解密的注意事项)