龙方德 發表於 2019-6-15 19:36:00

C#实现RSA加密解密

<h2 id="rsa介绍">RSA介绍</h2>
<p>RSA公钥加密算法是<strong>1977</strong>年由Ron Rivest、Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。</p>
<p><strong>RSA的缺点</strong>:<br>
<img src="https://minio.mytechsky.top/blog/images/2022022723013533-20220227230134.png" alt="image" loading="lazy"></p>
<ul>
<li>
<p>产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。</p>
</li>
<li>
<p>分组长度太大,为保证安全性,n 至少也要 600bits以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。目前,SET(Secure Electronic Transaction)协议中要求CA采用2048bits长的密钥,其他实体使用1024比特的密钥。C)RSA密钥长度随着保密级别提高,增加很快。下表列出了对同一安全级别所对应的密钥长度。</p>
<table>
<thead>
<tr>
<th>保密级别</th>
<th>对称密钥长度(bit)</th>
<th>RSA密钥长度(bit)</th>
<th>ECC密钥长度(bit)</th>
<th>保密年限</th>
</tr>
</thead>
<tbody>
<tr>
<td>80</td>
<td>80</td>
<td>1024</td>
<td>160</td>
<td>2010</td>
</tr>
<tr>
<td>112</td>
<td>112</td>
<td>2048</td>
<td>224</td>
<td>2030</td>
</tr>
<tr>
<td>128</td>
<td>128</td>
<td>3072</td>
<td>256</td>
<td>2040</td>
</tr>
<tr>
<td>192</td>
<td>192</td>
<td>7680</td>
<td>384</td>
<td>2080</td>
</tr>
<tr>
<td>256</td>
<td>256</td>
<td>15360</td>
<td>512</td>
<td>2120</td>
</tr>
</tbody>
</table>
</li>
</ul>
<h2 id="rsa的参数">RSA的参数</h2>
<p>RSA密码由三个整数组成,我们分别称之为n, e, d</p>
<p><strong>(n、d)</strong>: <strong>私钥</strong>,这个我们要私密保存<br>
<strong>(n、e)</strong>: <strong>公钥</strong>,可以对外公布<br>
<strong>n</strong>: <strong>模数</strong>(Modulus),私钥和公钥都包含有这个数<br>
<strong>e</strong>: <strong>公钥指数</strong>(publicExponent),一般是固定值65537<br>
<strong>d</strong>:<strong>私钥指数</strong>(privateExponent)</p>
<p>dotnet中的表示RSA参数的结构体是<code>RSAParameters</code></p>
<p><img src="https://user-images.githubusercontent.com/38829279/93090717-c01cd680-f6cf-11ea-8aac-e91837bb963d.png" alt="image" loading="lazy"></p>
<h2 id="openssl生成rsa密钥对">openssl生成RSA密钥对</h2>
<h3 id="1-生成一个rsa密钥">1. 生成一个RSA密钥</h3>
<p><code>openssl genrsa -out private_pkcs1.pem 2048</code></p>
<p>上面的命令导出是<code>pkcs#1</code>格式rsa私钥</p>
<h3 id="2-从生成的rsa密钥中提取rsa公钥">2. 从生成的RSA密钥中提取RSA公钥</h3>
<blockquote>
<p>ps: 私钥中包含了公钥相关信息,所以可以从私钥中导出公钥信息</p>
</blockquote>
<p><code>openssl rsa -in private_pkcs1.pem -out public_pkcs1.pem -pubout -RSAPublicKey_out</code></p>
<h3 id="公钥格式转换pkcs8--pkcs1">公钥格式转换(PKCS#8 =&gt; PKCS#1)</h3>
<p><code>openssl rsa -in public_pkcs8.pem -out public_pkcs1.pem -pubin -RSAPublicKey_out</code></p>
<h3 id="私钥格式转换-pkcs1--pkcs8">私钥格式转换 (PKCS#1 =&gt; PKCS#8)</h3>
<p><code>openssl pkcs8 -in private_pkcs1.pem -out private_pkcs8.pem -topk8 -nocrypt</code></p>
<h3 id="rsa私钥格式转换pkcs8--pkcs1">RSA私钥格式转换(PKCS#8 =&gt; PKCS#1)</h3>
<p><code>openssl rsa -in private_pkcs8.pem -out private_pkcs1.pem</code></p>
<h2 id="c中rsa的相关操作">C#中RSA的相关操作</h2>
<p><strong>生成公钥和私钥</strong></p>
<pre><code class="language-csharp">struct RSASecretKey
{
    public RSASecretKey(string privateKey, string publicKey)
    {
      PrivateKey = privateKey;
      PublicKey = publicKey;
    }
    public string PublicKey { get; set; }
    public string PrivateKey { get; set; }
    public override string ToString()
    {
      return string.Format(
            "PrivateKey: {0}\r\nPublicKey: {1}", PrivateKey, PublicKey);
    }
}

/// &lt;summary&gt;
/// generate RSA secret key
/// &lt;/summary&gt;
/// &lt;param name="keySize"&gt;the size of the key,must from 384 bits to 16384 bits in increments of 8 &lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
RSASecretKey GenerateRSASecretKey(int keySize)
{
    RSASecretKey rsaKey = new RSASecretKey();
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize))
    {
      rsaKey.PrivateKey = rsa.ToXmlString(true);
      rsaKey.PublicKey = rsa.ToXmlString(false);
    }
    return rsaKey;
}
</code></pre>
<p><img src="https://img2018.cnblogs.com/blog/1596066/201906/1596066-20190615143036011-113394550.png" alt="" loading="lazy"></p>
<p><strong>实现公钥加密私钥解密</strong></p>
<pre><code class="language-csharp">string RSAEncrypt(string xmlPublicKey,string content)
{
    string encryptedContent = string.Empty;
    using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
      rsa.FromXmlString(xmlPublicKey);
      byte[] encryptedData = rsa.Encrypt(Encoding.Default.GetBytes(content), false);
      encryptedContent = Convert.ToBase64String(encryptedData);
    }
    return encryptedContent;
}

