http://www.cnblogs.com/revealit/p/6094750.html基於C#的RSA非對稱加密算法

最近在搞單點登陸的設計,在設計中須要一個Token令牌的加密傳輸,這個令牌在整個鏈接單點的各個站中起着鏈接認證做用,若是被仿造將會有不可預計的損失,可是這個Token是要可逆的。因此像那種md5,sha之類的不可逆加密就無法用了,而後可逆的加密主要是分爲對稱加密和非對稱加密。html

  • 對稱加密:用加密的鑰匙來解密,好比DES,AES的加解密。
  • 非對稱加密:一個鑰匙加密,用另外一個鑰匙解密。

直接看下面的方法:算法

一、首先生成密鑰對數組

?
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
/// <summary>
/// RSA加密的密匙結構  公鑰和私匙
/// </summary>
public struct RSAKey
{
     public string PublicKey { get ; set ; }
     public string PrivateKey { get ; set ; }
}
 
#region 獲得RSA密匙對
/// <summary>
/// 獲得RSA密匙對
/// </summary>
/// <returns></returns>
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字符串
/// <summary>
/// 將密鑰組合成base64編碼字符串
/// </summary>
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);
}
 
/// <summary>
/// 從base64字符串,解析原來的密鑰
/// </summary>
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密碼,把公鑰和私鑰分別轉爲密鑰字符串,把密鑰字符串轉爲對應的公私鑰。安全

爲何多了一個公私鑰和字符串之間的相互轉換,太蛋疼的動做,好吧,我懂你。ide

二、公有的明文加解密算法測試

?
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 字符串加密解密 公開方法
/// <summary>
/// 字符串加密
/// </summary>
/// <param name="source">源字符串 明文</param>
/// <param name="key">密匙</param>
/// <returns>加密遇到錯誤將會返回原字符串</returns>
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;
}
 
/// <summary>
/// 字符串解密
/// </summary>
/// <param name="encryptString">密文</param>
/// <param name="key">密鑰</param>
/// <returns>遇到解密失敗將會返回原字符串</returns>
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

三、私有的加解密算法ui

複製代碼
#region 字符串加密解密 私有  實現加解密的實現方法
/// <summary>
/// 用指定的密匙加密 
/// </summary>
/// <param name="source">明文</param>
/// <param name="d">能夠是RSACryptoServiceProvider生成的D</param>
/// <param name="n">能夠是RSACryptoServiceProvider生成的Modulus</param>
/// <returns>返回密文</returns>
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('@');
}

/// <summary>
/// 用指定的密匙加密 
/// </summary>
/// <param name="source">密文</param>
/// <param name="e">能夠是RSACryptoServiceProvider生成的Exponent</param>
/// <param name="n">能夠是RSACryptoServiceProvider生成的Modulus</param>
/// <returns>返回明文</returns>
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
複製代碼

四、使用方式編碼

?
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加密

 

附:spa

都說RSA解密效率過低,這裏附加一個表:

序號

原文件大小(KB

加密後文件大小(KB

加密用時(

解密用時(

1      

6

6

0

1

2      

12

12

0

3

3      

24

24

0

5

4      

45

45

0

10

5      

90

90

1

21

6      

180

180

2

40

7      

360

360

2

98

8      

720

721

2

165

9      

1440

1440

5

325

因爲Token才幾百個字節,效率上沒測試過解密效果,但安全和這若干毫秒哪一個更重要?答案不言而明。

相關文章
相關標籤/搜索