zoukankan      html  css  js  c++  java
  • 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 + " ");
    Console.WriteLine("私钥:" + keyPair.PrivateKey + " ");
    string en = RSAHelper.EncryptString(str, keyPair.PrivateKey);
    Console.WriteLine("加密后:"+en + " ");
    Console.WriteLine("解密:"+RSAHelper.DecryptString(en, keyPair.PublicKey) + " ");
    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才几百个字节,效率上没测试过解密效果,但安全和这若干毫秒哪个更重要?答案不言而明。

  • 相关阅读:
    新工作 Day24 周六
    新工作 Day23 周五
    新工作 Day22 周四
    新工作 Day21 周三
    新工作 Day20 周二
    新工作 Day19 周一
    新工作 Day18 周日
    新工作 Day17 周六
    java线程池 多线程搜索文件包含关键字所在的文件路径
    java实现搜索文件夹中所有文件包含的关键字的文件路径(递归搜索)
  • 原文地址:https://www.cnblogs.com/Chareree/p/8708667.html
Copyright © 2011-2022 走看看