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

  • 相关阅读:
    LeetCode Path Sum II
    LeetCode Longest Palindromic Substring
    LeetCode Populating Next Right Pointers in Each Node II
    LeetCode Best Time to Buy and Sell Stock III
    LeetCode Binary Tree Maximum Path Sum
    LeetCode Find Peak Element
    LeetCode Maximum Product Subarray
    LeetCode Intersection of Two Linked Lists
    一天一个设计模式(1)——工厂模式
    PHP迭代器 Iterator
  • 原文地址:https://www.cnblogs.com/Chareree/p/8708667.html
Copyright © 2011-2022 走看看