zoukankan      html  css  js  c++  java
  • 计算机网络安全 —— 非对称加密算法 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 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}
    ");
     7                 var rsa = new RsaAlgorithm();
     8 
     9                 Console.WriteLine($"RSA私钥:
    {rsa.PrivateKey}
    ");
    10                 var encrypt = rsa.Encrypt(input);
    11                 Console.WriteLine($"RSA加密后内容:
    {encrypt}
    ");
    12                 var sign = rsa.Sign("SHA1", input);
    13                 Console.WriteLine($"RSA生成数字签名[SHAI]:
    {sign}
    ");
    14 
    15                 Console.WriteLine($"RSA公钥:
    {rsa.PublicKey}
    ");
    16                 var decrypt = rsa.Decrypt(encrypt);
    17                 Console.WriteLine($"RSA解密后内容:
    {decrypt}
    ");
    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:Users97460Desktop1.rar");
    25                 Console.Write($"加密内容:{Convert.ToBase64String(input)}
    ");
    26                 var rsa = new RsaAlgorithm(1024);
    27 
    28                 Console.WriteLine($"RSA私钥:
    {rsa.PrivateKey}
    ");
    29                 var encrypt = rsa.Encrypt(input);
    30                 Console.WriteLine($"RSA加密后内容:
    {Convert.ToBase64String(encrypt)}
    ");
    31 
    32                 Console.WriteLine($"RSA公钥:
    {rsa.PublicKey}
    ");
    33                 var decrypt = rsa.Decrypt(encrypt);
    34                 Console.WriteLine($"RSA解密后内容:
    {Convert.ToBase64String(decrypt)}
    ");
    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}
    ");
    42 
    43                 // 证书加密
    44                 var rsaEncrypt = new RsaAlgorithm();
    45                 rsaEncrypt.X509CertCreateEncryptRSA(@"RSAKey.cer");
    46                 Console.WriteLine($"RSA私钥:
    {rsaEncrypt.PrivateKey}
    ");
    47                 var encrypt = rsaEncrypt.Encrypt(input);
    48                 Console.WriteLine($"RSA加密后内容:
    {encrypt}
    ");
    49 
    50                 // 证书解密
    51                 var rsaDecrypt = new RsaAlgorithm(1024);
    52                 rsaDecrypt.X509CertCreateDecryptRSA(@"RSAKey.pfx", "888888");
    53                 Console.WriteLine($"RSA公钥:
    {rsaEncrypt.PublicKey}
    ");
    54                 var decrypt = rsaDecrypt.Decrypt(encrypt);
    55                 Console.WriteLine($"RSA解密后内容:
    {decrypt}
    ");
    56             }
    57             Console.ReadKey();
    58         }
    

    代码示例:https://github.com/Dwayne112401/encryption

    相关内容:计算机网络安全 —— 对称加密算法 DES (一)计算机网络安全 —— 报文摘要算法 ME5 (三)计算机网络安全 —— 实体鉴别与生成大随机数(四)

  • 相关阅读:
    Minimum Depth of Binary Tree leetcode java
    Maximum Depth of Binary Tree leetcode java
    Symmetric Tree leetcode java
    Same Tree leetcode java
    Binary Tree Postorder Traversal leetcode java
    Binary Tree Preorder Traversal leetcode java
    Binary Tree Inorder Traversal leetcode java
    Combinations leetcode java
    一键清除Centos iptables 防火墙所有规则
    阿里云centos7.7x64安装open,并配置ip转发和nat伪装
  • 原文地址:https://www.cnblogs.com/dongweian/p/14330446.html
Copyright © 2011-2022 走看看