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 (三)计算机网络安全 —— 实体鉴别与生成大随机数(四)

  • 相关阅读:
    (一)Python入门-6面向对象编程:10特殊方法和运算符重载-特殊属性
    (一)Python入门-6面向对象编程:09多态
    (一)Python入门-6面向对象编程:08多重继承-mro()-super()获得父类的定义
    (一)Python入门-6面向对象编程:07面向对象三大特征(封装、继承、多态)-继承
    (一)Python入门-6面向对象编程:06私有属性和私有方法(实现封装)-@property装饰器-get和set方法-总结
    (一)Python入门-6面向对象编程:05方法没有重载-方法的动态性
    (一)Python入门-6面向对象编程:04__del__方法(析构函数)和垃圾回收机制-__call__方法和可调用对象
    python并发编程
    python学习笔记:第21天 常用内置模块之collections和time
    python学习笔记:第20天 多继承、MRO C3算法
  • 原文地址:https://www.cnblogs.com/dongweian/p/14330446.html
Copyright © 2011-2022 走看看