string RSADecrypt(string xmlPrivateKey, string content)
{
    string decryptedContent = string.Empty;
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
      rsa.FromXmlString(xmlPrivateKey);
      byte[] decryptedData = rsa.Decrypt(Convert.FromBase64String(content), false);
      decryptedContent = Encoding.GetEncoding("gb2312").GetString(decryptedData);
    }
    return decryptedContent;
}
</code></pre>
<p><img src="https://img2018.cnblogs.com/blog/1596066/201906/1596066-20190615143111535-1504544917.png" alt="" loading="lazy"><br>
<img src="https://img2018.cnblogs.com/blog/1596066/201906/1596066-20190615143146269-513797370.png" alt="" loading="lazy"></p>
<h3 id="密钥格式的转换">密钥格式的转换</h3>
<p>C#中RSA公钥和私钥的格式都是XML的,而在其他语言如java中,生成的RSA密钥就是普通的Base64字符串,所以需要将C#xml格式的密钥转换成普通的Base64字符串,同时也要实现Base64密钥字符串生成C#中xml格式的密钥.<br>
安装 <strong>BouncyCastle</strong> 这个Nuget包<br>
<code>PM &gt; Install-Package BouncyCastle</code><br>
<strong>BouncyCastle</strong>项目网址<br>
<strong>BouncyCastle</strong>github地址<br>
构造一个<strong>RSAKeyConventer</strong>类</p>
<pre><code class="language-csharp">namespace RSA
{
    using System;
    using System.Security.Cryptography;
    using Org.BouncyCastle.Asn1.Pkcs;
    using Org.BouncyCastle.Math;
    using Org.BouncyCastle.Pkcs;
    using Org.BouncyCastle.Asn1.X509;
    using Org.BouncyCastle.X509;
    using Org.BouncyCastle.Security;
    using Org.BouncyCastle.Crypto.Parameters;

    public class RSAKeyConverter
    {
      /// &lt;summary&gt;
      /// xml private key -&gt; base64 private key string
      /// &lt;/summary&gt;
      /// &lt;param name="xmlPrivateKey"&gt;&lt;/param&gt;
      /// &lt;returns&gt;&lt;/returns&gt;
      public static string FromXmlPrivateKey(string xmlPrivateKey)
      {
            string result = string.Empty;
            using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(xmlPrivateKey);
                RSAParameters param = rsa.ExportParameters(true);
                RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(
                  new BigInteger(1, param.Modulus), new BigInteger(1, param.Exponent),
                  new BigInteger(1, param.D), new BigInteger(1, param.P),
                  new BigInteger(1, param.Q), new BigInteger(1, param.DP),
                  new BigInteger(1, param.DQ), new BigInteger(1, param.InverseQ));
                PrivateKeyInfo privateKey = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);

                result = Convert.ToBase64String(privateKey.ToAsn1Object().GetEncoded());
            }
            return result;
      }

      /// &lt;summary&gt;
      /// xml public key -&gt; base64 public key string
      /// &lt;/summary&gt;
      /// &lt;param name="xmlPublicKey"&gt;&lt;/param&gt;
      /// &lt;returns&gt;&lt;/returns&gt;
      public static string FromXmlPublicKey(string xmlPublicKey)
      {
            string result = string.Empty;
            using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(xmlPublicKey);
                RSAParameters p = rsa.ExportParameters(false);
                RsaKeyParameters keyParams = new RsaKeyParameters(
                  false, new BigInteger(1,p.Modulus), new BigInteger(1, p.Exponent));
                SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyParams);
                result = Convert.ToBase64String(publicKeyInfo.ToAsn1Object().GetEncoded());
            }
            return result;
      }

      /// &lt;summary&gt;
      /// base64 private key string -&gt; xml private key
      /// &lt;/summary&gt;
      /// &lt;param name="privateKey"&gt;&lt;/param&gt;
      /// &lt;returns&gt;&lt;/returns&gt;
      public static string ToXmlPrivateKey(string privateKey)
      {
            RsaPrivateCrtKeyParameters privateKeyParams =
                PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey)) as RsaPrivateCrtKeyParameters;
            using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                RSAParameters rsaParams = new RSAParameters()
                {
                  Modulus = privateKeyParams.Modulus.ToByteArrayUnsigned(),
                  Exponent = privateKeyParams.PublicExponent.ToByteArrayUnsigned(),
                  D = privateKeyParams.Exponent.ToByteArrayUnsigned(),
                  DP = privateKeyParams.DP.ToByteArrayUnsigned(),
                  DQ = privateKeyParams.DQ.ToByteArrayUnsigned(),
                  P = privateKeyParams.P.ToByteArrayUnsigned(),
                  Q = privateKeyParams.Q.ToByteArrayUnsigned(),
                  InverseQ = privateKeyParams.QInv.ToByteArrayUnsigned()
                };
                rsa.ImportParameters(rsaParams);
                return rsa.ToXmlString(true);
            }
      }

      /// &lt;summary&gt;
      /// base64 public key string -&gt; xml public key
      /// &lt;/summary&gt;
      /// &lt;param name="pubilcKey"&gt;&lt;/param&gt;
      /// &lt;returns&gt;&lt;/returns&gt;
      public static string ToXmlPublicKey(string pubilcKey)
      {
            RsaKeyParameters p =
                PublicKeyFactory.CreateKey(Convert.FromBase64String(pubilcKey)) as RsaKeyParameters;
            using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                RSAParameters rsaParams = new RSAParameters
                {
                  Modulus = p.Modulus.ToByteArrayUnsigned(),
                  Exponent = p.Exponent.ToByteArrayUnsigned()
                };
                rsa.ImportParameters(rsaParams);
                return rsa.ToXmlString(false);
            }
      }
    }
}
</code></pre>
<h2 id="js的rsa操作">js的rsa操作</h2>
<p>移步: https://github.com/travist/jsencrypt</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>作者:Laggage</p>
<p>出处:https://www.cnblogs.com/laggage/p/11028614.html</p>
<p>说明:转载请注明来源</p><br><br>
来源:https://www.cnblogs.com/laggage/p/11028614.html
頁: [1]
查看完整版本: C#实现RSA加密解密