對稱加密算法是指加密和解密採用相同的密鑰,是可逆的(便可解密)。html
AES加密算法是密碼學中的高級加密標準,採用的是對稱分組密碼體制,密鑰長度的最少支持爲128。AES加密算法是美國聯邦政府採用的區塊加密標準,這個標準用來替代原先的DES,已經被多方分析且廣爲全世界使用。web
AES數學原理詳解:http://www.javashuo.com/article/p-majyrkax-cn.html算法
優勢:加密速度快api
缺點:密鑰的傳遞和保存是一個問題,參與加密和解密的雙方使用的密鑰是同樣的,這樣密鑰就很容易泄露。數組
非對稱加密算法是指加密和解密採用不一樣的密鑰(公鑰和私鑰),所以非對稱加密也叫公鑰加密,是可逆的(便可解密)。公鑰密碼體制根據其所依據的難題通常分爲三類:大素數分解問題類、離散對數問題類、橢圓曲線類。安全
RSA加密算法是基於一個十分簡單的數論事實:將兩個大素數相乘十分容易,可是想要對其乘積進行因式分解極其困難,所以能夠將乘積公開做爲加密密鑰。雖然RSA的安全性一直未能獲得理論上的證實,但它經歷了各類攻擊至今未被徹底攻破。 網絡
優勢:加密和解密的密鑰不一致,公鑰是能夠公開的,只需保證私鑰不被泄露便可,這樣就密鑰的傳遞變的簡單不少,從而下降了被破解的概率。框架
缺點:加密速度慢ide
RSA加密算法既能夠用來作數據加密,也能夠用來數字簽名。工具
--數據加密過程:發送者用公鑰加密,接收者用私鑰解密(只有擁有私鑰的接收者才能解讀加密的內容)
--數字簽名過程:甲方用私鑰加密,乙方用公鑰解密(乙方解密成功說明就是甲方加的密,甲方就不能夠抵賴)
詳細數學原理見 【前因後果系列】RSA算法原理
ECC加密算法是基於橢圓曲線上離散對數計算問題(ECDLP)的ECC算法。ECC算法的數學理論很是深奧和複雜,在工程應用中比較難於實現,但它的單位安全強度相對較高。
用國際上公認的對於ECC算法最有效的攻擊方法--Pollard rho方法去破譯和攻擊ECC算法,它的破譯或求解難度基本上是指數級的。正是因爲RSA算法和ECC算法這一明顯不一樣,使得ECC算法的單位安全強度高於RSA算法,也就是說,要達到一樣的安全強度,ECC算法所需的密鑰長度遠比RSA算法低。有研究表示160位的橢圓密鑰與1024位的RSA密鑰安全性相同。在私鑰的加密解密速度上,ECC算法比RSA、DSA速度更快。存儲空間佔用更小。
擴展閱讀:
How to encrypt data using Elliptic Curve Algorithm in C#
MD5全稱是Message-Digest Algorithm 5(信息摘要算法5),單向的算法不可逆(被MD5加密的數據不能被解密)。MD5加密後的數據長度要比加密數據小的多,且長度固定,且加密後的串是惟一的。
適用場景:經常使用在不可還原的密碼存儲、信息完整性校驗等。
信息完整性校驗:典型的應用是對一段信息產生信息摘要,以防止被篡改。若是再有一個第三方的認證機構,用MD5還能夠防止文件做者的「抵賴」,這就是所謂的數字簽名應用。
SHA-1摘要比MD5摘要長32 位,因此SHA-1對強行攻擊有更大的強度,比MD5更安全。使用強行技術,產生任何一個報文使其摘要等於給定報摘要的難度對MD5是2^128數量級的操做,而對SHA-1則是2^160數量級的操做。
在相同的硬件上,SHA-1 的運行速度比 MD5 慢。
因爲以上加密算法都有各自的缺點(RSA加密速度慢、AES密鑰存儲問題、MD5加密不可逆),所以實際應用時常將幾種加密算法混合使用。
例如:RSA+AES:
採用RSA加密AES的密鑰,採用AES對數據進行加密,這樣集成了兩種加密算法的優勢,既保證了數據加密的速度,又實現了安全方便的密鑰管理。
那麼,採用多少位的密鑰合適呢?通常來說密鑰長度越長,安全性越高,可是加密速度越慢。因此密鑰長度也要合理的選擇,通常RSA建議採用1024位的數字,AES建議採用128位便可。
嚴格意義講,Base64並不能算是一種加密算法,而是一種編碼格式,是網絡上最多見的用於傳輸8bid字節代碼的編碼方式之一。
Base64編碼可用於在HTTP環境下傳遞較長的標識信息,Base編碼不只不只比較簡單,同時也據有不可讀性(編碼的數據不會被肉眼直接看到)。
using System; using System.Text; using System.Security.Cryptography; using System.IO; namespace EnDeCode1 { /// <summary> /// 加密解密工具類 /// 做者博客:https://www.cnblogs.com/tuyile006/ /// </summary> public class EncodeHelper { #region MD5 /// <summary> /// MD5哈希加密 /// </summary> /// <param name="scr">原始string數據</param> /// <returns>加密後的數據</returns> public static string MD5(string scr) { MD5 md5 = new MD5CryptoServiceProvider(); byte[] palindata = Encoding.Default.GetBytes(scr);//將要加密的字符串轉換爲字節數組 byte[] encryptdata = md5.ComputeHash(palindata);//將字符串加密後也轉換爲字符數組 return Convert.ToBase64String(encryptdata);//將加密後的字節數組轉換爲加密字符串 } #endregion #region SHA1 /// <summary> /// SHA1哈希加密 /// </summary> /// <param name="scr">原始string數據</param> /// <returns>加密後的數據</returns> public static string SHA1(string scr) { SHA1 sha1 = new SHA1CryptoServiceProvider(); byte[] palindata = Encoding.Default.GetBytes(scr);//將要加密的字符串轉換爲字節數組 byte[] encryptdata = sha1.ComputeHash(palindata);//將字符串加密後也轉換爲字符數組 return Convert.ToBase64String(encryptdata);//將加密後的字節數組轉換爲加密字符串 } #endregion #region RSA /// <summary> /// RSA加密 /// </summary> /// <param name="scr">原始string數據</param> /// <returns></returns> public static string RSA(string scr) { CspParameters csp = new CspParameters(); //密鑰容器知識參見https://docs.microsoft.com/zh-cn/dotnet/standard/security/how-to-store-asymmetric-keys-in-a-key-container //在Web中配置參見https://docs.microsoft.com/zh-cn/previous-versions/aspnet/yxw286t2%28v%3dvs.100%29 csp.KeyContainerName = "tuyile006.cnblogs.com";//密匙容器的名稱,保持加密解密一致才能解密成功 using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp)) { byte[] plaindata = Encoding.Default.GetBytes(scr);//將要加密的字符串轉換爲字節數組 byte[] encryptdata = rsa.Encrypt(plaindata, false);//將加密後的字節數據轉換爲新的加密字節數組 return Convert.ToBase64String(encryptdata);//將加密後的字節數組轉換爲字符串 } } /// <summary> /// RSA解密 /// </summary> /// <param name="scr">密文</param> /// <returns></returns> public static string RSADecrypt(string scr) { try { CspParameters csp = new CspParameters(); csp.KeyContainerName = "tuyile006.cnblogs.com";//密匙容器的名稱,保持加密解密一致才能解密成功 using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp)) { byte[] bytes = Convert.FromBase64String(scr); //加密時用了Base64,則解密時對應的也要用Base64解碼 byte[] DecryptBytes = rsa.Decrypt(bytes, false); return Encoding.Default.GetString(DecryptBytes); } } catch (Exception) { return string.Empty; } } /// <summary> /// 返回RSA公匙 /// </summary> /// <returns></returns> public static string GetRSAPublicKey() { CspParameters csp = new CspParameters(); csp.KeyContainerName = "tuyile006.cnblogs.com";//密匙容器的名稱,保持加密解密一致才能解密成功 using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp)) { return rsa.ToXmlString(false); } } #endregion #region DES const string DesIV_64 = "xiaoy><@";//定義默認加密密鑰 8個字節 /// <summary> /// 按指定鍵值進行DES加密 /// </summary> /// <param name="strContent">要加密字符</param> /// <param name="strKey">自定義鍵值 ASCII編碼 必須大於或等於8個字符</param> /// <returns></returns> public static string DES(string strContent, string strKey) { if (string.IsNullOrEmpty(strContent)) return string.Empty; if (strKey.Length > 8) strKey = strKey.Substring(0, 8); DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider(); byte[] byKey = Encoding.ASCII.GetBytes(strKey); byte[] byIV = Encoding.ASCII.GetBytes(DesIV_64); using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIV), CryptoStreamMode.Write)) { using (StreamWriter sw = new StreamWriter(cst)) { sw.Write(strContent); sw.Flush(); cst.FlushFinalBlock(); sw.Flush(); return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length); } } } } /// <summary> /// 按指定鍵值進行DES解密 /// </summary> /// <param name="strContent">要解密字符</param> /// <param name="strKey">加密時使用的鍵值 ASCII編碼 必須大於或等於8個字符</param> /// <returns></returns> public static string DESDecrypt(string strContent, string strKey) { if (string.IsNullOrEmpty(strContent)) return string.Empty; if (strKey.Length > 8) strKey = strKey.Substring(0, 8); byte[] byKey = Encoding.ASCII.GetBytes(strKey); byte[] byIV = Encoding.ASCII.GetBytes(DesIV_64); byte[] byEnc; try { byEnc = Convert.FromBase64String(strContent); using (DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider()) { using (MemoryStream ms = new MemoryStream(byEnc)) { using (CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIV), CryptoStreamMode.Read)) { StreamReader sr = new StreamReader(cst); return sr.ReadToEnd(); } } } } catch { return string.Empty; } } #endregion #region AES const string AesIV_128 = "xiaoy設計.";//定義默認加密密鑰 16個字節 Unicode編碼爲8個英文或漢字 /// <summary> /// 按指定鍵值進行AES加密 /// </summary> /// <param name="plainText">要解密字符</param> /// <param name="strKey">加密時使用的鍵值 Unicode編碼 必須大於或等於8個英文或漢字</param> /// <returns></returns> public static string AES(string strContent, string strKey) { if (string.IsNullOrEmpty(strContent)) return string.Empty; if (strKey.Length > 8) strKey = strKey.Substring(0, 8); using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider()) { aesAlg.Key = Encoding.Unicode.GetBytes(strKey); aesAlg.IV = Encoding.Unicode.GetBytes(AesIV_128); ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { swEncrypt.Write(strContent); } return Convert.ToBase64String(msEncrypt.ToArray()); //返回Base64密文方便傳輸 } } } } /// <summary> /// 按指定鍵值進行AES解密 /// </summary> /// <param name="strContent">要解密字符</param> /// <param name="strKey">加密時使用的鍵值 Unicode編碼 必須大於或等於8個英文或漢字</param> /// <returns></returns> public static string AESDecrypt(string strContent, string strKey) { if (string.IsNullOrEmpty(strContent)) return string.Empty; if (strKey.Length > 8) strKey = strKey.Substring(0, 8); //與加密時Base64對應 byte[] byEnc; try { byEnc = Convert.FromBase64String(strContent); //解密 using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider()) { aesAlg.Key = Encoding.Unicode.GetBytes(strKey); aesAlg.IV = Encoding.Unicode.GetBytes(AesIV_128); // Create a decryptor to perform the stream transform. ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for decryption. using (MemoryStream msDecrypt = new MemoryStream(byEnc)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { return srDecrypt.ReadToEnd(); } } } } } catch { return string.Empty; } } #endregion #region ECC /// <summary> /// 利用ecc生成key /// 假設從A-->B進行信息發送 /// </summary> /// <param name="AKeyName">A的公鑰名稱 自身</param> /// <param name="BKey">B的公鑰</param> /// <returns> 生成A端用於交互信息的密鑰,能夠用於AES加密的密鑰</returns> public static string ECC_EncodeKey(string AKeyName,string BKey) { byte[] BKeybyte = Convert.FromBase64String(BKey); using (ECDiffieHellmanCng AClient = new ECDiffieHellmanCng(CngKey.Open(AKeyName))) //using (ECDiffieHellmanCng AClient = new ECDiffieHellmanCng()) { AClient.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; AClient.HashAlgorithm = CngAlgorithm.Sha256; byte[] MsgKey = AClient.DeriveKeyMaterial(CngKey.Import(BKeybyte, CngKeyBlobFormat.EccPublicBlob)); return Convert.ToBase64String(MsgKey); } } /// <summary> /// 獲取自身的公鑰 /// </summary> /// <returns>Base64編碼的字符串,接收端須要Base64解碼再使用</returns> public static string ECC_GetMyPublicKey(string keyName) { if (!CngKey.Exists(keyName)) { using (ECDiffieHellmanCng MyECC = new ECDiffieHellmanCng(CngKey.Create(CngAlgorithm.ECDiffieHellmanP256, keyName))) { MyECC.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; MyECC.HashAlgorithm = CngAlgorithm.Sha256; byte[] Keybyte = MyECC.PublicKey.ToByteArray(); return Convert.ToBase64String(Keybyte); } } else { using (ECDiffieHellmanCng MyECC = new ECDiffieHellmanCng(CngKey.Open(keyName))) { byte[] Keybyte = MyECC.PublicKey.ToByteArray(); return Convert.ToBase64String(Keybyte); } } } #endregion } }
這些算法已經在.net框架裏面封裝好了,只須要引用System.Security.Cryptography庫,使用起來仍是很是方便的。
使用示例:(下載Demo)
算法調用很簡單:
txtEncode.Text = EncodeHelper.MD5(txtMsg.Text);
txtEncode.Text = EncodeHelper.RSA(txtMsg.Text);
txtMsg.Text = "解密後的文本:" + EncodeHelper.RSADecrypt(txtEncode.Text);
txtEncode.Text = EncodeHelper.AES(txtMsg.Text, "密鑰能夠是漢字哦");
txtMsg.Text = "解密後的文本:" + EncodeHelper.AESDecrypt(txtEncode.Text, "密鑰能夠是漢字哦");
稍微複雜一點的是ECC+AES混合加密,用ECC加密AES的密鑰,而用AES加密要傳送的信息,接收端用ECC公鑰解密獲得AES密鑰,而後解密信息。
該過程能夠參考MSDN上的例子https://docs.microsoft.com/ru-ru/dotnet/api/system.security.cryptography.ecdiffiehellmancng
string bkey, akey,akeyname="akey",bkeyname="bkey"; private void btn_Ecc_Click(object sender, EventArgs e) { akey = EncodeHelper.ECC_GetMyPublicKey(akeyname); //A先獲取自身的publickey bkey = EncodeHelper.ECC_GetMyPublicKey(bkeyname); //B先獲取自身的publickey string AClientAESKey = EncodeHelper.ECC_EncodeKey(akeyname, bkey); //用bkey生成用於AES算法的key txtEncode.Text = EncodeHelper.AES(txtMsg.Text, AClientAESKey); } private void btn_eccrec_Click(object sender, EventArgs e) { string BClientAESKey = EncodeHelper.ECC_EncodeKey(bkeyname, akey); //用akey生成用於AES算法的key txtMsg.Text ="解密後的文本:"+ EncodeHelper.AESDecrypt(txtEncode.Text, BClientAESKey); }