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才几百个字节,效率上没测试过解密效果,但安全和这若干毫秒哪个更重要?答案不言而明。

C