現在很多公司開始為了保證數據庫的安全性,通常會對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 } }