.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);
    }
}            
复制代码

 

 

相关链接

posted @   -YOZE-  阅读(804)  评论(0编辑  收藏  举报
编辑推荐:
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
· 你所不知道的 C/C++ 宏知识
阅读排行:
· 不到万不得已,千万不要去外包
· C# WebAPI 插件热插拔(持续更新中)
· 会议真的有必要吗?我们产品开发9年了,但从来没开过会
· 【译】我们最喜欢的2024年的 Visual Studio 新功能
· 如何打造一个高并发系统?
点击右上角即可分享
微信分享提示