zoukankan      html  css  js  c++  java
  • 那些常用的加密算法

    前言

    本文主要讲解一下C#常用的那些加密算法。

    MD5加密

    MD5加密是最常见的加密方式,因为MD5是不可逆的,所以很多系统的密码都是用MD5加密保存的。

    虽然MD5是不可以解码的,但因为MD5加密的字符串是固定的,所以,理论上只需要建立一个庞大的数据库,把所有的字符串都加密一遍,那就可以解码所有的MD5密文了。

    虽然建立一个可以解码全部MD5的数据库不太现实,但一个五六百亿数据量的数据库就可以解码绝大部分字符串了,毕竟大部分情况下,我们的密码也是有长度限制的。

    实际应用中MD5有64位和32位加密之分,代码如下:

    #region MD5加密 32和64  
    public static string GetMd532(string ConvertString)
    {
        MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
        string t2 = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(ConvertString)), 4, 8);
        t2 = t2.Replace("-", "");
    
        return t2;
    } 
    public static string Get64Md5(string str)
    {
        string cl = str;
        string pwd = "";
        var md5 = MD5.Create();
        byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl)); 
        for (int i = 0; i < s.Length; i++)
        {
            pwd = pwd + s[i].ToString("X2");
        } 
        return pwd;
    } 
    #endregion

    我们运行一下,加密函数。

    Console.WriteLine($"MD5-64:{ MD5Helper.Get64Md5("Kiba518")}");
    Console.WriteLine($"MD5-32:{ MD5Helper.Get32Md5("Kiba518")}");

    结果如下图所示:

    SHA1加密

    SHA1加密算法与MD5加密类似,都是不可逆的,只是算法不同。所以也和MD5一样,存在容易被大数据解码的问题。

    代码如下:

    private static readonly Encoding Encoder = Encoding.UTF8;
    public static String Sha1(String content )
    {
        try
        {
            SHA1 sha1 = new SHA1CryptoServiceProvider();//创建SHA1对象
            byte[] bytes_in = Encoder.GetBytes(content);//将待加密字符串转为byte类型
            byte[] bytes_out = sha1.ComputeHash(bytes_in);//Hash运算
            sha1.Dispose();//释放当前实例使用的所有资源
            String result = BitConverter.ToString(bytes_out);//将运算结果转为string类型
            result = result.Replace("-", "").ToUpper();
            return result;
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

    运行加密函数,结果如下图所示:

    Base64加密

    准确的来说,Base64是一种编码,而不是加密,通常Base64编码后字符串会用于传输数据。 不过也因为Base64编码后字符串具有不可读性,所以,不少人也把他当做加密算法来使用。

    代码如下:

    private static readonly Encoding Encoder = Encoding.UTF8;
    public static string EncodeBase64(string source)
    {
        string target = "";
        byte[] bytes = Encoder.GetBytes(source);
        try
        {
            target = Convert.ToBase64String(bytes);
        }
        catch
        {
            target = source;
        }
        return target;
    }
    public static string DecodeBase64(string result)
    {
        string decode = "";
        byte[] bytes = Convert.FromBase64String(result);
        try
        {
            decode = Encoder.GetString(bytes);
        }
        catch
        {
            decode = result;
        }
        return decode;
    }

    运行Base64编码函数。

    string base64Str = Base64Helper.EncodeBase64("Kiba518");
    Console.WriteLine($"SHA1编码:{ base64Str}");
    Console.WriteLine($"SHA1解码:{ Base64Helper.DecodeBase64(base64Str)}");

    结果如下图所示:

    Des加密

    DES加密算法是对密钥进行保密,而公开算法,即只有拥有相同密钥的人才能解密。

    DES加密算法对密钥有要求,必须是8个字符,如abcdefgh这样的。

    代码如下:

    public static string Encrypt(string stringToEncrypt, string shortKey)
    {
        DESCryptoServiceProvider des = new DESCryptoServiceProvider();
        byte[] inputByteArray = Encoding.GetEncoding("UTF-8").GetBytes(stringToEncrypt);
        des.Key = ASCIIEncoding.UTF8.GetBytes(shortKey);
        des.IV = ASCIIEncoding.UTF8.GetBytes(shortKey);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
        cs.Write(inputByteArray, 0, inputByteArray.Length);
        cs.FlushFinalBlock();
        StringBuilder ret = new StringBuilder();
        foreach (byte b in ms.ToArray())
        {
            ret.AppendFormat("{0:X2}", b);
        }
        ret.ToString();
        return ret.ToString();
    }
    public static string Decrypt(string stringToDecrypt, string sKey)
    {
        DESCryptoServiceProvider des = new DESCryptoServiceProvider();
    ​
        byte[] inputByteArray = new byte[stringToDecrypt.Length / 2];
        for (int x = 0; x < stringToDecrypt.Length / 2; x++)
        {
            int i = (Convert.ToInt32(stringToDecrypt.Substring(x * 2, 2), 16));
            inputByteArray[x] = (byte)i;
        }
        des.Key = ASCIIEncoding.UTF8.GetBytes(sKey);
        des.IV = ASCIIEncoding.UTF8.GetBytes(sKey);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
        cs.Write(inputByteArray, 0, inputByteArray.Length);
        cs.FlushFinalBlock();
        StringBuilder ret = new StringBuilder();
        return System.Text.Encoding.Default.GetString(ms.ToArray());
    }

    如代码所示,我们使用DESCryptoServiceProvider类来进行DES加密。

    DESCryptoServiceProvider类的Mode属性可以指定加密运算模式。

    加密运算模式如下:

    CBC:密码块链模式。

    ECB:电子密码本模式。

    OFB:输出反馈模式。

    CFB:密码反馈模式。

    CTS: 密码文本窃取模式。

    在C#中默认的加密运算模式是CBC—密码块链模式。

    在Java中默认的加密运算模式是ECB—电子密码本模式。

    即,如果密文是在C#项目和Java项目之间传递,那么必须配置相同的加密运算模式。

    运行DES加密函数代码如下:

    string key_8 = "abcdefgh";
    string desShortKeyStr = DESHelper.Encrypt("Kiba518", key_8);
    Console.WriteLine($"DES加密:{ desShortKeyStr}");
    Console.WriteLine($"DES解密:{ DESHelper.Decrypt(desShortKeyStr, key_8)}");

    结果如下图所示:

    有时候,我们的密钥不是正好8个字符,那我们就截取前8为作为密钥就可以了。

    RSA加密

    RSA加密采用公钥加密,私钥解密的模式。Https的数字证书也是使用这种模式加密的。

    代码如下:

    public static string RSADecrypt(string xmlPrivateKey, string enptStr)
     {
         RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
         provider.FromXmlString(xmlPrivateKey);
         byte[] rgb = Convert.FromBase64String(enptStr);
         byte[] bytes = provider.Decrypt(rgb, RSAEncryptionPadding.OaepSHA1);
         return new UnicodeEncoding().GetString(bytes);
     }
     public static string RSAEncrypt(string xmlPublicKey, string enptStr)
     {
         RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
         provider.FromXmlString(xmlPublicKey);
         byte[] bytes = new UnicodeEncoding().GetBytes(enptStr);
         return Convert.ToBase64String(provider.Encrypt(bytes, RSAEncryptionPadding.OaepSHA1));
     }

    运行DES加密函数代码如下:

    //加密公钥  
    string publicKey = "<RSAKeyValue><Modulus>18+I2j3HU/fXQasRXOWGegP3dG75I/It2n42rgeIATeftBkoQNH73Rz0IYW++arqd0Yy5hFpNkqzY/dOmD+bDXWUheWA0P/dVZf+qeWwVV+iW3lRAU8SmnPcaD35Ic1jMEPFQVeX1zGI2ofD8aGodeSRA4+JKo+KLgyGVGDI+d0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
    //解密私钥 
    string privateKey = "<RSAKeyValue>      <Modulus>18+I2j3HU/fXQasRXOWGegP3dG75I/It2n42rgeIATeftBkoQNH73Rz0IYW++arqd0Yy5hFpNkqzY/dOmD+bDXWUheWA0P/dVZf+qeWwVV+iW3lRAU8SmnPcaD35Ic1jMEPFQVeX1zGI2ofD8aGodeSRA4+JKo+KLgyGVGDI+d0=</Modulus><Exponent>AQAB</Exponent><P>2EEAI+cO1fyvmGpg3ywMLHHZ1/X3ZrF6xZBNM2AL7bJFVfL8RS8UznUCdsL/R/o1b+lGo1CetlI++n6IvYYwyw==</P><Q>/3muAXWOU3SMKFWSDpHUgeM9kZev0ekQDefRSayXM8q9ItkaWTOJcIN614A0UGdYE6VX1ztPgveQFzm0qJDy9w==</Q><DP>NM/i/eGewOmd5IYONFJogq4nOlOKYNz1E6yC/gn1v83qmuvlaevuk+EFggVrHKPhSvxYUOgOao45bSlbsZVE8w==</DP><DQ>MKU7w91dh3iWw4tfr1SHUWAytglbGi41t2Af0taBSARftUX/pWKR1hHDD0vDKlgzRjJiooIRps966WE8jChliw==</DQ><InverseQ>YEIfQArVNP27AJn3WOBswHP/+gJ6Bk434MZ80CJONp4b6e+Ilxd2dwloxGKNbGgCyaNJEFI5J8qYSNNe0KqPkw==</InverseQ><D>ZAscSPesqLtS+WlBMkxgy719AGfVbRl+sjQiSwjIvq+3hDjJVUtCs90RO10SDBF0gfhz7f2SRY3ZnXTu5VtPF9KEQyUaY0F6eXwz4YQNzJTI2c1o5SFXZP8Ynqwltg8gNIhMe8bB6nVgASeADBim22DlSFCzmD3vt1gTI8nxmO0=</D></RSAKeyValue>";
    string myname = "my name is Kiba518!my name is Kiba518!!!!43"; //最大长度43
    string rsaStr = RSAHelper.RSAEncrypt(publicKey, myname);
    Console.WriteLine($"RSA加密:{ rsaStr}");
    string dersaStr = RSAHelper.RSADecrypt(privateKey, rsaStr);
    Console.WriteLine($"RSA解密:{ dersaStr}");

    结果如下图所示:

    RSA加密有个特点,就是他对被加密的字符串有长度限制。

    长度限制规则:待加密的字节数不能超过密钥的长度值除以 8 再减去 11(即:RSACryptoServiceProvider.KeySize / 8 - 11),而加密后得到密文的字节数,正好是密钥的长度值除以 8(即:RSACryptoServiceProvider.KeySize / 8)。注:该长度指的是byte[]数组的长度,而不是字符串的长度。

    简单来说,就是被加密字符串不能太长。

    但是,在真实的业务中,我们需要加密的字符串往往会很长,那么,RSA又对被加密字符串有长度限制,我们该怎么办呢? 很简单,把待加密的字符串拆开,每段长度都小于等于限制长度,然后分段加密,这样,问题就解决了。

    分段加密代码如下:

    public static String SubRSAEncrypt(string xmlPublicKey, string enptStr)
    {
        RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
        provider.FromXmlString(xmlPublicKey);
        Byte[] bytes = Encoder.GetBytes(enptStr);
        int MaxBlockSize = provider.KeySize / 8 - 11;    //加密块最大长度限制
    ​
        if (bytes.Length <= MaxBlockSize)
            return Convert.ToBase64String(provider.Encrypt(bytes, false));
    ​
        using (MemoryStream PlaiStream = new MemoryStream(bytes))
        using (MemoryStream CrypStream = new MemoryStream())
        {
            Byte[] Buffer = new Byte[MaxBlockSize];
            int BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);
    ​
            while (BlockSize > 0)
            {
                Byte[] ToEncrypt = new Byte[BlockSize];
                Array.Copy(Buffer, 0, ToEncrypt, 0, BlockSize);
    ​
                Byte[] Cryptograph = provider.Encrypt(ToEncrypt, false);
                CrypStream.Write(Cryptograph, 0, Cryptograph.Length);
    ​
                BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);
            }
    ​
            return Convert.ToBase64String(CrypStream.ToArray(), Base64FormattingOptions.None);
        }
    ​
    }
    /// <summary>
    /// 分段解密,应对长字符串
    /// </summary>
    /// <param name="xmlPublicKey"></param>
    /// <param name="enptStr"></param>
    /// <returns></returns>
    public static String SubRSADecrypt(string xmlPublicKey, string enptStr)
    {
        RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
        provider.FromXmlString(xmlPublicKey);
        Byte[] bytes = Convert.FromBase64String(enptStr);
        int MaxBlockSize = provider.KeySize / 8;    //解密块最大长度限制
    ​
        if (bytes.Length <= MaxBlockSize)
            return Encoder.GetString(provider.Decrypt(bytes, false));
    ​
        using (MemoryStream CrypStream = new MemoryStream(bytes))
        using (MemoryStream PlaiStream = new MemoryStream())
        {
            Byte[] Buffer = new Byte[MaxBlockSize];
            int BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);
    ​
            while (BlockSize > 0)
            {
                Byte[] ToDecrypt = new Byte[BlockSize];
                Array.Copy(Buffer, 0, ToDecrypt, 0, BlockSize);
    ​
                Byte[] Plaintext = provider.Decrypt(ToDecrypt, false);
                PlaiStream.Write(Plaintext, 0, Plaintext.Length);
    ​
                BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);
            }
    ​
            return Encoder.GetString(PlaiStream.ToArray());
        }
    }

    结果如下图所示:

    国密加密

    国密加密有以下几种模式。

    如图所示,SM3是一种数据摘要计算,与MD5和SHA1类似,都是不可逆的。而SM2算法中还需要使用SM3对数据加密。

    C#使用国密加密,首先引用BouncyCastle.Crypto.dll。

    具体使用方式参考网址:https://www.cnblogs.com/valu/p/12842778.html

    Demo中有代码具体封装的代码。

    调用代码如下:

    #region SM3 不可逆
     byte[] md = new byte[32];
     byte[] msg1 = Encoding.Default.GetBytes("KIBA518");
     SM3Digest sm3 = new SM3Digest();
     sm3.BlockUpdate(msg1, 0, msg1.Length);
     sm3.DoFinal(md, 0);
     System.String s = new UTF8Encoding().GetString(Hex.Encode(md));
     System.Console.Out.WriteLine(s.ToUpper());
    ​
     #endregion
    ​
     #region SM2
     SM2Utils.GenerateKeyPair();
    ​
     String plainText = "KIBA518";
     byte[] sourceData = Encoding.Default.GetBytes(plainText);
    ​
     //下面的秘钥可以使用generateKeyPair()生成的秘钥内容  
     // 国密规范正式私钥  
     String prik = "3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94";
     // 国密规范正式公钥  
     String pubk = "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A";
    ​
     System.Console.Out.WriteLine("加密: ");
     String cipherText = SM2Utils.Encrypt(Hex.Decode(pubk), sourceData);
     System.Console.Out.WriteLine(cipherText);
     System.Console.Out.WriteLine("解密: ");
     plainText = Encoding.Default.GetString(SM2Utils.Decrypt(Hex.Decode(prik), Hex.Decode(cipherText)));
     System.Console.Out.WriteLine(plainText);
    ​
     Console.ReadLine();
     #endregion
    

    结果如下图所示

    结语

    到此C#常用的那些加密算法就介绍完了,下面我们一起看一下,同一字符串,加密后情况。

    可以看到,不同加密方式得到的密文长度都不一样,其中DES加密后在Base64编码的模式的密文长度最短。RSA加密的密文最长。

    ----------------------------------------------------------------------------------------------------

    到此那些常用的加密算法基本使用已经介绍完了,代码已经传到Github上了,欢迎大家下载。

    代码已经传到Github上了,欢迎大家下载。

    Github地址: https://github.com/kiba518/EncryptionDemo

    ----------------------------------------------------------------------------------------------------

    注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
    若您觉得这篇文章还不错,请点击下方的推荐】,非常感谢!

    https://www.cnblogs.com/kiba/p/14028476.html

     

  • 相关阅读:
    【训练题】最优比率生成树 P1696
    2019/9/15 校内模拟赛 考试报告
    b 解题报告
    HDU4714 Tree2cycle 解题报告
    2019/9/2 校内练习赛 考试报告
    2019/8/31 校内模拟赛 考试报告
    2019/8/29 校内模拟赛 考试报告
    康托展开
    洛谷P3807卢卡斯定理
    矩阵
  • 原文地址:https://www.cnblogs.com/kiba/p/14028476.html
Copyright © 2011-2022 走看看