BouncyCastle.Crypto.dll
該庫的源代碼下載地址:http://www.bouncycastle.org/csharp/download/bccrypto-net-1.7-src.zip
BigInteger類具有RSA加解密的功能,下載地址:
http://www.codeproject.com/KB/cs/biginteger.aspx
對pem密鑰文件的解析參考代碼:
http://www.codeproject.com/KB/security/CryptoInteropKeys.aspx
————————————————————————————————————————————————
使用pem格式RSA密鑰文件加解密,大致從兩個方面介紹
一、對RSA文件格式的解析
a) RSA文件的生成(openssl的使用方法)
b) RSA文件在不同平臺中的解析方式(解析代碼)
二、對解析出來的公鑰,私鑰的使用方法
a) Java平臺上的不同的加解密方式(公鑰加密,私鑰解密/私鑰加密,公鑰解密)
b) .net平臺上的不同的加解密方式(私鑰加密,公鑰解密/公鑰加密,私鑰解密)
從根本上解決不同平臺RSA密鑰互通的問題。
.net平臺pem文件解析方式:NF上解析,CF平臺解析,(CF:compactframework)
u 使用BigInteger類進行公鑰解密
pem文件的解析
對pem密鑰文件的解析參考代碼:
http://www.codeproject.com/KB/security/CryptoInteropKeys.aspx
爲了使該代碼可以在CF平臺上也能使用,對其做了一些修改。
首先爲了方便解析pem文件,在AsnKeyParser類中添加了一個構造函數,和一個變量。(類本身提供了一個internal AsnKeyParser(Stringpathname)方法用來解析pem文件。)
internal AsnKeyParser(AsnParserparser)
{
this.parser = parser;
}
private AsnParserparser;
//(AsnParser是AsnKeyParser.cs文件中的一個類)。
然後是從公鑰字符串中獲取公鑰的代碼:
byte[] binKey = System.Convert.FromBase64String(pub_key);
// Base64解碼,pub_key是公鑰字符串
AsnParser parser = newAsnParser(binKey);
AsnKeyParser keyParser = newAsnKeyParser(parser);
RSAParameters publicKey =keyParser.ParseRSAPublicKey();
//至此爲止獲得了公鑰
使用BigInteger類作公鑰解密
由於.net平臺上提供的RSACryptoServiceProvider只能用作公鑰加密,私鑰解密,(和其內部實現有關)。如果要使用私鑰加密,公鑰解密,可以依靠第三方,使用標準RSA算法實現的組件。
以上所提到的BigIngeter類提供了標準的RSA加解密算法,
BigInteger類具有解密的功能,下載地址:
http://www.codeproject.com/KB/cs/biginteger.aspx
使用公鑰解密的具體方法如下:
byte[] data = Convert.FromBase64String(enStr);//enStr爲密文
//byte[] data =HexStringToByteArray(enStr);
//如果密文是16進制字符串可以使用HexStringToByteArray方法轉換爲字節數組
BigInteger biN = newBigInteger(publicKey.Modulus);
BigInteger biE = newBigInteger(publicKey.Exponent);
BigInteger biText = newBigInteger(data);
BigInteger biEnText = biText.modPow(biE, biN);
string temp =byteToHexStr(biEnText.getBytes());
//十六進制字符串轉爲byte數組
private static byte[] HexStringToByteArray(stringsBytes)
{
int pos = 0;
int len = (sBytes.Length / 2);
byte[] b = newbyte[len];
int count = sBytes.Length;
for (int i= 0; i < count; i += 2)
{
b[pos] = Convert.ToByte(sBytes.Substring(i,2), 16);
pos++;
}
//string temp =Encoding.Default.GetString(b);
return b;
}
/// <summary>
/// 字節數組轉16進制字符串
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static string byteToHexStr(byte[]bytes)
{
string returnStr = "";
if (bytes != null)
{
for (int i= 0; i < bytes.Length; i++)
{
returnStr += bytes[i].ToString("X2");
}
}
return returnStr;
}
由於我的原文是16進制的字符串,在解密的過程中發現如果原文的字節中有00的話解密會有異常,原文第一字節如果是00,解密出來會被拋棄,只要手工加上00,如果是第2,3,4字節是00的話,修改BigInteger中的getBytes方法便可解決,修改如下:
public byte[] getBytes()
{
int numBits = bitCount();
int numBytes = numBits >> 3;
if ((numBits & 0x7) != 0)
numBytes++;
byte[] result = newbyte[numBytes];
//Console.WriteLine(result.Length);
int pos = 0;
uint tempVal, val = data[dataLength - 1];
if ((tempVal = (val >> 24 &0xFF)) != 0)
{ result[pos++] = (byte)tempVal; }
if ((tempVal = (val >> 16 &0xFF)) != 0)
{ result[pos++] = (byte)tempVal; }
else if (pos> 0)
{ pos++; }
else
{ result[pos++] = (byte)tempVal; }
if ((tempVal = (val >> 8 &0xFF)) != 0)
{ result[pos++] = (byte)tempVal; }
else if (pos> 0)
{ pos++; }
else
{ result[pos++] = (byte)tempVal; }
if ((tempVal = (val & 0xFF)) != 0)
{ result[pos++] = (byte)tempVal; }
else
{ result[pos++] = (byte)tempVal; }
for (int i= dataLength - 2; i >= 0; i--, pos += 4)
{
val = data[i];
result[pos + 3] = (byte)(val & 0xFF);
val >>= 8;
result[pos + 2] = (byte)(val & 0xFF);
val >>= 8;
result[pos + 1] = (byte)(val & 0xFF);
val >>= 8;
result[pos] = (byte)(val& 0xFF);
}
return result;
}
u 使用開源的BouncyCastle.Crypto.dl組件庫來作加解密
該庫的源代碼下載地址:http://www.bouncycastle.org/csharp/download/bccrypto-net-1.7-src.zip
使用時,先導入其中crypto\bzip2,csharp\crypto\src兩個文件夾所有的內容
然後刪除crypto\src\ AssemblyInfo.cs,crypto\src\asn1\util\ Dump.cs文件
crypto\src\util\Platform.cs類中編寫了平臺與編譯選擇代碼,如果要在WinCE平臺(CF)上使用,需要在條件預編譯中加上條件編譯,右鍵點擊項目》屬性
在條件編譯符號在加上:NETCF_2_0,
對平臺的支持情況,可以參看crypto\src\util\ Platform.cs類中的條件預編譯代碼
對於WinForm中可以直接使用BouncyCastle.Crypto.dl庫
下載地址:http://www.bouncycastle.org/csharp/download/bccrypto-net-1.7-bin.zip
調用的代碼如下:(還是使用公鑰解密密文)
using System.Security.Cryptography;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.OpenSsl;
TextReader xl = newStreamReader("c:/pub.key");
//pub.key文件格式如下:
-----BEGIN PUBLIC KEY-----
MEwwDQasdf…………………Y6oTv3w1hq+zSCzcw6Mv+a6Kx3
CMpgg9jDGmGwdp4mg5LopYag0ZYHq21AJwIDAQAB
-----END PUBLIC KEY-----
PemReader y1 = newPemReader(xl);
string sign = "mt25lD1UX9fnf+96v1Y8hlvIgW0Uou3H7LivTeiQaSoXFNzHaBntuFz2NDIe7XGF";
byte[] data = System.Convert.FromBase64String(sign);
AsymmetricKeyParameter pubkey = (AsymmetricKeyParameter)y1.ReadObject();
IAsymmetricBlockCipher engine = newRsaEngine();
engine.Init(false,pubkey);
byte[] testData = engine.ProcessBlock(data,0, data.Length);
string temp = byteToHexStr(testData); //字節數組轉換爲16進制字符串
在CE平臺調用上有些差異,調用方法如下:
string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName);
TextReader xl = newStreamReader(appPath+"\\pub.key");
PemReader y1 = newPemReader(xl);
string sign = "mt25lD1UX9fnf+96v1Y8hlvIgW0Uou3H7LivTeiQaSoXFNzHaBntuFz2NDIe7XGF";
byte[] data = System.Convert.FromBase64String(sign);
PemObject ss1=y1.ReadPemObject();
AsymmetricKeyParameter pubkey = PublicKeyFactory.CreateKey(ss1.Content);
IAsymmetricBlockCipher engine = newRsaEngine();
engine.Init(false,pubkey);
byte[] testData = engine.ProcessBlock(data,0, data.Length);
string temp = byteToHexStr(testData);