C#的RSA私钥加密&公钥解密类

1.问题的出现


        我们知道,C#的类库中提供了RSA加密、解密以及密钥(publickey&privatekey)的生成方法,使我们能够很方便的实现RSA的加密解密以及密钥生成的操作。然而,在我们做项目的时候,我们也会发现C#自带的RSA类有以下的局限性:

  1. 密钥生成的格式为XML,虽然这种标准的格式使得我们得以在C#程序中轻松将XML格式的密钥导入,但是这种XML格式的密钥却不能很好的兼容一些其他的项目(比如Java项目)

  2. C#自带的RSA类只支持公钥加密私钥解密,却不支持私钥加密公钥解密(此文章将要讨论的问题),致使我们在开发某些项目(如用于软件加密、服务端数据私钥加密)时无法顺利进行

        说到这里,就有必要说一下关于RSA的概念了。


2.关于RSA


        RSA是一种不对称的加密算法,其安全性依赖于大数的因子分解,其生成的公钥/私钥对可以分别用于加密/解密或者解密/加密,也就是说,在理论上,RSA算法既可以实现公钥加密私钥解密,也可以实现私钥加密公钥解密。公钥加密私钥解密模式可以用于加密情形,这样,用户加密的数据在传输过程中被劫持也无法被第三方破解,从而保证用户与服务端握手的安全性。而私钥加密公钥解密则可以用于数字签名,这样,通过私钥加密产生的电子证书是不能被伪造的,而拿到公钥的用户可以使用公钥对其解密 ,从而可以校验此电子证书。

        也就是说,在理论上,我们是可以实现私钥加密公钥解密的,那么我们首先就要了解一下C#中的RSA类。


3.C#中的RSA类


在C#中,RSACryptoServiceProvider类可以用于RSA加密解密以及密钥对生成。

实例化

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

导出密钥

RSAParameters privatekey = rsa.ExportParameters(true); //导出私钥

RSAParameters publickey = rsa.ExportParameters(false); //导出公钥

导入密钥

rsa.FromXmlString(str); //参数str为XML格式的字符串

公钥加密

byte[] arrSource = Encoding.UTF8.GetBytes(source); //source为要加密的字符串
byte[] arrEnc = rsa.Encrypt(arrSource, false);
string Enc = Convert.ToBase64String(arrEnc);

私钥解密

byte[] arrEnc = Convert.FromBase64String(Enc); //Enc为需要解密的字符串
byte[] arrDec = rsa.Decrypt(arrEnc, false);
string Dec = Encoding.UTF8.GetString(arrDec);

XML格式的密钥中,私钥包含Modulus、Exponent(生成密钥一般都是用的65537)、P、Q、DP、DQ、InverseQ、D,公钥包含Modulus、Exponent,其中Modulus和Exponent为RSA公钥,Modulus和D为RSA私钥。


4.实现私钥加密&公钥解密


考虑到使用大数运算自己编写RSA私钥加密以及公钥解密的类方法比较繁琐,我想到了BouncyCastle,我们首先下载BouncyCastle的dll,然后新建一个RSAHelper类

首先做引入以下的库,这些库可以用于字符串编码、使用C#自带的RSA类

using System.Text;
using System;
using System.Security.Cryptography;

然后,我们还需要引入BouncyCastle的相关库

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Parameters;

下面我们首先编写私钥加密函数

/// <summary>
/// 用私钥给数据进行RSA加密
/// </summary>
/// <param name="xmlPrivateKey"> 私钥(XML格式字符串)</param>
/// <param name="strEncryptString"> 要加密的数据 </param>
/// <returns> 加密后的数据 </returns>
public static string PrivateKeyEncrypt(string xmlPrivateKey, string strEncryptString){    //加载私钥
    RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
    privateRsa.FromXmlString(xmlPrivateKey);        
    //转换密钥
    AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
    IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding"); //使用RSA/ECB/PKCS1Padding格式
    //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥

    c.Init(true, keyPair.Private);
    byte[] DataToEncrypt = Encoding.UTF8.GetBytes(strEncryptString);
    byte[] outBytes = c.DoFinal(DataToEncrypt);//加密
    string strBase64 = Convert.ToBase64String(outBytes);
    return strBase64;
}

接下来,编写公钥解密函数

/// <summary>
/// 用公钥给数据进行RSA解密 
/// </summary>
/// <param name="xmlPublicKey"> 公钥(XML格式字符串) </param>
/// <param name="strDecryptString"> 要解密数据 </param>
/// <returns> 解密后的数据 </returns>
public static string PublicKeyDecrypt(string xmlPublicKey, string strDecryptString){
    //加载公钥
    RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
    publicRsa.FromXmlString(xmlPublicKey);
    RSAParameters rp = publicRsa.ExportParameters(false);//转换密钥
    AsymmetricKeyParameter pbk = DotNetUtilities.GetRsaPublicKey(rp);

    IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding"); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
    c.Init(false, pbk);
    byte[] DataToDecrypt = Convert.FromBase64String(strDecryptString);
    byte[] outBytes = c.DoFinal(DataToDecrypt);//解密

    string strDec = Encoding.UTF8.GetString(outBytes);
    return strDec;
}

大功告成,现在我们就可以使用RSAHelper类的这两个静态方法来实现私钥加密以及公钥解密的功能了。


猜你喜欢

转载自blog.51cto.com/7957017/2324056