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
/// <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密码,把公钥和私钥分别转为密钥字符串,把密钥字符串转为对应的公私钥。

为什么多了一个公私钥和字符串之间的相互转换,太蛋疼的动作,好吧,我懂你。

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 字符串加密解密 公开方法
/// <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

3、私有的加解密算法

复制代码
#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
复制代码

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      

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

posted on 2018-04-03 15:17  陈-chen  阅读(256)  评论(0编辑  收藏  举报