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

.Net Core 下,以前的RSA加密解密的API有較大的改變,這里記錄下 使用過程中的一些區(qū)別.

要進行.Net Core下的RSA相關操作, 要用到以下幾個包:

<ItemGroup>
    <PackageReference Include="System.Security.Cryptography.Csp" Version="4.3.0" />
    <PackageReference Include="System.Security.Cryptography.Algorithms" Version="4.3.0" />
</ItemGroup>
  • RSACryptoServiceProvider
    在Windows 環(huán)境下依然可以使用RSACryptoServiceProvider, 但在Linux 環(huán)境下編譯不過. 參考 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="<RSAKeyValue><Modulus>yuW8mDcb1+n/fIKqNaT3LQ3qsKNBg4GC7ZD2KXEJqMOyk5x8JOgwgg3mwnie1LfqryzYHSIJLjxR35WznjrCBT+p07IkitGCPY6JuNI/w1KmaoPueb8V/j8YvPQEs6UIXgj/PJdsw1xPgzIxZj9fyxnXOTqbIee4bTOkT28610yKjiq/90dGvWFRmFWPhjTlet02Dt4Qe0nrK/DMCw2dIIcBqrAJyQCMa8dKObbx0Q7+32X71MB3IyzCWZWou8xMBNAxbIYF3Yu6zjLmcBjWpLAAud3tHp72XJ27sNSfZNR1x4Liqo9NnjOivuRnxIxwCpexBh42Qsfx7JSm3aKeZQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
        private const string PrivKeyXml="<RSAKeyValue><Modulus>yuW8mDcb1+n/fIKqNaT3LQ3qsKNBg4GC7ZD2KXEJqMOyk5x8JOgwgg3mwnie1LfqryzYHSIJLjxR35WznjrCBT+p07IkitGCPY6JuNI/w1KmaoPueb8V/j8YvPQEs6UIXgj/PJdsw1xPgzIxZj9fyxnXOTqbIee4bTOkT28610yKjiq/90dGvWFRmFWPhjTlet02Dt4Qe0nrK/DMCw2dIIcBqrAJyQCMa8dKObbx0Q7+32X71MB3IyzCWZWou8xMBNAxbIYF3Yu6zjLmcBjWpLAAud3tHp72XJ27sNSfZNR1x4Liqo9NnjOivuRnxIxwCpexBh42Qsfx7JSm3aKeZQ==</Modulus><Exponent>AQAB</Exponent><P>5LPiWxYbwHe/i/IRKJ84B5PrSPdtPqn1Uj/FUu+4ZMpNw3UEyt0u73MLgXLjwCrx7A484cLS4el5z0eOBAnjw2d1Hm6E/jh8sH5zQHv7u1rFefUMYRMYXSqirTVlj226ccFRE9OZ3lKPuXrodappqNstjlprV1AMDxfLHA1aUXs=</P><Q>4x1cWbomvGv8JKlginM9GN0sTcM2BeO961dE2K/zBN5CnmW3um7PvDHyb+ntYYoOaW1lx8V/TB3X5w6ywsMiZhe5uXmqiSWaj8vGAyJ+NM+K2AgHDcEqLFUiyTJ/XkqV2k7iMcSLuRO738OECeC/bEu3HGoGGryJWuEC+fEvGZ8=</Q><DP>B0Bk5vp2es3RNwC/5ofV4PehuDiQMDJ3Yto+yXhsYlW/zXjCZCRLPrBpJvubmRZDgXaaG5Zv1VXv1NCyAhLGNAXtwr9CXEUyPu5jfSHxQ2mHZWyNre5LEXkum0tcIwYZqU214mkNMe1wPTNWd5SlsQLyGNdpG+Wf3EKm4AbUXE0=</DP><DQ>Ea8klLwA7iT+YiBqKv2kIT5/h6KOn1DHZf7KlpDEvHlN+KV08+hS9pVxCjPNzw1/58ej6DVBnzynpg8n7jBhik+In5+QntM1wMKeLXpPF2+doQqm+fQzg3Yxmjb7Ye0u0+vWgweJ1aRquZawvlAot5cBsA21YfmSPGhO4gVcpIM=</DQ><InverseQ>bSssYm1rAcXrZ3G9gDki8Qj0HUUXRrjNJCK2QTHhU5cGY5yiyQE+JVkHOkteKDEaGhaMbGj9cn4D6x22FVV6F9zx+L1RFfrtJpdD9/iYKll6nD3HzpSQ+3AoSE8R8e6bQEWlioW8dICm4A1Acaj7kJyJw1JpJKfjnRrsr05dnQI=</InverseQ><D>KB+GTBOZzfjYLScpwbH9r0sxPf0K15ak7ZXdGBTidB0/EzG+2w2Piih1mb+AqVA1eK7Fjf1NE3eaOTzBaGj2NVOBoft4fnsv5jxpv8LUGSwe/LFaV3kSQFT572PSCjR4kx/0WWcYewmmL6udWTrvFprllMuiIfJQ5kdwFsVIPYrrN7D2A6FOyVuXmmr1DW6+6E/MUjvOWA2UBf4VeybQRsjekaD2ckIM0UK/7+8CWIoNtUzK2ZJ1oqyOk5oVk8Ja0VI3AZSZL1s5Xx/estVZfpmtVGg20T21yXZ7PREpcZQxK67ywNFm12dreZw8sByVvLGKazJfGtijSfHadEPngQ==</D></RSAKeyValue>";
        #endregion

        #region Methods
        public byte[] Encrypt(byte[] input)
        {
            Func<byte[], byte[]> 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<byte[], byte[]> 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("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
                    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("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
                    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);
    }
}

相關鏈接

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子乎澄,更是在濱河造成了極大的恐慌赫舒,老刑警劉巖林束,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件管宵,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜓谋,警方通過查閱死者的電腦和手機区匣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門偷拔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人亏钩,你說我怎么就攤上這事莲绰。” “怎么了姑丑?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵蛤签,是天一觀的道長。 經(jīng)常有香客問我栅哀,道長震肮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任留拾,我火速辦了婚禮戳晌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘痴柔。我一直安慰自己沦偎,他們只是感情好,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布咳蔚。 她就那樣靜靜地躺著扛施,像睡著了一般。 火紅的嫁衣襯著肌膚如雪屹篓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天匙奴,我揣著相機與錄音堆巧,去河邊找鬼。 笑死,一個胖子當著我的面吹牛谍肤,可吹牛的內(nèi)容都是我干的啦租。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼荒揣,長吁一口氣:“原來是場噩夢啊……” “哼篷角!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起系任,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤恳蹲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后俩滥,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嘉蕾,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年霜旧,在試婚紗的時候發(fā)現(xiàn)自己被綠了错忱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡挂据,死狀恐怖以清,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情崎逃,我是刑警寧澤掷倔,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站婚脱,受9級特大地震影響今魔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜障贸,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一错森、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧篮洁,春花似錦涩维、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至篷牌,卻和暖如春睡蟋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背枷颊。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工戳杀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留该面,地道東北人。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓信卡,卻偏偏與公主長得像隔缀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子傍菇,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容