前言
本文主要介紹如何使用.Net
自帶API
結合BouncyCastle
類庫實現RSA
加密和解密,密鑰生成和密鑰格式轉換。
一、RSA介紹
RSA
加密算法是1977
年由Ron Rivest
、Adi Shamirh
和Len Adleman
在(美國麻省理工學院)開發的。RSA
取名來自開發他們三者的名字。
RSA
加密算法是一種非對稱加密算法,簡單來說,就是加密時使用一個鑰匙,解密時使用另一個鑰匙。因為加密的鑰匙是公開的,所又稱公鑰,解密的鑰匙是不公開的,所以稱為私鑰。
RSA
是被研究得最廣泛的公鑰算法,從提出到現在已近二十年,經歷了各種攻擊的考驗,逐漸為人們接受,普遍認為是目前最優秀的公鑰方案之一。
RSA
的缺點主要有:
-
產生密鑰很麻煩,受到素數產生技術的限制,因而難以做到一次一密。
-
分組長度太大,為保證安全性,
n
至少也要600bits
以上,使運算代價很高,尤其是速度較慢,較對稱密碼算法慢幾個數量級;且隨着大數分解技術的發展,這個長度還在增加,不利於數據格式的標准化。目前,SET(Secure Electronic Transaction)
協議中要求CA
采用2048bits
長的密鑰,其他實體使用1024bits
的密鑰。 -
RSA
密鑰長度隨着保密級別提高,增加很快。下表列出了對同一安全級別所對應的密鑰長度。保密級別 對稱密鑰長度(bit) RSA密鑰長度(bit) ECC密鑰長度(bit) 保密年限 80 80 1024 160 2010 112 112 2048 224 2030 128 128 3072 256 2040 192 192 7680 384 2080 256 256 15360 512 2120
RSA
的算法在這里就不贅述了,可以看看下面這張圖有利於理解。

二、C#代碼實現
2.1 生成公鑰/私鑰
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);
}
}
/// <summary>
/// 生成`RSA`密鑰
/// </summary>
/// <param name="keySize">密鑰的大小,從384位到16384位,每8位遞增 </param>
/// <returns></returns>
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;
}
2.2 公鑰加密/私鑰解密
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;
}
2.3 密鑰格式轉換
C#
中RSA
公鑰和私鑰的格式都是XML
的,而在其他語言如java
中,生成的RSA
密鑰就是普通的Base64
字符串,所以需要將C# xml
格式的密鑰轉換成普通的Base64
字符串,同時也要實現Base64
密鑰字符串生成C# xml
格式的密鑰。
安裝 BouncyCastle
這個Nuget
包 PM > Install-Package BouncyCastle
構造一個RSAKeyConventer
類
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;
namespace RSA
{
public class RSAKeyConverter
{
/// <summary>
/// 轉換"私鑰"格式
/// </summary>
/// <param name="xmlPrivateKey">xml格式私鑰</param>
/// <returns>base64格式私鑰</returns>
public static string ToBase64PrivateKey(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;
}
/// <summary>
/// 轉換"公鑰"格式
/// </summary>
/// <param name="xmlPublicKey">xml格式公鑰</param>
/// <returns>base64格式公鑰</returns>
public static string ToBase64PublicKey(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;
}
/// <summary>
/// 轉換"私鑰"格式
/// </summary>
/// <param name="privateKey">base64格式私鑰</param>
/// <returns>xml格式私鑰</returns>
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);
}
}
/// <summary>
/// 轉換"公鑰"格式
/// </summary>
/// <param name="pubilcKey">base64格式公鑰</param>
/// <returns>xml格式公鑰</returns>
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);
}
}
}
}