對稱加密算法在C#中的踩坑日常


前言

有幸接觸了一下傳說中的對稱加密算法3DES

感覺這些加密算法與我的工作是想去甚遠的,一般沒什么機會接觸這些東西

今次了解了一下3DES這個對稱算法

原理算不上明白,算是踩了C#中的一些坑吧

C#中對於密鑰的處理比較奇怪,花費了一晚上一早上的時間才弄明白

期間偷窺了不少C#的源代碼

下面由我娓娓道來

簡介

3DES算法命名

定義算法最早期的標准被放在ANS X9.52中並在1998年發布並將其描述為三重數據加密算法(簡稱TDEA),在ANSI X3.92中定義了該算法的三個操作但是並沒有使用DES或者3DES,直到1999年發布的FIPS PUB 46-3在正式命名三重數據加密算法,大概在2004到2005的樣子才正式引入三重數據加密算法,之前一直以TDEA存在着,也就是說TDEA就是3DES,但是沒有使用3DES作為標准術語。

基本邏輯

三重數據加密算法使用包括密鑰K1,密鑰K2和密鑰約束K3,每一個包含56位不包含奇偶校驗,算法實現公式如下:

ciphertext = EK3(DK2(EK1(plaintext)))

密文 = EK3(DK2(EK1(平文)))

用K1對數據進行加密,用K2對數據進行解密,用K3對數據再加密。

解密公式為如下:

plaintext = DK1(EK2(DK3(ciphertext)))

平文 = DK1(EK2(DK3(密文)))

用K3j對數據進行解密,用K2對數據進行加密,用K1對數據進行加密。每次加密都處理64位數據並形成一塊。

3DES加密選項

定義了三種密鑰選項。

(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所支持。

C#實現

講真簡介里用來湊字數的這些內容我其實沒怎么看明白

C#中使用TripleDESCryptoServiceProvider類來實現相關功能

        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);
        }

從下面源碼中看出,該類接收的Key為16位或24位

enter description here

然后對於這個Key,C#似乎有自己的處理方式

以下為個人理解:

這個24位的key會被處理成3個8字節的獨立密鑰參與運算

當提供24位key時並沒有什么不妥

但是當提供16位的key時 會把提供的key拆分成兩個塊(block) 並以第一個塊作為第三個塊組成一個24位的密鑰

如下:

輸入密鑰:49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 50, 51, 52, 53, 54, 55

實際使用:49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 50, 51, 52, 53, 54, 55, 49, 50, 51, 52, 53, 54, 55, 56

可以看出使用了前8位來進行后面8位的補全

這時候你可能要問,如果提供一個不是16位也不是24位的密鑰時會發生什么

會拋異常

enter description here

以上理解都是在.NetFramework中的體現

如果換到NetCore中,效果就又不一樣了

NetCore

在NetCore中不存在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);
        }

NetCore中同樣要求我們提供24位的Key

但是不在兼容16位的Key,如果你提供一個非24位的Key就會異常

不過沒關系,對於16位的Key我們可以自行處理一下

同理使用前8位補全后8位

        public static string DesEncrypt(string input, string key)
        {

            byte[] inputArray = Encoding.UTF8.GetBytes(input);
            var tripleDES = TripleDES.Create();
            var byteKey = Encoding.UTF8.GetBytes(key);
            //復制前8位補全后8位
			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);
            //復制前8位補全后8位
			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);
        }

至此就可以正常兼容NetFramework的代碼了

小結

至此寫下此文,也算是對3DES有了些許了解吧

需要記住

在.NET Core中利用3DES加密和解密必須要給出3個密鑰即24個字節即使密鑰3和密鑰1相等,它不會像.NET Framework中會重用密鑰1中的位數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM