计算机网络安全 —— 非对称加密算法 RSA 和数字签名

一、非对称加密算法基本概念 #

​ 在对称密钥系统中,两个参与者要共享同一个秘密密钥。但怎样才能做到这一点呢?一种是事先约定,另一种是用信使来传送 。在高度自动化的大型计算机网络中,用信使来传送密钥显然是不合适的。如果事先约定密钥,就会给密钥的管理和更换都带来了极大的不便。当然我们可以使用复杂的密钥分发中心(KeyDistributionCenter,KDC)来解决该问题,但采用公钥密码体制可以比较容易地解决这个问题。公钥密码体制的概念是由Stanford大学的研究人员Diffie与Hellman于1976年提出的。公钥密码体制使用不同的加密密钥与解密密钥

​ **由于加密密钥不能用来解密,并且从加密密钥不能推导出解密密钥,因此加密密钥可以公开。**例如,参与者A可以在报纸上公布自己的加 密密钥(即公钥),而解密密钥(即私钥)自己秘密保存。任何参与都可以获得该公钥,并用来加密发送给参与者A的信息,而该信息只 能由A解密。可见采用公钥密码体制更易解决密钥分发的问题。

​ **公钥密码体制有许多很好的特性,使得它不仅可以用于加密,还可以很方便地用于鉴别和数字签名。**但不幸的是,目前的公钥密码算法比对称密码算法要慢好几个数量级。因此,对称密码被用于绝大部分加密,而公钥密码则通常用于会话密钥的建立。例如,参与者A要发送 大量秘密信息给B。A首先选择一个用于加密数据本身(如采用DES算法)的密钥,由于该密钥仅用于该次会话,被称为会话密钥。因为对称密钥由双方共享,A必须将该会话密钥通过秘密渠道告知B。为此,A用B的RSA公钥加密该会话密钥后发送给B。B收到加密的会话密 钥后用自己的私钥解密后得到会话密钥。此后,A和B之间就可以用该会话密钥加密通信的数据。具体流程如下图:

二、数字签名的基本概念#

​ 在日常生活中,可以根据亲笔签名或印章来证明书信或文件的真实来源 。但在计算机网络中传送的文电又如何盖章呢?这就是**数字签名(digitalsignature)**所要解决的问题。

​ 数字签名必须保证以下三点:

  1. *接收方能够核实发送方对报文的数字签名;*
  2. *发送方事后不能抵赖对报文的数字签名;*
  3. *任何人包括接收方都不能伪造对报文的签名。*

​ 现在已有多种实现数字签名的方法。但采用公钥算法要比采用对称密钥算法更容易实现。具体流程如下:

我们知道公钥密码算法的计算代价非常大,对整个报文进行数字签名是一件非常耗时的事情。更有效的方法是仅对报文摘要进行数字签名。

上述过程仅对报文进行了签名,对报文X本身却未保密。因为截获DSKA(X)并知道发送方身份的任何人,通过查阅手册即可获得发送方的公钥PKA,因而能得知电文内容。若采用下图所示的方法,则可同时实现秘密通信和数字签名。图中SKA和SKB分别为A和B的私钥,而PKA 和PKB分别为A和B的公钥。具体流程如下:

二、.NET使用 RSA 算法 #

​ RSA 的私钥或者公钥可以由算法自动生成,也可以读取证书生成,同时我们可以使用 RSA 算法完成数字签名,具体代码如下:

