计算机网络安全 —— 非对称加密算法 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         }
相关推荐
xnuscd6 分钟前
后端开发入门
网络·数据库·oracle
hxj..1 小时前
【网络安全】CSRF
安全·web安全·csrf
布朗克1681 小时前
JWT介绍和结合springboot项目实践(登录、注销授权认证管理)
java·spring boot·后端·安全·jwt
ღ张明宇࿐1 小时前
鸿蒙开发App 如何通过抓包查看 http 网络请求?
网络·http·鸿蒙
Qspace丨轻空间1 小时前
气膜建筑:打造全天候安全作业空间,提升工程建设效率—轻空间
大数据·科技·安全·生活·娱乐
夏子曦2 小时前
RPC——Remote Procedure Call(远程过程调用)
网络·网络协议·rpc
东方隐侠安全团队-千里2 小时前
网安瞭望台第6期 :XMLRPC npm 库被恶意篡改、API与SDK的区别
前端·网络·网络安全·npm·node.js
uhakadotcom2 小时前
开发我们的第一个基于Rust的应用:端口扫描器
后端·安全·rust
java_heartLake2 小时前
网络安全之WAF
计算机网络·安全·web安全
河北稳控科技2 小时前
解决水库安全监测难题 长期无外接电源 低功耗设备智能化监测系统
安全