C#中對(duì)稱加密算法的踩坑日常記錄
1|0前言
有幸接觸了一下傳說中的對(duì)稱加密算法3DES
感覺這些加密算法與我的工作是想去甚遠(yuǎn)的,一般沒什么機(jī)會(huì)接觸這些東西
今次了解了一下3DES這個(gè)對(duì)稱算法
原理算不上明白,算是踩了C#中的一些坑吧
C#中對(duì)于密鑰的處理比較奇怪,花費(fèi)了一晚上一早上的時(shí)間才弄明白
期間偷窺了不少C#的源代碼
下面由我娓娓道來
2|0簡(jiǎn)介
2|13DES算法命名
定義算法最早期的標(biāo)準(zhǔn)被放在ANS X9.52中并在1998年發(fā)布并將其描述為三重?cái)?shù)據(jù)加密算法(簡(jiǎn)稱TDEA),在ANSI X3.92中定義了該算法的三個(gè)操作但是并沒有使用DES或者3DES,直到1999年發(fā)布的FIPS PUB 46-3在正式命名三重?cái)?shù)據(jù)加密算法,大概在2004到2005的樣子才正式引入三重?cái)?shù)據(jù)加密算法,之前一直以TDEA存在著,也就是說TDEA就是3DES,但是沒有使用3DES作為標(biāo)準(zhǔn)術(shù)語。
2|2基本邏輯
三重?cái)?shù)據(jù)加密算法使用包括密鑰K1,密鑰K2和密鑰約束K3,每一個(gè)包含56位不包含奇偶校驗(yàn),算法實(shí)現(xiàn)公式如下:
ciphertext = EK3(DK2(EK1(plaintext)))
即
密文 = EK3(DK2(EK1(平文)))
用K1對(duì)數(shù)據(jù)進(jìn)行加密,用K2對(duì)數(shù)據(jù)進(jìn)行解密,用K3對(duì)數(shù)據(jù)再加密。
解密公式為如下:
plaintext = DK1(EK2(DK3(ciphertext)))
即
平文 = DK1(EK2(DK3(密文)))
用K3j對(duì)數(shù)據(jù)進(jìn)行解密,用K2對(duì)數(shù)據(jù)進(jìn)行加密,用K1對(duì)數(shù)據(jù)進(jìn)行加密。每次加密都處理64位數(shù)據(jù)并形成一塊。
2|33DES加密選項(xiàng)
定義了三種密鑰選項(xiàng)。
(1)三個(gè)密鑰相互獨(dú)立。
(2)K1和K2密鑰獨(dú)立,但K1 = K3。
(3)三個(gè)密鑰相等。
密鑰選項(xiàng)1的強(qiáng)度最高,擁有3 x 56 = 168個(gè)獨(dú)立的密鑰位。
密鑰選項(xiàng)2的安全性稍低,擁有2 x 56 = 112個(gè)獨(dú)立的密鑰位。該選項(xiàng)比簡(jiǎn)單的應(yīng)用DES兩次的強(qiáng)度較高,即使用K1和K2,因?yàn)樗梢苑烙型鞠嘤龉簟?/p>
密鑰選項(xiàng)3等同與DES,只有56個(gè)密鑰位。這個(gè)選項(xiàng)提供了與DES的兼容性,因?yàn)榈?和第2次DES操作相互抵消了。該選項(xiàng)不再為國(guó)家標(biāo)準(zhǔn)科技協(xié)會(huì)(NIST)所推薦,亦不為ISO/IEC 18033-3所支持。
2|4C#實(shí)現(xiàn)
講真簡(jiǎn)介里用來湊字?jǐn)?shù)的這些內(nèi)容我其實(shí)沒怎么看明白
C#中使用TripleDESCryptoServiceProvider類來實(shí)現(xiàn)相關(guān)功能
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位
然后對(duì)于這個(gè)Key,C#似乎有自己的處理方式
以下為個(gè)人理解:
這個(gè)24位的key會(huì)被處理成3個(gè)8字節(jié)的獨(dú)立密鑰參與運(yùn)算
當(dāng)提供24位key時(shí)并沒有什么不妥
但是當(dāng)提供16位的key時(shí) 會(huì)把提供的key拆分成兩個(gè)塊(block) 并以第一個(gè)塊作為第三個(gè)塊組成一個(gè)24位的密鑰
如下:
輸入密鑰:49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 50, 51, 52, 53, 54, 55
實(shí)際使用: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位來進(jìn)行后面8位的補(bǔ)全
這時(shí)候你可能要問,如果提供一個(gè)不是16位也不是24位的密鑰時(shí)會(huì)發(fā)生什么
會(huì)拋異常
以上理解都是在.NetFramework中的體現(xiàn)
如果換到NetCore中,效果就又不一樣了
2|5NetCore
在NetCore中不存在TripleDESCryptoServiceProvider 取而代之的是 TripleDES
所以此時(shí)我們的代碼需要稍作修改
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,如果你提供一個(gè)非24位的Key就會(huì)異常
不過沒關(guān)系,對(duì)于16位的Key我們可以自行處理一下
同理使用前8位補(bǔ)全后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); //復(fù)制前8位補(bǔ)全后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); //復(fù)制前8位補(bǔ)全后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的代碼了
3|0小結(jié)
至此寫下此文,也算是對(duì)3DES有了些許了解吧
需要記住
在.NET Core中利用3DES加密和解密必須要給出3個(gè)密鑰即24個(gè)字節(jié)即使密鑰3和密鑰1相等,它不會(huì)像.NET Framework中會(huì)重用密鑰1中的位數(shù)。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
C#中foreach循環(huán)對(duì)比for循環(huán)的優(yōu)勢(shì)和劣勢(shì)
循環(huán)語句是編程的基本語句,在C#中除了沿用C語言的循環(huán)語句外,還提供了foreach語句來實(shí)現(xiàn)循環(huán),下面這篇文章主要給大家介紹了關(guān)于C#中foreach循環(huán)對(duì)比for循環(huán)的優(yōu)勢(shì)和劣勢(shì),需要的朋友可以參考借鑒,下面來一起看看吧。2017-09-09C#實(shí)現(xiàn)快遞api接口調(diào)用方法
這篇文章主要介紹了C#實(shí)現(xiàn)快遞api接口調(diào)用方法,主要是通過快遞API網(wǎng)接口的服務(wù),使用的時(shí)候直接申請(qǐng)個(gè)接口UID即可,有需要的小伙伴來參考下吧。2015-03-03Unity 實(shí)現(xiàn)鼠標(biāo)滑過UI時(shí)觸發(fā)動(dòng)畫的操作
這篇文章主要介紹了Unity 實(shí)現(xiàn)鼠標(biāo)滑過UI時(shí)觸發(fā)動(dòng)畫的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-04-04C#中IEnumerator<T>和IEnumerable的區(qū)別
在C#中,IEnumerator<T>和IEnumerable是用于實(shí)現(xiàn)迭代的接口,本文主要介紹了C#中IEnumerator<T>和IEnumerable的區(qū)別,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01關(guān)于C#中GUI編程的標(biāo)準(zhǔn)事件問題
這篇文章主要介紹了C#中GUI編程的標(biāo)準(zhǔn)事件,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01C#?在PDF中添加墨跡注釋Ink?Annotation的步驟詳解
PDF中的墨跡注釋表現(xiàn)為徒手涂鴉式的形狀,該類型的注釋,可任意指定形狀頂點(diǎn)的位置及個(gè)數(shù),通過指定的頂點(diǎn),程序?qū)⑦B接各點(diǎn)繪制成平滑的曲線,下面通過C#程序代碼介紹下在pdf中添加注釋的步驟,感興趣的朋友一起看看吧2022-02-02C# 實(shí)現(xiàn)QQ式截圖功能實(shí)例代碼
本篇文章主要介紹了C# 實(shí)現(xiàn)QQ式截圖功能實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02