.Net Core下使用 RSA
.Net Core 下,以前的RSA加密解密的API有较大的改变,这里记录下 使用过程中的一些区别.
要进行.Net Core下的RSA相关操作, 要用到以下几个包:
< ItemGroup > < PackageReferenceInclude ="System.Security.Cryptography.Csp"Version="4.3.0"/> < PackageReferenceInclude ="System.Security.Cryptography.Algorithms"Version="4.3.0"/> </ ItemGroup > |
-
RSACryptoServiceProvider
在Windows 环境下依然可以使用RSACryptoServiceProvider
, 但在Linux 环境下编译不过. 参考 dudu 的文章 .net core中使用openssl的公钥私钥进行加解密 -
FromXmlString方法和ToXmlString
由于不在使用RSACryptoServiceProvider
这两个方法不在提供,我们可以通过扩展方法来添加这两个方法,以处理C#生成的密钥.
相关代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Xml; namespace libs { public class RsaHelper { #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扩展方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 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 publicvirtualstringCreateSaltKey(int size) { //generate a cryptographic random number using(var provider =newRNGCryptoServiceProvider()) { var buff =newbyte[size]; provider.GetBytes(buff); // Return a Base64 string representation of the random number returnConvert.ToBase64String(buff); } } //new publicvirtualstringCreateSaltKey(int size) { //generate a cryptographic random number using(var random =RandomNumberGenerator.Create()) { var buff =newbyte[size]; random.GetBytes(buff); // Return a Base64 string representation of the random number returnConvert.ToBase64String(buff); } }
相关链接
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
· 你所不知道的 C/C++ 宏知识
· 不到万不得已,千万不要去外包
· C# WebAPI 插件热插拔(持续更新中)
· 会议真的有必要吗?我们产品开发9年了,但从来没开过会
· 【译】我们最喜欢的2024年的 Visual Studio 新功能
· 如何打造一个高并发系统?