http://www.cnblogs.com/revealit/p/6094750.html基于C#的RSA非对称加密算法
最近在搞单点登录的设计,在设计中需要一个Token令牌的加密传输,这个令牌在整个连接单点的各个站中起着连接认证作用,如果被仿造将会有不可预计的损失,但是这个Token是要可逆的。所以像那种md5,sha之类的不可逆加密就没法用了,然后可逆的加密主要是分为对称加密和非对称加密。
- 对称加密:用加密的钥匙来解密,比如DES,AES的加解密。
- 非对称加密:一个钥匙加密,用另一个钥匙解密。
直接看下面的方法:
1、首先生成密钥对
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
///
/// RSA加密的密匙结构 公钥和私匙
///
public struct RSAKey
{
public string PublicKey { get; set; }
public string PrivateKey { get; set; }
}
#region 得到RSA密匙对
///
/// 得到RSA密匙对
///
///
public static RSAKey GetRASKey()
{
RSACryptoServiceProvider.UseMachineKeyStore = true;
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(DWKEYSIZE);
RSAParameters p = rsaProvider.ExportParameters(true);
return new RSAKey()
{
PublicKey = ComponentKey(p.Exponent, p.Modulus),
PrivateKey = ComponentKey(p.D, p.Modulus)
};
}
#endregion
#region 将密匙组合成base64字符串
///
/// 将密钥组合成base64编码字符串
///
private static string ComponentKey(byte[] b1, byte[] b2)
{
List<byte> list = new List<byte>();
list.Add((byte)b1.Length);
list.AddRange(b1);
list.AddRange(b2);
byte[] b = list.ToArray<byte>();
return Convert.ToBase64String(b);
}
///
/// 从base64字符串,解析原来的密钥
///
private static void ResolveKey(string key, out byte[] b1, out byte[] b2)
{
//从base64字符串 解析成原来的字节数组
byte[] b = Convert.FromBase64String(key);
//初始化参数的数组长度
b1 = new byte[b[0]];
b2 = new byte[b.Length - b[0] - 1];
//将相应位置是值放进相应的数组
for (int n = 1, i = 0, j = 0; n < b.Length; n++)
{
if (n <= b[0])
{
b1[i++] = b[n];
}
else
{
b2[j++] = b[n];
}
}
}
#endregion
|
简要的说明一下上面这段代码,做了3件事:生成RSA密码,把公钥和私钥分别转为密钥字符串,把密钥字符串转为对应的公私钥。
为什么多了一个公私钥和字符串之间的相互转换,太蛋疼的动作,好吧,我懂你。
2、公有的明文加解密算法
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
#region 字符串加密解密 公开方法
///
/// 字符串加密
///
/// 源字符串 明文
/// 密匙
///
public static string EncryptString(string source, string key)
{
string encryptString = string.Empty;
byte[] d;
byte[] n;
try
{
if (!CheckSourceValidate(source))
{
throw new Exception("source string too long");
}
//解析这个密钥
ResolveKey(key, out d, out n);
BigInteger biN = new BigInteger(n);
BigInteger biD = new BigInteger(d);
encryptString = EncryptString(source, biD, biN);
}
catch
{
encryptString = source;
}
return encryptString;
}
///
/// 字符串解密
///
/// 密文
/// 密钥
///
public static string DecryptString(string encryptString, string key)
{
string source = string.Empty;
byte[] e;
byte[] n;
try
{
//解析这个密钥
ResolveKey(key, out e, out n);
BigInteger biE = new BigInteger(e);
BigInteger biN = new BigInteger(n);
source = DecryptString(encryptString, biE, biN);
}
catch
{
source = encryptString;
}
return source;
}
#endregion
|
3、私有的加解密算法
#region 字符串加密解密 私有 实现加解密的实现方法 ////// 用指定的密匙加密 /// /// 明文 /// 可以是RSACryptoServiceProvider生成的D /// 可以是RSACryptoServiceProvider生成的Modulus ///返回密文 private static string EncryptString(string source, BigInteger d, BigInteger n) { int len = source.Length; int len1 = 0; int blockLen = 0; if ((len % 128) == 0) len1 = len / 128; else len1 = len / 128 + 1; string block = ""; StringBuilder result = new StringBuilder(); for (int i = 0; i < len1; i++) { if (len >= 128) blockLen = 128; else blockLen = len; block = source.Substring(i * 128, blockLen); byte[] oText = System.Text.Encoding.Default.GetBytes(block); BigInteger biText = new BigInteger(oText); BigInteger biEnText = biText.modPow(d, n); string temp = biEnText.ToHexString(); result.Append(temp).Append("@"); len -= blockLen; } return result.ToString().TrimEnd('@'); } ////// 用指定的密匙加密 /// /// 密文 /// 可以是RSACryptoServiceProvider生成的Exponent /// 可以是RSACryptoServiceProvider生成的Modulus ///返回明文 private static string DecryptString(string encryptString, BigInteger e, BigInteger n) { StringBuilder result = new StringBuilder(); string[] strarr1 = encryptString.Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < strarr1.Length; i++) { string block = strarr1[i]; BigInteger biText = new BigInteger(block, 16); BigInteger biEnText = biText.modPow(e, n); string temp = System.Text.Encoding.Default.GetString(biEnText.getBytes()); result.Append(temp); } return result.ToString(); } #endregion
4、使用方式
?| 1 2 3 4 5 6 7 8 |
string str = "{\"sc\":\"his51\",\"no\":\"1\",\"na\":\"管理员\"}{\"sc\":\"@his51\",\"no\":\"1\",\"na\":\"管理员\"}{\"sc\":\"his51\",\"no\":\"1\",\"na\":\"管员\"}{\"sc\":\"his522";
RSAHelper.RSAKey keyPair = RSAHelper.GetRASKey();
Console.WriteLine("公钥:" + keyPair.PublicKey + "\r\n");
Console.WriteLine("私钥:" + keyPair.PrivateKey + "\r\n");
string en = RSAHelper.EncryptString(str, keyPair.PrivateKey);
Console.WriteLine("加密后:"+en + "\r\n");
Console.WriteLine("解密:"+RSAHelper.DecryptString(en, keyPair.PublicKey) + "\r\n");
Console.ReadKey();
|
附件:RSAtest.rar
附:
都说RSA解密效率太低,这里附加一个表:
|
序号 |
原文件大小(KB) |
加密后文件大小(KB) |
加密用时(秒) |
解密用时(秒) |
|
1 |
||||
|
2 |
12 |
12 |
||
|
3 |
24 |
24 |
||
|
4 |
45 |
45 |
10 |
|
|
5 |
90 |
90 |
21 |
|
|
6 |
180 |
180 |
40 |
|
|
7 |
360 |
360 |
98 |
|
|
8 |
720 |
721 |
165 |
|
|
9 |
1440 |
1440 |
325 |
由于Token才几百个字节,效率上没测试过解密效果,但安全和这若干毫秒哪个更重要?答案不言而明。