计算机网络安全 —— 非对称加密算法 RSA 和数字签名(二)
一、非对称加密算法基本概念
在对称密钥系统中,两个参与者要共享同一个秘密密钥。但怎样才能做到这一点呢?一种是事先约定,另一种是用信使来传送。在高度自动化的大型计算机网络中,用信使来传送密钥显然是不合适的。如果事先约定密钥,就会给密钥的管理和更换都带来了极大的不便。当然我们可以使用复杂的密钥分发中心(KeyDistributionCenter,KDC)来解决该问题,但采用公钥密码体制可以比较容易地解决这个问题。公钥密码体制的概念是由Stanford大学的研究人员Diffie与Hellman于1976年提出的。公钥密码体制使用不同的加密密钥与解密密钥。
由于加密密钥不能用来解密,并且从加密密钥不能推导出解密密钥,因此加密密钥可以公开。例如,参与者A可以在报纸上公布自己的加 密密钥(即公钥),而解密密钥(即私钥)自己秘密保存。任何参与都可以获得该公钥,并用来加密发送给参与者A的信息,而该信息只 能由A解密。可见采用公钥密码体制更易解决密钥分发的问题。
公钥密码体制有许多很好的特性,使得它不仅可以用于加密,还可以很方便地用于鉴别和数字签名。但不幸的是,目前的公钥密码算法比对称密码算法要慢好几个数量级。因此,对称密码被用于绝大部分加密,而公钥密码则通常用于会话密钥的建立。例如,参与者A要发送 大量秘密信息给B。A首先选择一个用于加密数据本身(如采用DES算法)的密钥,由于该密钥仅用于该次会话,被称为会话密钥。因为对称密钥由双方共享,A必须将该会话密钥通过秘密渠道告知B。为此,A用B的RSA公钥加密该会话密钥后发送给B。B收到加密的会话密 钥后用自己的私钥解密后得到会话密钥。此后,A和B之间就可以用该会话密钥加密通信的数据。具体流程如下图:
二、数字签名的基本概念
在日常生活中,可以根据亲笔签名或印章来证明书信或文件的真实来源。但在计算机网络中传送的文电又如何盖章呢?这就是数字签名(digitalsignature)所要解决的问题。
数字签名必须保证以下三点:
- 接收方能够核实发送方对报文的数字签名;
- 发送方事后不能抵赖对报文的数字签名;
- 任何人包括接收方都不能伪造对报文的签名。
现在已有多种实现数字签名的方法。但采用公钥算法要比采用对称密钥算法更容易实现。具体流程如下:
我们知道公钥密码算法的计算代价非常大,对整个报文进行数字签名是一件非常耗时的事情。更有效的方法是仅对报文摘要进行数字签名。
上述过程仅对报文进行了签名,对报文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 }
代码示例:https://github.com/Dwayne112401/encryption
计算机网络安全 —— 非对称加密算法 RSA 和数字签名(二)的更多相关文章
- 非对称加密算法-RSA算法
一.概述 1.RSA是基于大数因子分解难题.目前各种主流计算机语言都支持RSA算法的实现 2.java6支持RSA算法 3.RSA算法可以用于数据加密和数字签名 4.RSA算法相对于DES/AES等对 ...
- 非对称加密算法RSA使用注意事项
原文:非对称加密算法RSA使用注意事项 第一个问题,也是最重要的一个——RSA无法对超过117字节的数据进行加密!切记!其实也勿需要求对更大数据的加密,虽然网上已经有相关解决方案,比如BigInteg ...
- Java进阶(七)Java加密技术之非对称加密算法RSA
Java加密技术(四)--非对称加密算法RSA 非对称加密算法--RSA 基本概念 非对称加密算法是一种密钥的保密方法. 非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(priv ...
- JAVA 非对称加密算法RSA
非对称加密算法 RSA过程 : 以甲乙双方为例 1.初始化密钥 构建密钥对,生成公钥.私钥保存到keymap中 KeyPairGenerator ---> KeyPair --> RSAP ...
- Java加密技术(四)非对称加密算法RSA
RSA 这样的算法1978年就出现了.它是第一个既能用于数据加密也能用于数字签名的算法.它易于理解和操作.也非常流行.算法的名字以发明者的名字命名:Ron Rivest, AdiShamir ...
- 非对称加密算法RSA 学习
非对称加密算法RSA 学习 RSA加密算法是一种非对称加密算法.RSA是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Ad ...
- 第十二章 非对称加密算法-RSA
注意:本节内容主要参考自<Java加密与解密的艺术(第2版)>第8章“高等加密算法--非对称加密算法” 12.1.RSA(最经典的非对称加密算法) 特点: 使用一套密钥即可完成加解密(与D ...
- openssl 非对称加密算法RSA命令详解
1.非对称加密算法概述 非对称加密算法也称公开密钥算法,其解决了对称加密算法密钥分配的问题,非对称加密算法基本特点如下: 1.加密密钥和解密密钥不同 2.密钥对中的一个密钥可以公开 3.根据公开密钥很 ...
- java-信息安全(五)-非对称加密算法RSA
概述 信息安全基本概念: RSA算法(Ron Rivest.Adi Shamir.Leonard Adleman,人名组合) RSA RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rive ...
随机推荐
- 在python中元组与列表的区别及序列解包
一. 元组与列表的区别 元组中的数据一旦定义就不允许更改. 元组没有append().extend()和insert()等方法,无法向元组中添加元素. 元组没有remove()或pop()方法,也无法 ...
- C#中的深度学习(四):使用Keras.NET识别硬币
在本文中,我们将研究一个卷积神经网络来解决硬币识别问题,并且我们将在Keras.NET中实现一个卷积神经网络. 在这里,我们将介绍卷积神经网络(CNN),并提出一个CNN的架构,我们将训练它来识别硬币 ...
- C# 多态virtual标记重写 以及EF6 查询性能AsNoTracking
首先你如果不用baivirtual重写的话,系统默认会为du你加new关键字,他zhi的作用是覆盖,而virtual的关键作用在dao于实现多态 virtual 代表在继承了这个类的子类里面可以使用o ...
- 配置文件中配置集合类(Map、list)@Value注入map、List
spel表达式就是spring表达式.在java代码中,还有这种写法: @Value("#{'${auth.filter.exclude-urls}'.split(',')}") ...
- 工作中用的sql
//字段是空字符串或者null select * from blade_process_should_pay_invoice where is_deleted = 0 and process_inst ...
- Redis集群搭建采坑总结
背景 先澄清一下,整个过程问题都不是我解决的,我在里面就是起了个打酱油的角色.因为实际上我负责这个项目,整个过程也比较清楚.之前也跟具体负责的同事说过,等过段时间带他做做项目复盘.结果一直忙,之前做的 ...
- 简述java多态
一.多态性: 1.java实现多态的前提:继承.覆写: 2.覆写调用的前提:看new是哪个类的对象,而后看方法是否被子类覆写,若覆写则调用覆写的方法,若没覆写则调用父类的方法: 二.多态性组成: 1方 ...
- 容器编排系统K8s之访问控制--RBAC授权
前文我们了解了k8s上的访问控制机制,主要对访问控制中的第一关用户认证做了相关说明以及常规用户的配置文件的制作,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/ ...
- JAVA顺序结构和选择结构
顺序结构 JAVA的基本结构就是顺序结构,除非特别指明,否则按顺序一句一句执行 顺序结构是最简单的算法结构 语句和语句直接,框与框直接就是按从上到下的顺序执行的,它是由若干个依次执行的处理步骤组成的, ...
- SonarQube学习(三)- 项目代码扫描
一.前言 元旦三天假,两天半都在玩86版本DNF,不得不说,这个服真的粘度太高了,但是真的很良心. 说明: 注册账号上线100w点券,一身+15红字史诗装备以及+21强化新手武器.在线泡点一分钟888 ...