现在很多公司开始为了保证数据库的安全性,通常会对Web.Config的数据库连接字符串进行加密。本文将介绍学习使用Aes加密解密数据库连接字符串。本文采用MySql数据库。
- AES概念简述
AES 是对称的高级加密标准算法(PS:对称加密就是加密用的密码和解密用的密码是一样的,非对称就是加密和解密用的密钥不一样)。
参考步骤:
1、Aes加密、解密工具
2、配置Web.Config
3、自定义数据库连接类
4、Aes加密、解密类
- Aes加密、解密工具
对数据库连接字符串进行加密,大家也可以使用在线的加密解密工具方式。
下图中"hema"为秘钥(Key)。
- 配置Web.Config
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <entityFramework>
<defaultConnectionFactory type="Hema.Dao.CustomMySqlConnectionFactory, Hema.Dao" > <parameters>
//数据Aes加密串 <parameter value="KrwK655bTg0YL0OYBllvwYM+BY6ioLMkizpMQEBL/VPB4gi0O1R15DR+BDfvCc0wOCgo+5/amzDz5bT7+On6rn5MPBIRFh5UTSOYgprJsdNCBrWOU7JfssLGpJOP3PJg" /> </parameters> </defaultConnectionFactory> <providers> <provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6" /> </providers> </entityFramework> </configuration>
<defaultConnectionFactory>项只会在没有添加connectionString配置项的情况下使用,默认值是LocalDbConnectionFactory,也就是使用LocalDb。我们可以将type改为"Hema.Dao.CustomMySqlConnectionFactory, Hema.Dao",这样就可以使用自定义类连接MySql数据库。
- 自定义数据库连接类
using MySql.Data.Entity;
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Data.Entity.Core.Common;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Hema.Framework.Core;
namespace Hema.Dao
{
//继承IDbConnectionFactory接口,此接口的实现用来基于给定的数据库名称创建某个数据库服务器类型的 DbConnection 对象。
public class CustomMySqlConnectionFactory : IDbConnectionFactory
{
public string _connectionString;
//秘钥
public const string Conn_EncryptKey = "hema";
public CustomMySqlConnectionFactory()
{
}
public CustomMySqlConnectionFactory(string connectionString)
{
//解密
_connectionString = EncryptUtility.AESDecrypt(connectionString, Conn_EncryptKey);
}
public System.Data.Common.DbConnection CreateConnection(string nameOrConnectionString)
{
//新建一个MySqlConnection数据库连接
return new MySqlConnection(_connectionString);
}
}
}
- Aes加密、解密类
using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Xml; namespace Hema.Framework.Core { public class EncryptUtility { #region AES /// <summary> /// AES加密 /// </summary> /// <param name="encryptString">要加密的字符</param> /// <param name="encryptKey">对应的密钥(不可为中文,不能超过32个字符,超过32个字符的截取前32个字符)</param> /// <returns>返回Base64格式的字符串</returns> public static string AESEncrypt(string encryptString, string encryptKey, string vector = null) { if (string.IsNullOrEmpty(encryptString)) { throw new ArgumentNullException("参数encryptString为空!"); } if (string.IsNullOrEmpty(encryptKey)) { throw new ArgumentNullException("参数encryptKey为空!"); } if (encryptKey.Length > 32) encryptKey = encryptKey.Substring(0, 32); if (encryptKey.Length < 32) encryptKey = encryptKey.PadRight(32, '0'); RijndaelManaged rijndaelProvider = new RijndaelManaged(); rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey); if (string.IsNullOrEmpty(vector)) { rijndaelProvider.Mode = CipherMode.ECB; } else { rijndaelProvider.IV = Encoding.UTF8.GetBytes(vector); } rijndaelProvider.Padding = PaddingMode.PKCS7; // 填充模式 ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor(); byte[] inputData = Encoding.UTF8.GetBytes(encryptString); byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length); return Convert.ToBase64String(encryptedData); } /// <summary> /// AES解密 /// </summary> /// <param name="decryptString">要解密的字符(该字符必须是已经加密过的Base64格式的字符串)</param> /// <param name="decryptKey">解密的密钥,该密钥要和加密的密钥一致(不可为中文,不能超过32个字符,超过32个字符的截取前32个字符)</param> /// <returns>解密后的字符串</returns> public static string AESDecrypt(string decryptString, string decryptKey, string vector = null) { if (string.IsNullOrEmpty(decryptString)) { throw new ArgumentNullException("参数encryptString为空!"); } if (string.IsNullOrEmpty(decryptKey)) { throw new ArgumentNullException("参数encryptKey为空!"); } if (decryptKey.Length > 32) decryptKey = decryptKey.Substring(0, 32); if (decryptKey.Length < 32) decryptKey = decryptKey.PadRight(32, '0'); try { RijndaelManaged rijndaelProvider = new RijndaelManaged(); rijndaelProvider.Key = Encoding.UTF8.GetBytes(decryptKey); if (string.IsNullOrEmpty(vector)) { rijndaelProvider.Mode = CipherMode.ECB; } else { rijndaelProvider.IV = Encoding.UTF8.GetBytes(vector); } rijndaelProvider.Padding = PaddingMode.PKCS7; // 填充模式 ICryptoTransform rijndaelDecrypt = rijndaelProvider.CreateDecryptor(); byte[] inputData = Convert.FromBase64String(decryptString); byte[] decryptedData = rijndaelDecrypt.TransformFinalBlock(inputData, 0, inputData.Length); return Encoding.UTF8.GetString(decryptedData); } catch { return string.Empty; } } /// <summary> /// 加密文件流 /// </summary> /// <param name="fs"></param> /// <returns></returns> public static CryptoStream AES_EncryptStrream(FileStream fs, string decryptKey, string vector) { decryptKey = GetSubString(decryptKey, 32, ""); decryptKey = decryptKey.PadRight(32, ' '); RijndaelManaged rijndaelProvider = new RijndaelManaged(); rijndaelProvider.Key = Encoding.UTF8.GetBytes(decryptKey); rijndaelProvider.IV = Encoding.UTF8.GetBytes(vector); ICryptoTransform encrypto = rijndaelProvider.CreateEncryptor(); CryptoStream cytptostreamEncr = new CryptoStream(fs, encrypto, CryptoStreamMode.Write); return cytptostreamEncr; } /// <summary> /// 解密文件流 /// </summary> /// <param name="fs"></param> /// <returns></returns> public static CryptoStream AES_DecryptStream(FileStream fs, string decryptKey, string vector) { decryptKey = GetSubString(decryptKey, 32, ""); decryptKey = decryptKey.PadRight(32, ' '); RijndaelManaged rijndaelProvider = new RijndaelManaged(); rijndaelProvider.Key = Encoding.UTF8.GetBytes(decryptKey); rijndaelProvider.IV = Encoding.UTF8.GetBytes(vector); ICryptoTransform Decrypto = rijndaelProvider.CreateDecryptor(); CryptoStream cytptostreamDecr = new CryptoStream(fs, Decrypto, CryptoStreamMode.Read); return cytptostreamDecr; } /// <summary> /// 对指定文件加密 /// </summary> /// <param name="InputFile"></param> /// <param name="OutputFile"></param> /// <returns></returns> public static bool AES_EncryptFile(string InputFile, string OutputFile, string vector) { try { string decryptKey = "www.iqidi.com"; FileStream fr = new FileStream(InputFile, FileMode.Open); FileStream fren = new FileStream(OutputFile, FileMode.Create); CryptoStream Enfr = AES_EncryptStrream(fren, decryptKey, vector); byte[] bytearrayinput = new byte[fr.Length]; fr.Read(bytearrayinput, 0, bytearrayinput.Length); Enfr.Write(bytearrayinput, 0, bytearrayinput.Length); Enfr.Close(); fr.Close(); fren.Close(); } catch { //文件异常 return false; } return true; } /// <summary> /// 对指定的文件解压缩 /// </summary> /// <param name="InputFile"></param> /// <param name="OutputFile"></param> /// <returns></returns> public static bool AES_DecryptFile(string InputFile, string OutputFile, string vector) { try { string decryptKey = "www.iqidi.com"; FileStream fr = new FileStream(InputFile, FileMode.Open); FileStream frde = new FileStream(OutputFile, FileMode.Create); CryptoStream Defr = AES_DecryptStream(fr, decryptKey, vector); byte[] bytearrayoutput = new byte[1024]; int m_count = 0; do { m_count = Defr.Read(bytearrayoutput, 0, bytearrayoutput.Length); frde.Write(bytearrayoutput, 0, m_count); if (m_count < bytearrayoutput.Length) break; } while (true); Defr.Close(); fr.Close(); frde.Close(); } catch { //文件异常 return false; } return true; } /// <summary> /// 按字节长度(按字节,一个汉字为2个字节)取得某字符串的一部分 /// </summary> /// <param name="sourceString">源字符串</param> /// <param name="length">所取字符串字节长度</param> /// <param name="tailString">附加字符串(当字符串不够长时,尾部所添加的字符串,一般为"...")</param> /// <returns>某字符串的一部分</returns> private static string GetSubString(string sourceString, int length, string tailString) { return GetSubString(sourceString, 0, length, tailString); } /// <summary> /// 按字节长度(按字节,一个汉字为2个字节)取得某字符串的一部分 /// </summary> /// <param name="sourceString">源字符串</param> /// <param name="startIndex">索引位置,以0开始</param> /// <param name="length">所取字符串字节长度</param> /// <param name="tailString">附加字符串(当字符串不够长时,尾部所添加的字符串,一般为"...")</param> /// <returns>某字符串的一部分</returns> private static string GetSubString(string sourceString, int startIndex, int length, string tailString) { string myResult = sourceString; //当是日文或韩文时(注:中文的范围:u4e00 - u9fa5, 日文在u0800 - u4e00, 韩文为xAC00-xD7A3) if (System.Text.RegularExpressions.Regex.IsMatch(sourceString, "[u0800-u4e00]+") || System.Text.RegularExpressions.Regex.IsMatch(sourceString, "[xAC00-xD7A3]+")) { //当截取的起始位置超出字段串长度时 if (startIndex >= sourceString.Length) { return string.Empty; } else { return sourceString.Substring(startIndex, ((length + startIndex) > sourceString.Length) ? (sourceString.Length - startIndex) : length); } } //中文字符,如"中国人民abcd123" if (length <= 0) { return string.Empty; } byte[] bytesSource = Encoding.Default.GetBytes(sourceString); //当字符串长度大于起始位置 if (bytesSource.Length > startIndex) { int endIndex = bytesSource.Length; //当要截取的长度在字符串的有效长度范围内 if (bytesSource.Length > (startIndex + length)) { endIndex = length + startIndex; } else { //当不在有效范围内时,只取到字符串的结尾 length = bytesSource.Length - startIndex; tailString = ""; } int[] anResultFlag = new int[length]; int nFlag = 0; //字节大于127为双字节字符 for (int i = startIndex; i < endIndex; i++) { if (bytesSource[i] > 127) { nFlag++; if (nFlag == 3) { nFlag = 1; } } else { nFlag = 0; } anResultFlag[i] = nFlag; } //最后一个字节为双字节字符的一半 if ((bytesSource[endIndex - 1] > 127) && (anResultFlag[length - 1] == 1)) { length = length + 1; } byte[] bsResult = new byte[length]; Array.Copy(bytesSource, startIndex, bsResult, 0, length); myResult = Encoding.Default.GetString(bsResult); myResult = myResult + tailString; return myResult; } return string.Empty; } #endregion } }