复制代码
  1 using System;
  2 using System.IO;
  3 using System.Security.Cryptography;
  4 using System.Security.Cryptography.X509Certificates;
  5 using System.Text;
  6 
  7 namespace encryption.rsa
  8 {
  9     /// <summary>
 10     /// https://cloud.tencent.com/developer/article/1054441
 11     /// </summary>
 12     public class RsaAlgorithm
 13     {
 14         public Encoding Encoding { get; set; }
 15         public string PrivateKey { get;private set; }
 16         public string PublicKey { get;private set; }
 17 
 18         private  RSACryptoServiceProvider _rsa;
 19         private int _keySize;
 20         #region .ctor
 21 
 22         public RsaAlgorithm(int keySize=512)
 23         {
 24             _keySize = keySize;
 25             _rsa = new RSACryptoServiceProvider() { KeySize = _keySize };
 26             Encoding = Encoding.UTF8;
 27             PrivateKey = _rsa.ToXmlString(true);
 28             PublicKey = _rsa.ToXmlString(false);
 29         }
 30 
 31         #endregion
 32 
 33         #region 创建RSA
 34 
 35         /// <summary>
 36         /// 创建加密RSA
 37         /// </summary>
 38         /// <param name="publicKey">公钥</param>
 39         /// <returns></returns>
 40         public  RSACryptoServiceProvider CreateEncryptRSA(string publicKey)
 41         {
 42             try
 43             {
 44                 _rsa = new RSACryptoServiceProvider() { KeySize = _keySize };
 45                 _rsa.FromXmlString(publicKey);
 46                 PublicKey = publicKey;
 47                 PrivateKey = null;
 48                 return _rsa;
 49             }
 50             catch (CryptographicException ex)
 51             {
 52                 throw ex;
 53             }
 54         }
 55 
 56         /// <summary>
 57         /// 根据字符串创建解密RSA
 58         /// </summary>
 59         /// <param name="privateKey">私钥</param>
 60         /// <returns></returns>
 61         public RSACryptoServiceProvider CreateDecryptRSA(string privateKey)
 62         {
 63             try
 64             {
 65                 _rsa = new RSACryptoServiceProvider() { KeySize = _keySize };
 66                 _rsa.FromXmlString(privateKey);
 67                 PublicKey = null;
 68                 PrivateKey = privateKey;
 69                 return _rsa;
 70             }
 71             catch (CryptographicException ex)
 72             {
 73                 throw ex;
 74             }
 75         }
 76 
 77         /// <summary>
 78         /// 根据安全证书创建加密RSA
 79         /// </summary>
 80         /// <param name="certfile">公钥文件</param>
 81         /// <returns></returns>
 82         public RSACryptoServiceProvider X509CertCreateEncryptRSA(string certfile)
 83         {
 84             try
 85             {
 86                 if (File.Exists(certfile)==false)
 87                 {
 88                     throw new ArgumentNullException(certfile, "加密证书未找到");
 89                 }
 90                 X509Certificate2 x509Cert = new X509Certificate2(certfile);
 91                 _rsa = (RSACryptoServiceProvider)x509Cert.PublicKey.Key;
 92                 return _rsa;
 93             }
 94             catch (CryptographicException ex)
 95             {
 96                 throw ex;
 97             }
 98         }
 99 
100         /// <summary>
101         /// 根据私钥文件创建解密RSA
102         /// </summary>
103         /// <param name="keyfile">私钥文件</param>
104         /// <param name="password">访问含私钥文件的密码</param>
105         /// <returns></returns>
106         public RSACryptoServiceProvider X509CertCreateDecryptRSA(string keyfile, string password)
107         {
108             try
109             {
110                 if (File.Exists(keyfile)==false)
111                 {
112                     throw new ArgumentNullException(keyfile, "解密证书未找到");
113                 }
114                 X509Certificate2 x509Cert = new X509Certificate2(keyfile, password);
115                 _rsa = (RSACryptoServiceProvider)x509Cert.PrivateKey;
116                 return _rsa;
117             }
118             catch (CryptographicException ex)
119             {
120                 throw ex;
121             }
122         }
123 
124         #endregion
125 
126 
127         #region 加密
128 
129         /// <summary>
130         /// RSA 加密
131         /// </summary>
132         /// <param name="dataToEncrypt">待加密数据</param>
133         /// <returns></returns>
134         public string Encrypt(string dataToEncrypt)
135         {
136             byte[] bufferBytes = Encoding.GetBytes(dataToEncrypt);
137             return Convert.ToBase64String(this.Encrypt(bufferBytes));
138         }
139 
140         /// <summary>
141         /// RSA 加密
142         /// </summary>
143         /// <param name="dataToEncrypt">待加密数据</param>
144         /// <returns></returns>
145         public byte[] Encrypt(byte[] dataToEncrypt)
146         {
147             byte[] data = null;
148             int blockLen = _rsa.KeySize / 8 - 11;
149             if (dataToEncrypt.Length <= blockLen)
150             {
151                 return _rsa.Encrypt(dataToEncrypt, false);
152             }
153 
154             using (var dataStream = new MemoryStream(dataToEncrypt))
155             using (var enStream = new MemoryStream())
156             {
157                 Byte[] buffer = new Byte[blockLen];
158                 int len = dataStream.Read(buffer, 0, blockLen);
159 
160                 while (len > 0)
161                 {
162                     Byte[] block = new Byte[len];
163                     Array.Copy(buffer, 0, block, 0, len);
164 
165                     Byte[] enBlock = _rsa.Encrypt(block, false);
166                     enStream.Write(enBlock, 0, enBlock.Length);
167 
168                     len = dataStream.Read(buffer, 0, blockLen);
169                 }
170 
171                 data = enStream.ToArray();
172             }
173 
174             return data;
175         }
176 
177         #endregion
178 
179 
180         #region 解密
181 
182         /// <summary>
183         /// RSA 解密
184         /// </summary>
185         /// <param name="encryptedData">待解密数据<see cref="string"/></param>
186         /// <returns></returns>
187         public string Decrypt(string encryptedData)
188         {
189             string str = null;
190             byte[] buffer = Convert.FromBase64String(encryptedData);
191             return Encoding.GetString(this.Decrypt(buffer));
192         }
193 
194         /// <summary>
195         /// RSA 解密
196         /// </summary>
197         /// <param name="encryptedData">待解密数据(byte数组)<see cref="byte"/></param>
198         /// <returns></returns>
199         public byte[] Decrypt(byte[] encryptedData)
200         {
201             byte[] data = null;
202             int blockLen = _rsa.KeySize / 8;
203             if (encryptedData.Length <= blockLen)
204             {
205                 return _rsa.Decrypt(encryptedData, false);
206             }
207 
208             using (var dataStream = new MemoryStream(encryptedData))
209             using (var deStream = new MemoryStream())
210             {
211                 Byte[] buffer = new Byte[blockLen];
212                 int len = dataStream.Read(buffer, 0, blockLen);
213 
214                 while (len > 0)
215                 {
216                     Byte[] block = new Byte[len];
217                     Array.Copy(buffer, 0, block, 0, len);
218 
219                     Byte[] deBlock = _rsa.Decrypt(block, false);
220                     deStream.Write(deBlock, 0, deBlock.Length);
221 
222                     len = dataStream.Read(buffer, 0, blockLen);
223                 }
224 
225                 data = deStream.ToArray();
226             }
227 
228             return data;
229         }
230 
231         #endregion
232 
233         #region 签名与验签
234         /// <summary>
235         ///  RSA 签名
236         /// https://docs.microsoft.com/zh-tw/dotnet/api/system.security.cryptography.rsacryptoserviceprovider.signdata?view=net-5.0
237         /// </summary>
238         /// <param name="hash">报文摘要算法</param>
239         /// <param name="str">报文数据</param>
240         /// <returns></returns>
241         public string Sign(string hash, string str)
242         {
243             byte[] data = Encoding.GetBytes(str);
244             byte[] sign = _rsa.SignData(data, hash);
245             return Convert.ToBase64String(sign);
246         }
247 
248         /// <summary>
249         /// 签名
250         /// </summary>
251         /// <param name="hash">报文摘要算法</param>
252         /// <param name="data">报文数据</param>
253         /// <returns></returns>
254         public string Sign(string hash, byte[] data)
255         {
256             byte[] sign = _rsa.SignData(data, hash);
257             return Convert.ToBase64String(sign);
258         }
259 
260         /// <summary>
261         /// 验签
262         /// </summary>
263         /// <param name="data">报文数据</param>
264         /// <param name="hash">报文摘要算法</param>
265         /// <param name="sign">签名</param>
266         /// <returns></returns>
267         public bool VerifySign(byte[] data, string hash,string sign)
268         {
269             byte[] signBytes = Convert.FromBase64String(sign);
270             return _rsa.VerifyData(data, hash, signBytes);
271         }
272 
273         /// <summary>
274         /// 验签
275         /// </summary>
276         /// <param name="data">报文数据</param>
277         /// <param name="hash">报文摘要算法</param>
278         /// <param name="sign">签名</param>
279         /// <returns></returns>
280         public bool VerifySign(string data, string hash, string sign)
281         {
282             return VerifySign(Encoding.GetBytes(data),hash,sign);
283         }
284         #endregion
285     }
286 }

