当前位置:   article > 正文

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

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

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

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

四、测试代码与效果

​ 测试代码如下:

  1. 1 static void Main(string[] args)
  2. 2 {
  3. 3 {
  4. 4 Console.WriteLine("-----------------------------------------------------RSA 字符串加密与解密以及签名与验签--------------------------------------------------");
  5. 5 var input = "公钥密码体制中,目前最著名的是由美国三位科学家Rivest, Shamir 和 Adleman 于1976年提出,并在1978年正式发表的RSA 算法。";
  6. 6 Console.Write($"加密内容:{input}\r\n");
  7. 7 var rsa = new RsaAlgorithm();
  8. 8
  9. 9 Console.WriteLine($"RSA私钥:\r\n{rsa.PrivateKey}\r\n");
  10. 10 var encrypt = rsa.Encrypt(input);
  11. 11 Console.WriteLine($"RSA加密后内容:\r\n{encrypt}\r\n");
  12. 12 var sign = rsa.Sign("SHA1", input);
  13. 13 Console.WriteLine($"RSA生成数字签名[SHAI]:\r\n{sign}\r\n");
  14. 14
  15. 15 Console.WriteLine($"RSA公钥:\r\n{rsa.PublicKey}\r\n");
  16. 16 var decrypt = rsa.Decrypt(encrypt);
  17. 17 Console.WriteLine($"RSA解密后内容:\r\n{decrypt}\r\n");
  18. 18 string signResult = rsa.VerifySign(decrypt, "SHA1", sign) ? "验签通过" : "验签未通过";
  19. 19 Console.WriteLine($"RSA进行鉴别数字签名:{signResult}");
  20. 20 }
  21. 21
  22. 22 {
  23. 23 Console.WriteLine("-----------------------------------------------------RSA 文件加密与解密--------------------------------------------------");
  24. 24 var input = System.IO.File.ReadAllBytes(@"C:\Users\97460\Desktop\1.rar");
  25. 25 Console.Write($"加密内容:{Convert.ToBase64String(input)}\r\n");
  26. 26 var rsa = new RsaAlgorithm(1024);
  27. 27
  28. 28 Console.WriteLine($"RSA私钥:\r\n{rsa.PrivateKey}\r\n");
  29. 29 var encrypt = rsa.Encrypt(input);
  30. 30 Console.WriteLine($"RSA加密后内容:\r\n{Convert.ToBase64String(encrypt)}\r\n");
  31. 31
  32. 32 Console.WriteLine($"RSA公钥:\r\n{rsa.PublicKey}\r\n");
  33. 33 var decrypt = rsa.Decrypt(encrypt);
  34. 34 Console.WriteLine($"RSA解密后内容:\r\n{Convert.ToBase64String(decrypt)}\r\n");
  35. 35 System.IO.File.WriteAllBytes("1.rar", decrypt);
  36. 36 }
  37. 37
  38. 38 {
  39. 39 Console.WriteLine("-----------------------------------------------------RSA 使用证书加密与解密字符串--------------------------------------------------");
  40. 40 var input = "公钥密码体制中,目前最著名的是由美国三位科学家Rivest, Shamir 和 Adleman 于1976年提出,并在1978年正式发表的RSA 算法。";
  41. 41 Console.Write($"加密内容:{input}\r\n");
  42. 42
  43. 43 // 证书加密
  44. 44 var rsaEncrypt = new RsaAlgorithm();
  45. 45 rsaEncrypt.X509CertCreateEncryptRSA(@"RSAKey.cer");
  46. 46 Console.WriteLine($"RSA私钥:\r\n{rsaEncrypt.PrivateKey}\r\n");
  47. 47 var encrypt = rsaEncrypt.Encrypt(input);
  48. 48 Console.WriteLine($"RSA加密后内容:\r\n{encrypt}\r\n");
  49. 49
  50. 50 // 证书解密
  51. 51 var rsaDecrypt = new RsaAlgorithm(1024);
  52. 52 rsaDecrypt.X509CertCreateDecryptRSA(@"RSAKey.pfx", "888888");
  53. 53 Console.WriteLine($"RSA公钥:\r\n{rsaEncrypt.PublicKey}\r\n");
  54. 54 var decrypt = rsaDecrypt.Decrypt(encrypt);
  55. 55 Console.WriteLine($"RSA解密后内容:\r\n{decrypt}\r\n");
  56. 56 }
  57. 57 Console.ReadKey();
  58. 58 }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/332662
推荐阅读
相关标签
  

闽ICP备14008679号