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

server/2024/11/30 6:00:15/

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

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

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

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

img

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

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

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

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

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

img

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

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

img

二、.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.rsa8 {9     /// <summary>10     /// https://cloud.tencent.com/developer/article/105444111     /// </summary>12     public class RsaAlgorithm13     {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 .ctor21 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         #endregion32 33         #region 创建RSA34 35         /// <summary>36         /// 创建加密RSA37         /// </summary>38         /// <param name="publicKey">公钥</param>39         /// <returns></returns>40         public  RSACryptoServiceProvider CreateEncryptRSA(string publicKey)41         {42             try43             {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         /// 根据字符串创建解密RSA58         /// </summary>59         /// <param name="privateKey">私钥</param>60         /// <returns></returns>61         public RSACryptoServiceProvider CreateDecryptRSA(string privateKey)62         {63             try64             {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         /// 根据安全证书创建加密RSA79         /// </summary>80         /// <param name="certfile">公钥文件</param>81         /// <returns></returns>82         public RSACryptoServiceProvider X509CertCreateEncryptRSA(string certfile)83         {84             try85             {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         }

http://www.ppmy.cn/server/146090.html

相关文章

【大数据测试之:RabbitMQ消息列队测试-发送、接收、持久化、确认、重试、死信队列并处理消息的并发消费、负载均衡、监控等】详细教程---保姆级

RabbitMQ消息列队测试教程 一、环境准备1. 安装 RabbitMQ2. 安装 Python 依赖 二、基本消息队列中间件实现1. 消息发送模块2. 消息接收模块 三、扩展功能1. 消息持久化和队列持久化2. 消息优先级3. 死信队列&#xff08;DLQ&#xff09; 四、并发处理和负载均衡1. 使用 Python …

Qt—QLineEdit 使用总结

文章参考:Qt—QLineEdit 使用总结 一、简述 QLineEdit是一个单行文本编辑控件。 使用者可以通过很多函数,输入和编辑单行文本,比如撤销、恢复、剪切、粘贴以及拖放等。 通过改变 QLineEdit 的 echoMode() ,可以设置其属性,比如以密码的形式输入。 文本的长度可以由 m…

.npmrc文件的用途

.npmrc 文件是 npm&#xff08;Node.js 的包管理工具&#xff09;用于配置项目或用户的设置文件。它可以存储与 npm 相关的配置信息&#xff0c;如注册表地址、认证信息、代理设置、安装路径等。.npmrc 文件可以出现在不同的地方&#xff0c;具有不同的作用范围&#xff0c;通常…

kafka学习-02

kafka分区的分配以及再平衡&#xff1a; 4个&#xff1a; 1、Range 以及再平衡 1&#xff09;Range 分区策略原理 2&#xff09;Range 分区分配策略案例 &#xff08;1&#xff09;修改主题 first 为 7 个分区。 bin/kafka-topics.sh --bootstrap-server bigdata01:9092 --…

视频流媒体服务解决方案之Liveweb视频汇聚平台

一&#xff0c;Liveweb视频汇聚平台简介: LiveWeb是深圳市好游科技有限公司开发的一套综合视频汇聚管理平台&#xff0c;可提供多协议&#xff08;RTSP/RTMP/GB28181/海康Ehome/大华&#xff0c;海康SDK等&#xff09;的视频设备接入&#xff0c;支持GB/T28181上下级联&#xf…

Linux查看网络基础命令

文章目录 Linux网络基础命令1. ifconfig 和 ip一、ifconfig命令二、ip命令 2. ss命令一、基本用法二、常用选项三、输出信息四、使用示例 3. sar 命令一、使用sar查看网络使用情况 4. ping 命令一、基本用法二、常用选项三、输出结果四、使用示例 Linux网络基础命令 1. ifconf…

传输控制协议(TCP)

传输控制协议是Internet一个重要的传输层协议。TCP提供面向连接、可靠、有序、字节流传输服务。 1、TCP报文段结构 注&#xff1a;TCP默认采用累积确认机制。 2、三次握手、四次挥手 &#xff08;1&#xff09;当客户向服务器发送完最后一个数据段后&#xff0c;发送一个FIN段…

国产FPGA+DSP 双FMC 6U VPX处理板

高性能国产化信号处理平台采用6U VPX架构&#xff0c;双FMC接口国产V7 FPGA 国产多核 DSP 的硬件架构&#xff0c;可以完成一体化电子系统、有源相控阵雷达、电子侦察、MIMO 通信、声呐等领域的高速实时信号处理。 信号处理平台的组成框图如图 1 所示&#xff0c; DSP处理器采…