四、测试代码与效果 #

​ 测试代码如下:

复制代码
 1   static void Main(string[] args)
 2         {
 3             {
 4                 Console.WriteLine("-----------------------------------------------------RSA 字符串加密与解密以及签名与验签--------------------------------------------------");
 5                 var input = "公钥密码体制中,目前最著名的是由美国三位科学家Rivest, Shamir 和 Adleman 于1976年提出,并在1978年正式发表的RSA 算法。";
 6                 Console.Write($"加密内容:{input}\r\n");
 7                 var rsa = new RsaAlgorithm();
 8 
 9                 Console.WriteLine($"RSA私钥:\r\n{rsa.PrivateKey}\r\n");
10                 var encrypt = rsa.Encrypt(input);
11                 Console.WriteLine($"RSA加密后内容:\r\n{encrypt}\r\n");
12                 var sign = rsa.Sign("SHA1", input);
13                 Console.WriteLine($"RSA生成数字签名[SHAI]:\r\n{sign}\r\n");
14 
15                 Console.WriteLine($"RSA公钥:\r\n{rsa.PublicKey}\r\n");
16                 var decrypt = rsa.Decrypt(encrypt);
17                 Console.WriteLine($"RSA解密后内容:\r\n{decrypt}\r\n");
18                 string signResult = rsa.VerifySign(decrypt, "SHA1", sign) ? "验签通过" : "验签未通过";
19                 Console.WriteLine($"RSA进行鉴别数字签名:{signResult}");
20             }
21 
22             {
23                 Console.WriteLine("-----------------------------------------------------RSA 文件加密与解密--------------------------------------------------");
24                 var input = System.IO.File.ReadAllBytes(@"C:\Users\97460\Desktop\1.rar");
25                 Console.Write($"加密内容:{Convert.ToBase64String(input)}\r\n");
26                 var rsa = new RsaAlgorithm(1024);
27 
28                 Console.WriteLine($"RSA私钥:\r\n{rsa.PrivateKey}\r\n");
29                 var encrypt = rsa.Encrypt(input);
30                 Console.WriteLine($"RSA加密后内容:\r\n{Convert.ToBase64String(encrypt)}\r\n");
31 
32                 Console.WriteLine($"RSA公钥:\r\n{rsa.PublicKey}\r\n");
33                 var decrypt = rsa.Decrypt(encrypt);
34                 Console.WriteLine($"RSA解密后内容:\r\n{Convert.ToBase64String(decrypt)}\r\n");
35                 System.IO.File.WriteAllBytes("1.rar", decrypt);
36             }
37 
38             {
39                 Console.WriteLine("-----------------------------------------------------RSA 使用证书加密与解密字符串--------------------------------------------------");
40                 var input = "公钥密码体制中,目前最著名的是由美国三位科学家Rivest, Shamir 和 Adleman 于1976年提出,并在1978年正式发表的RSA 算法。";
41                 Console.Write($"加密内容:{input}\r\n");
42 
43                 // 证书加密
44                 var rsaEncrypt = new RsaAlgorithm();
45                 rsaEncrypt.X509CertCreateEncryptRSA(@"RSAKey.cer");
46                 Console.WriteLine($"RSA私钥:\r\n{rsaEncrypt.PrivateKey}\r\n");
47                 var encrypt = rsaEncrypt.Encrypt(input);
48                 Console.WriteLine($"RSA加密后内容:\r\n{encrypt}\r\n");
49 
50                 // 证书解密
51                 var rsaDecrypt = new RsaAlgorithm(1024);
52                 rsaDecrypt.X509CertCreateDecryptRSA(@"RSAKey.pfx", "888888");
53                 Console.WriteLine($"RSA公钥:\r\n{rsaEncrypt.PublicKey}\r\n");
54                 var decrypt = rsaDecrypt.Decrypt(encrypt);
55                 Console.WriteLine($"RSA解密后内容:\r\n{decrypt}\r\n");
56             }
57             Console.ReadKey();
58         }
相关推荐
用户962377954481 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954481 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star1 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954482 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
cipher3 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
一次旅行6 天前
网络安全总结
安全·web安全
DianSan_ERP6 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
red1giant_star6 天前
手把手教你用Vulhub复现ecshop collection_list-sqli漏洞(附完整POC)
安全