C# 中使用 RSA加解密演算法
一、什麼是RSA
RSA公開金鑰密碼體制。所謂的公開金鑰密碼體制就是使用不同的加密金鑰與解密金鑰,是一種“由已知加密金鑰推匯出解密金鑰在計算上是不可行的”密碼體制。
在公開金鑰密碼體制中,加密金鑰(即公開金鑰)PK是公開資訊,而解密金鑰(即祕密金鑰)SK是需要保密的。加密演算法E和解密演算法D也都是公開的。雖然金鑰SK是由公開金鑰PK決定的,但卻不能根據PK計算出SK。正是基於這種理論,1978年出現了著名的RSA演算法,它通常是先生成一對RSA 金鑰,其中之一是保密金鑰,由使用者儲存;另一個為公開金鑰,可對外公開,甚至可在網路伺服器中註冊。為提高保密強度,RSA金鑰至少為500位長,一般推薦使用1024位。這就使加密的計算量很大。為減少計算量,在傳送資訊時,常採用傳統加密方法 與公開金鑰加密方法相結合的方式,即資訊採用改進的DES或IDEA對話金鑰加密,然後使用RSA金鑰加密對話金鑰和資訊摘要。對方收到資訊後,用不同的 金鑰解密並可核對資訊摘要。
RSA演算法是第一個能同時用於加密和數字簽名的演算法,也易於理解和操作。RSA是被研究得最廣泛的公鑰演算法,從提出到現在的三十多年裡,經歷了各種攻擊的考驗,逐漸為人們接受,普遍認為是目前最優秀的公鑰方案之一。
二、RSA演算法金鑰長度的選擇
1. 非對稱加密演算法中1024 bit金鑰的強度相當於對稱加密演算法80bit金鑰的強度。
2. 金鑰長度增長一倍,公鑰操作所需時間增加約4倍,私鑰操作所需時間增加約8倍,公私鑰生成時間約增長16倍。
3. 一次能加密的密文長度與金鑰長度成正比,加密後的密文長度跟金鑰長度相同(RSA加密內容的長度有限制,和金鑰長度有關,這是由它的演算法決定的)
a、加密的明文長度不能超過RSA金鑰的長度減去11byte,比如金鑰長度是1024位的,1024位=1024bit=128byte,128-11=117byte,所以明文長度不能超過117byte,如果長度超過該值將會丟擲異常。
b、加密後密文的長度為金鑰的長度,如金鑰長度為1024bit(128Byte),最後生成的密文固定為 1024bit(128Byte)。
三、C#中的RSA加解密
.NET Framework 類庫提供了System.Security 名稱空間,System.Security 名稱空間提供公共語言執行時安全系統的基礎結構,包括許可權的基類,而該名稱空間下提供了RSACryptoServiceProvider類來執行RSA演算法的不對稱加密和解密。
1.金鑰對的生成:
a、根據RSACryptoServiceProvider直接生成
/// <summary> /// 生成金鑰 /// </summary> public RSAKey GenerateRSAKey() { RSAKey RSAKEY = new RSAKey(); RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); RSAKEY.PrivateKey = RSA.ToXmlString(true); //生成私鑰 RSAKEY.PublicKey = RSA.ToXmlString(false); //生成公鑰 RSA.Clear(); return RSAKEY; }
b、通過Makecert證書建立工具生成安全證書
makecert -r -pe -n "CN=RSAKey" -b 03/31/2005 -e 12/31/2012 -sky exchange -ss my
可通過"Visual Studio命令提示行"執行以上命令生成證書。
檢視生成的證書:
執行->輸入mmc開啟控制檯->選擇檔案->新增/刪除管理單元->在彈出框左側找到證書->選中證書新增->選擇我的使用者賬戶->完成確定
此時就可以在對應位置檢視到我們剛剛建立的名為RSAKey的證書了,
最終我們可以將證書匯出為:
其中RSAKey.cer中含有加密用的公鑰,RSAKey.pfx中含有解密用的私鑰。
2.建立加解密RSA
/// <summary>
/// 建立加密RSA
/// </summary>
/// <param name="publicKey">公鑰</param>
/// <returns></returns>
private RSACryptoServiceProvider CreateEncryptRSA(string publicKey)
{
try
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(publicKey);
return RSA;
}
catch (CryptographicException ex)
{
throw ex;
}
}
/// <summary>
/// 建立解密RSA
/// </summary>
/// <param name="privateKey">私鑰</param>
/// <returns></returns>
private RSACryptoServiceProvider CreateDecryptRSA(string privateKey)
{
try
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(privateKey);
return RSA;
}
catch (CryptographicException ex)
{
throw ex;
}
}
/// <summary>
/// 根據安全證書建立加密RSA
/// </summary>
/// <param name="certfile">公鑰檔案</param>
/// <returns></returns>
private RSACryptoServiceProvider X509CertCreateEncryptRSA(string certfile)
{
try
{
X509Certificate2 x509Cert = new X509Certificate2(certfile);
RSACryptoServiceProvider RSA = (RSACryptoServiceProvider)x509Cert.PublicKey.Key;
return RSA;
}
catch (CryptographicException ex)
{
throw ex;
}
}
/// <summary>
/// 根據私鑰檔案建立解密RSA
/// </summary>
/// <param name="keyfile">私鑰檔案</param>
/// <param name="password">訪問含私鑰檔案的密碼</param>
/// <returns></returns>
private RSACryptoServiceProvider X509CertCreateDecryptRSA(string keyfile, string password)
{
try
{
X509Certificate2 x509Cert = new X509Certificate2(keyfile, password);
RSACryptoServiceProvider RSA = (RSACryptoServiceProvider)x509Cert.PrivateKey;
return RSA;
}
catch (CryptographicException ex)
{
throw ex;
}
}
其中所提及的私鑰檔案和公鑰檔案就是根據Makecert證書建立工具生成安全證書,而X509CertCreateDecryptRSA方法中的引數password是我們匯出私鑰檔案所設定的訪問密碼,如果沒有改密碼即使有私鑰證書也沒辦法解密。
3.RSA加解密
/// <summary>
/// 加密
/// </summary>
/// <param name="dataToEncrypt">待加密資料</param>
/// <param name="publicKey">公鑰</param>
/// <returns></returns>
public string Encrypt(string dataToEncrypt, string publicKey)
{
Encoding encoder = Encoding.UTF8;
byte[] _dataToEncrypt = encoder.GetBytes(dataToEncrypt);
return this.Encrypt(_dataToEncrypt, publicKey);
}
/// <summary>
/// 加密
/// </summary>
/// <param name="dataToEncrypt">待加密資料</param>
/// <param name="publicKey">公鑰</param>
/// <returns></returns>
public string Encrypt(byte[] dataToEncrypt, string publicKey)
{
using (RSACryptoServiceProvider RSA = this.CreateEncryptRSA(publicKey))
{
byte[] encryptedData = RSA.Encrypt(dataToEncrypt, false);
return this.BytesToHexString(encryptedData);
}
}
/// <summary>
/// 根據安全證書加密
/// </summary>
/// <param name="dataToEncrypt"></param>
/// <param name="certfile"></param>
/// <returns></returns>
public string X509CertEncrypt(string dataToEncrypt, string certfile)
{
Encoding encoder = Encoding.UTF8;
byte[] _dataToEncrypt = encoder.GetBytes(dataToEncrypt);
return this.X509CertEncrypt(_dataToEncrypt, certfile);
}
/// <summary>
/// 根據安全證書加密
/// </summary>
/// <param name="dataToEncrypt">待加密資料</param>
/// <param name="certfile">安全證書</param>
/// <returns></returns>
public string X509CertEncrypt(byte[] dataToEncrypt, string certfile)
{
if (!File.Exists(certfile))
{
throw new ArgumentNullException(certfile, "加密證書未找到");
}
using (RSACryptoServiceProvider RSA = this.X509CertCreateEncryptRSA(certfile))
{
byte[] encryptedData = RSA.Encrypt(dataToEncrypt, false);
return this.BytesToHexString(encryptedData);
}
}
/// <summary>
/// 解密
/// </summary>
/// <param name="encryptedData">待解密資料</param>
/// <param name="privateKey">私鑰</param>
/// <returns></returns>
public string Decrypt(string encryptedData, string privateKey)
{
using (RSACryptoServiceProvider RSA = this.CreateDecryptRSA(privateKey))
{
Encoding encoder = Encoding.UTF8;
byte[] _encryptedData = HexStringToBytes(encryptedData);
byte[] decryptedData = RSA.Decrypt(_encryptedData, false);
return encoder.GetString(decryptedData);
}
}
/// <summary>
/// 解密
/// </summary>
/// <param name="encryptedData">待解密資料</param>
/// <param name="keyfile">私鑰檔案</param>
/// <param name="password">訪問私鑰檔案密碼</param>
/// <returns></returns>
public string X509CertDecrypt(string encryptedData, string keyfile, string password)
{
if (!File.Exists(keyfile))
{
throw new ArgumentNullException(keyfile, "解密證書未找到");
}
using (RSACryptoServiceProvider RSA = this.X509CertCreateDecryptRSA(keyfile, password))
{
Encoding encoder = Encoding.UTF8;
byte[] _encryptedData = HexStringToBytes(encryptedData);
byte[] decryptedData = RSA.Decrypt(_encryptedData, false);
return encoder.GetString(decryptedData);
}
}
最後整理了一個簡單的Demo:
Demo下載:RSACrypto.rar
參考資料:
http://dustin.iteye.com/blog/763931
http://baike.baidu.com/view/539299.htm
http://www.cnblogs.com/yjmyzz/archive/2008/08/20/1272098.html