本文已参与「新人创作礼」活动.一起开启掘金创作之路。
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();
}
}
}