一直困擾着我關於數據加密這一塊,24號晚上用了接近3個小時去完成一項任務,本覺得立馬能解決,可是爲了保證數據的安全性,咱們開始去對數據進行加密,而後接下來3個小時專門去研究加密這一塊,然而用着用着卻發現了一點問題,因而下班回來到寫這篇博客到深夜才正式解決,請往下看。算法
因爲數據須要獲取出來並顯示因而只能使用對稱加密,關於加密這一塊網上對於.NET Framework的實現數不勝數,好像對於.NET Core這一塊比較少,因而就開始進行研究。這個時候就利用DES或者Triple DES也稱做3DES,全名爲Triple Data Encryption Algorithm (TDEA or Triple DEA),也就是對稱密碼塊密碼,3DES對數據的每一個數據塊利用算法進行3次加密,最初開始設計該算法時,位數只有56位也就是7個字節,設計者認爲已經足夠用,可是隨着計算機的高速發展,暴露破解已經使得該算法呈現的問題日益突出,而3DES算法的出現提供了一種比較簡單的方法來增長密鑰的大小從而防止攻擊,而不是從新設計一套全新的分組密碼算法。安全
定義算法最先期的標準被放在ANS X9.52中並在1998年發佈並將其描述爲三重數據加密算法(簡稱TDEA),在ANSI X3.92中定義了該算法的三個操做可是並無使用DES或者3DES,直到1999年發佈的FIPS PUB 46-3在正式命名三重數據加密算法,大概在2004到2005的樣子才正式引入三重數據加密算法,以前一直以TDEA存在着,也就是說TDEA就是3DES,可是沒有使用3DES做爲標準術語。ide
三重數據加密算法使用包括密鑰K1,密鑰K2和密鑰約束K3,每個包含56位不包含奇偶校驗,算法實現公式以下:this
ciphertext = EK3(DK2(EK1(plaintext)))
即加密
密文 = EK3(DK2(EK1(平文)))
用K1對數據進行加密,用K2對數據進行解密,用K3對數據再加密。spa
解密公式爲以下:設計
plaintext = DK1(EK2(DK3(ciphertext)))
即調試
平文 = DK1(EK2(DK3(密文)))
用K3j對數據進行解密,用K2對數據進行加密,用K1對數據進行加密。每次加密都處理64位數據並造成一塊。code
定義了三種密鑰選項。orm
(1)三個密鑰相互獨立。
(2)K1和K2密鑰獨立,但K1 = K3。
(3)三個密鑰相等。
密鑰選項1的強度最高,擁有3 x 56 = 168個獨立的密鑰位。
密鑰選項2的安全性稍低,擁有2 x 56 = 112個獨立的密鑰位。該選項比簡單的應用DES兩次的強度較高,即便用K1和K2,由於它能夠防護中途相遇攻擊。
密鑰選項3等同與DES,只有56個密鑰位。這個選項提供了與DES的兼容性,由於第1和第2次DES操做相互抵消了。該選項再也不爲國家標準科技協會(NIST)所推薦,亦不爲ISO/IEC 18033-3所支持。
咱們看下在.NET Framework中對於3DES的具體實現,以下:
public static string DesEncrypt(string input, string key) { byte[] inputArray = Encoding.UTF8.GetBytes(input); TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider(); tripleDES.Key = Encoding.UTF8.GetBytes(key); tripleDES.Mode = CipherMode.ECB; tripleDES.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = tripleDES.CreateEncryptor(); byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); tripleDES.Clear(); return Convert.ToBase64String(resultArray, 0, resultArray.Length); }
public static string DesDecrypt(string input, string key) { byte[] inputArray = Convert.FromBase64String(input); TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider(); tripleDES.Key = Encoding.UTF8.GetBytes(key); tripleDES.Mode = CipherMode.ECB; tripleDES.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = tripleDES.CreateDecryptor(); byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); tripleDES.Clear(); return Encoding.UTF8.GetString(resultArray); }
咱們給出一個16位的加密密鑰,而後對相應數據進行加密和解密
var name = "Jeffcky"; var encryptStr = DesEncrypt(name, "sblw-3hn8-sqoy19"); Console.WriteLine(name); var decryptStr = DesDecrypt(encryptStr, "sblw-3hn8-sqoy19"); Console.WriteLine(decryptStr);
咱們定義密鑰爲16個字節,即此時應該是有兩個密鑰,可是此時密鑰卻不一樣,因此猜想內部實現的3DES密碼選項中的第二項,由於密鑰3和密鑰1相等,既然沒出錯,內部應該會去拿密鑰1中的位數做爲密鑰3的位數。接下里咱們再來看在.NET Core中的狀況。
因爲在.NET Core中不存在 TripleDESCryptoServiceProvider 取而代之的是 TripleDES ,因此此時咱們的代碼須要稍做修改,以下:
public static string DesEncrypt(string input, string key) { byte[] inputArray = Encoding.UTF8.GetBytes(input); var tripleDES = TripleDES.Create(); var byteKey = Encoding.UTF8.GetBytes(key); tripleDES.Key = byteKey; tripleDES.Mode = CipherMode.ECB; tripleDES.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = tripleDES.CreateEncryptor(); byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); return Convert.ToBase64String(resultArray, 0, resultArray.Length); } public static string DesDecrypt(string input, string key) { byte[] inputArray = Convert.FromBase64String(input); var tripleDES = TripleDES.Create(); var byteKey = Encoding.UTF8.GetBytes(key); tripleDES.Key = byteKey; tripleDES.Mode = CipherMode.ECB; tripleDES.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = tripleDES.CreateDecryptor(); byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); return Encoding.UTF8.GetString(resultArray); }
接着進行調用:
var name = "Jeffcky"; var encryptStr = DesEncrypt(name, "sblw-3hn8-sqoy19"); Console.WriteLine(name); var decryptStr = DesDecrypt(encryptStr, "sblw-3hn8-sqoy19"); Console.WriteLine(decryptStr);
結果出錯了詳細信息以下:
System.Security.Cryptography.CryptographicException:「Specified key is not a valid size for this algorithm.」
由上說明咱們給出密鑰的大小對於3DES對稱加密算法時無效的,爲什麼呢,在.NET Framework是好使的呀,當咱們調試時將鼠標放在3DES中密鑰時你會發現它實際須要的字節爲24個字節,而咱們只提供了16個字節,以下:
因此到這裏咱們應該知道問題出在什麼地方了,根據咱們對3DES的介紹內部實現的選項應該是密鑰選項2,將密鑰1和密鑰2獨立開來,而密鑰3和密鑰相同,在.NET Framework中咱們只要兩個密鑰便可,由於第三個密鑰和第一個相同,既然沒出錯確定是內部重用了密鑰1,可是在.NET Core須要咱們給出24個字節,說明即便密鑰1和密鑰3相同也要咱們提供密鑰的字節,因此咱們只要將密鑰1中的八個字節拷貝到密鑰3中,這樣就有了24個字節,實現以下:
public static string DesEncrypt(string input, string key) { byte[] inputArray = Encoding.UTF8.GetBytes(input); var tripleDES = TripleDES.Create(); var byteKey = Encoding.UTF8.GetBytes(key); byte[] allKey = new byte[24]; Buffer.BlockCopy(byteKey, 0, allKey, 0, 16); Buffer.BlockCopy(byteKey, 0, allKey, 16, 8); tripleDES.Key = allKey; tripleDES.Mode = CipherMode.ECB; tripleDES.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = tripleDES.CreateEncryptor(); byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); return Convert.ToBase64String(resultArray, 0, resultArray.Length); } public static string DesDecrypt(string input, string key) { byte[] inputArray = Convert.FromBase64String(input); var tripleDES = TripleDES.Create(); var byteKey = Encoding.UTF8.GetBytes(key); byte[] allKey = new byte[24]; Buffer.BlockCopy(byteKey, 0, allKey, 0, 16); Buffer.BlockCopy(byteKey, 0, allKey, 16, 8); tripleDES.Key = allKey; tripleDES.Mode = CipherMode.ECB; tripleDES.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = tripleDES.CreateDecryptor(); byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); return Encoding.UTF8.GetString(resultArray); }
此時咱們再來看下打印結果:
var name = "Jeffcky"; Console.WriteLine($"加密字符串爲{name}"); var encryptStr = DesEncrypt(name, "sblw-3hn8-sqoy19"); Console.WriteLine($"加密後結果爲:{encryptStr}"); var decryptStr = DesDecrypt(encryptStr, "sblw-3hn8-sqoy19"); Console.WriteLine($"解密後字符串爲{decryptStr}");
當時遇到這個問題我就處在崩潰的邊緣,結果去查找了資料發現有人遇到過問題,而後就去了解下3DES基本原理就解決了問題。
記住:在.NET Core中利用3DES加密和解密必需要給出3個密鑰即24個字節即便密鑰3和密鑰1相等,它不會像.NET Framework中會重用密鑰1中的位數。
參考資料:http://stackoverflow.com/questions/39013264/tripledes-16-byte-not-working