Asp.Net Core实战常见加密算法(C#)

377 阅读6分钟

本文已参与「新人创作礼」活动.一起开启掘金创作之路。

Asp.Net Core实战常见加密算法(C#)

先问个问题:为什么要使用加密算法? 因为数据在网络中传输时面临4个问题:

  • 窃听
  • 假冒
  • 篡改
  • 事后否认

加密技术就是用来解决“窃听”这个问题的。通常分为两大类:对称加密和非对称加密。

  • 对称加密

    • 概念: 对称加密就是加密和解密使用同一个密钥,通常称之为“Session Key ”,这种加密技术在当今被广泛采用,如美国政府所采用的DES加密标准就是一种典型的对称加密算法,它的Session Key长度为56bits。
    • 优点: 算法公开、计算量小、加密速度快、加密效率高。适用于需要加密大量数据的场景。
    • 缺点: 由于加解密使用同一个密钥,密钥传输的过程不安全,且容易被破解,密钥管理也比较麻烦。例如:不适用于浏览器到服务器的通信,因为密钥一旦发送到浏览器端就很容易暴露。
    • 常见算法: AES,DES,3DES,TDEA,Blowfish,RC5,IDEA
  • 非对称加密

    • 概念: 非对称加密就是加密和解密所使用的不是同一个密钥,通常有两个密钥,称为“公钥”和“私钥”,它们两个必需配对使用。“公钥”是指可以对外公布的,“私钥”则不能,只能由持有人一个人知道
    • 优点: 由于加解密是用不同的密钥,私钥并不公开,这样就保证了信息在网络传输中的安全性:即使被拦截也无法解密。非常适用于客户端到服务端的数据传输。例如:支付宝的支付请求,数字签名等。
    • 缺点: 加密速度慢,比较耗资源。只适用于少量敏感信息的加密。如果加密大量消息则效率会变得低下。另外,如果动态生成公钥和私钥也比较耗资源。
    • 常见算法: RSA,Elgamal,背包算法,Rabin,D-H,ECC

  有人可能会问,上面两类加密方式怎么没有MD5?MD5……严格意义上说不是一种加密算法,因为它不能解密。它只是一种密码散列算法,只是为了校验信息用的:保证信息没有篡改。如:你下载软件或游戏时,在下载页面官方都会提供一个“MD5字符串”,你下载完成后可以用md5工具对下载到的软件md5校验,如果得到的md5串和下载页面的一致,就说明软件或游戏没有被篡改过,可放心使用。   下面我们就一块来实战几种常见的加密方式和散列算法:

DES

分类:对称加密 DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
 
namespace EncryptionPractice.Utils
{
    public class DESUtils
    {
        /// <summary> 
        /// 加密数据 
        /// </summary> 
        /// <param name="text"></param> 
        /// <param name="sessionKey"></param> 
        /// <returns></returns> 
        public static string Encrypt(string text, string sessionKey)
        {
            try
            {
                var des = GetDESProvider(sessionKey);
                var bytes = Encoding.Default.GetBytes(text);
                using var memoryStream = GetMemoryStream(des.CreateEncryptor(), bytes);
                
                var result = new StringBuilder();
                foreach (var byteItem in memoryStream.ToArray())
                {
                    result.AppendFormat("{0:X2}", byteItem);
                }
 
                return result.ToString();
 
            } catch { 
                return string.Empty; 
            }
        }
 
        /// <summary> 
        /// 解密数据 
        /// </summary> 
        /// <param name="ciphertext"></param> 
        /// <param name="sessionKey"></param> 
        /// <returns></returns> 
        public static string Decrypt(string ciphertext, string sessionKey)
        {
            try
            {
                var length = ciphertext.Length / 2;
                var bytes = new byte[length];
                for (var i=0; i<length; i++)
                {
                    var j = Convert.ToInt32(ciphertext.Substring(i * 2, 2), 16);
                    bytes[i] = (byte) j;
                }
 
                var des = GetDESProvider(sessionKey);
                using var memoryStream = GetMemoryStream(des.CreateDecryptor(), bytes);
 
                return Encoding.Default.GetString(memoryStream.ToArray());
            }
            catch
            {
                return string.Empty;
            }
        }
 
        /// <summary>
        /// 获取DES引擎
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <returns></returns>
        private static DESCryptoServiceProvider GetDESProvider(string sessionKey)
        {
            var md5Key = MD5Utils.Get32(sessionKey).Substring(8, 8);
            var des = new DESCryptoServiceProvider
            {
                Key = Encoding.ASCII.GetBytes(md5Key),
                IV = Encoding.ASCII.GetBytes(md5Key)
            };
 
            return des;
        }
 
        /// <summary>
        /// 获取内存流
        /// </summary>
        /// <param name="cryptoTransform"></param>
        /// <param name="bytes"></param>
        /// <returns></returns>
        private static MemoryStream GetMemoryStream(ICryptoTransform cryptoTransform, byte[] bytes)
        {
            var memoryStream = new MemoryStream();
            using var cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write);
            cryptoStream.Write(bytes, 0, bytes.Length);
            cryptoStream.FlushFinalBlock();
 
            return memoryStream;
        }
    }
}

\

\

AES

分类:对称加密 高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES(Data Encryption Standard),已经被多方分析且广为全世界所使用。

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
 
namespace EncryptionPractice.Utils
{
    public class AESUtils
    {
        /// <summary>
        /// 默认Key
        /// </summary>
        const string KEY = "E10ADC3949BA59AB";
 
        /// <summary>
        /// 默认偏移量
        /// </summary>
        const string IV = "BE56E057F20F883E";
 
        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="text"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static string Encrypt(string text, string key = KEY, string iv = IV)
        {
            var bytes = Encoding.UTF8.GetBytes(text);
            var result = Origin(bytes, false, key, iv);
 
            return Convert.ToBase64String(result, 0, result.Length);
        }
 
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="ciphertext"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static string Decrypt(string ciphertext, string key = KEY, string iv = IV)
        {
            var bytes = Convert.FromBase64String(ciphertext);
            var result = Origin(bytes, true, key, iv);
 
            if (result.Length < 1) 
                return string.Empty;
 
            return Encoding.UTF8.GetString(result);
        }
 
        /// <summary>
        /// 底层方法
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="isDecrypt"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        private static byte[] Origin(byte[] bytes, bool isDecrypt, string key = KEY, string iv = IV)
        {
            try
            {
                var keyBytes = Encoding.UTF8.GetBytes(key);
                var ivBytes = Encoding.UTF8.GetBytes(iv);
 
                var rijndaelManaged = new RijndaelManaged
                {
                    BlockSize = 128,
                    KeySize = 256,
                    FeedbackSize = 128,
                    Padding = PaddingMode.PKCS7,
                    Key = keyBytes,
                    IV = ivBytes,
                    Mode = CipherMode.CBC
                };
 
                var cryptoTransform = isDecrypt ? rijndaelManaged.CreateDecryptor() : rijndaelManaged.CreateEncryptor();
                var result = cryptoTransform.TransformFinalBlock(bytes, 0, bytes.Length);
 
                return result;
            }
            catch
            {
                return new byte[] { };
            }
        }
    }
}

\

\

RSA

分类:非对称加密 RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。RSA就是他们三人姓氏开头字母拼在一起组成的。RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
 
namespace EncryptionPractice.Utils
{
    public class RSAUtils
    {
        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="text">明文</param>
        /// <param name="publicKey">公钥</param>
        /// <returns>密文</returns>
        public static string Encrypt(string text, string publicKey)
        {
            var blockSize = 256; // 加密块大小,越大越慢
            var bytes = Encoding.UTF8.GetBytes(text);
            var length = bytes.Length;
 
            // rsa实例
            var rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(publicKey);
 
            var offSet = 0; // 游标
            var i = 0;
            byte[] cache;
            var ms = new MemoryStream();
            while (length - offSet > 0)
            {
                var len = length - offSet > blockSize ? blockSize : length - offSet;
                var temp = new byte[len];
                Array.Copy(bytes, offSet, temp, 0, len);
                cache = rsa.Encrypt(bytes, false);
                ms.Write(cache, 0, cache.Length);
 
                i++;
                offSet = i * blockSize;
            }
 
            var cipherBytes = ms.ToArray();
            return Convert.ToBase64String(cipherBytes);
        }
 
        /// <summary>
        /// RSA解密
        /// </summary>
        /// <param name="ciphertext">密文</param>
        /// <param name="privateKey">私钥</param>
        /// <returns>明文</returns>
        public static string Decrypt(string ciphertext, string privateKey)
        {
            var blockSize = 256;
            var bytes = Convert.FromBase64String(ciphertext);
            var length = bytes.Length;
 
            // rsa实例
            var rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(privateKey);
 
            var offSet = 0; // 游标
            var i = 0;
            byte[] cache;
            var ms = new MemoryStream();
            while (length - offSet > 0)
            {
                var len = length - offSet > blockSize ? blockSize : length - offSet;
                var temp = new byte[len];
                Array.Copy(bytes, offSet, temp, 0, len);
                cache = rsa.Decrypt(bytes, false);
                ms.Write(cache, 0, cache.Length);
 
                i++;
                offSet = i * blockSize;
            }
 
            var cipherBytes = ms.ToArray();
            return Encoding.UTF8.GetString(cipherBytes);
        }
    }
}

\

生成公钥/密钥的方法(只适用于C#,其他编程语言使用需要转换)

var rsa = new RSACryptoServiceProvider();
var publicKey = rsa.ToXmlString(false);
var privateKey = rsa.ToXmlString(true);

\

   

MD5

分类:散列算法 MD5信息摘要算法(MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开。1996年后该算法被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。

using System;
using System.Security.Cryptography;
using System.Text;
 
namespace EncryptionPractice.Utils
{
    public class MD5Utils
    {
        /// <summary>
        /// 获取16位散列值
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string Get16(string text)
        {
            return Get32(text).Substring(7, 16);
        }
 
        /// <summary>
        /// 获取32位散列值
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string Get32(string text)
        {
            using var md5 = MD5.Create();
            var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(text));
            var result = BitConverter.ToString(hash);
 
            return result.Replace("-", "").ToUpper();
        }
 
        /// <summary>
        /// 获取16位散列值 v2
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string Get16v2(string text)
        {
            return Get32v2(text).Substring(7, 16);
        }
 
        /// <summary>
        /// 获取32位散列值
        /// </summary>
        /// <param name="text">字符串</param>
        /// <returns></returns>
        public static string Get32v2(string text)
        {
            var md5 = new MD5CryptoServiceProvider();
            var hash = md5.ComputeHash(Encoding.Default.GetBytes(text));
 
            var resutl = new StringBuilder();
            for (int i = 0; i < hash.Length; i++)
            {
                resutl.Append(hash[i].ToString("x2"));
            }
 
            return resutl.ToString().ToUpper();
        }
 
    }
}

\

\

SHA-2

分类:散列算法 SHA-2,名称来自于安全散列算法2(英语:Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,由美国国家安全局研发,由美国国家标准与技术研究院(NIST)在2001年发布。属于SHA算法之一,是SHA-1的后继者。其下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。

using System.Security.Cryptography;
using System.Text;
 
namespace EncryptionPractice.Utils
{
    public class SHAUtils
    {
        /// <summary>
        /// SHA256加密
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string Encrypt(string data)
        {
            var bytes = Encoding.UTF8.GetBytes(data);
            var hash = SHA256.Create().ComputeHash(bytes);
 
            var result = new StringBuilder();
            for (int i = 0; i < hash.Length; i++)
            {
                result.Append(hash[i].ToString("x2"));
            }
 
            return result.ToString();
        }
 
    }
}