離過年又近了一天,回家已經是近在咫尺,有人歡喜有人愁,由於過幾天就得經歷每一年一度的裝逼大戲,親戚朋友加同窗的各方顯擺,因此得靠一劑年終獎來裝飾一個安穩的年,在這裏我想起了一個題目「論裝逼的技術性和重要性」。html
都是老司機了,不扯淡,站在外面的都進來,而後請後面的把門關一下,咱們接着出發。算法
上一篇主要介紹.NET的散列加密,散列算法主要用於簽名等操做,在咱們的項目中,若是對加密沒有特別的要求,通常都是採用的對稱加密方式,由於這種加密方式相較其餘加密方式較爲簡單,可是這種加密方式比較的高效,因此今天就介紹一下.NET的對稱加密方式。數據庫
對稱加密是採用單密鑰加密方式,這也就意味着加密和解密都是用同一個密鑰。根據密碼學的相關定義,對稱加密系統的組成部分有5個,分別是明文空間,密文空間,密鑰空間,加密空間,解密算法。接下來用一個示意圖來表示一下:數組
DotNet對稱加密算法的核心是一個密碼函數,該函數將固定大小的消息數據塊(純文本)轉換成加密數據庫(加密文本)。轉化爲加密文本或重建爲純文本都須要密鑰,加密是可逆的,或者說是雙向的過程,可使用密鑰來反轉加密效果並重建純文本。ide
大多數對稱加密算法是在不一樣的密碼模式下運行,在密碼函數處理數據以前,這些模式指定了準備這些數據的不一樣方式。密碼模式有:電子代碼薄模式,密碼塊連接,密碼反饋模式。函數
有關塊值填充的內容在下面會講解到。源碼分析
(1).在.NET中對稱加密算法分類有以下結構圖:ui
(2).對於.NET對稱加密算法的說明以下表格:this
算法名稱加密 |
算法說明 |
DES加密算法 | 採用的是分組加密方式,使用56位密鑰加密64位明文,最後產生64位密文 |
3DES加密算法 | 採用168位的密鑰,三重加密,速度比較的慢 |
TripleDES加密算法 | 用兩個密鑰對數據進行3次加密/解密運算 |
RC2加密算法 | 運用密鑰長度可變,對明文采起64位分組加密 |
RC4加密算法 | 運用一個密鑰長度可變的面向字節流的加密算法,以隨機置換爲基礎 |
RC5加密算法 | 運用一種分組長度、密鑰長度、加密迭代輪數均可變的分組加密算法。(包含密鑰擴展、加密算法、解密算法) |
RC6加密算法 | RC6繼承了RC5的循環移位思想,RC6是輸入的明文由原先2個區擴展爲4個塊區 |
Rijndael加密算法 | 運用反覆運算的加密算法,容許數據區塊及密鑰的長度可變。數據區塊與密鑰長度的變更時各自獨立的 |
在.NET中對稱算法的層次結構以下圖:
SymmetricAlgorithm類容許配置一個算法(選擇大小,填充模式)並建立加密和解密數據的實例;不能使用該類和導出實現類來種子直接處理數據。接下來咱們具體瞭解一下SymmetricAlgorithm類的一些方法和屬性。該類是一個抽象類,是全部對稱加密算法基類。在使用派生類時,若是僅在用完對象後強制垃圾回收是不夠的,須要對該對象顯示的調用clear方法,以便在釋放對象以前將對象中所包含的全部敏感數據清除。
(1).IV屬性:獲取或設置對稱算法的初始化向量。
public virtual byte[] IV { get { if (this.IVValue == null) this.GenerateIV(); return (byte[]) this.IVValue.Clone(); } set { if (value == null) throw new ArgumentNullException("value"); if (value.Length != this.BlockSizeValue / 8) throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidIVSize")); this.IVValue = (byte[]) value.Clone(); } }
該屬於使用字節數組的形式表示Key,該屬性具備get和set屬性,代表該屬性是可讀可寫的,該屬性爲虛屬性,能夠在子類中重寫。Key屬性是用來獲取或設置對稱算法的密鑰,密鑰便可使用於加密也可使用於解密。
(2).LegalBlockSizes屬性: 獲取對稱算法支持的塊大小(以位爲單位)。
public virtual KeySizes[] LegalBlockSizes { get { return (KeySizes[]) this.LegalBlockSizesValue.Clone(); } }
該屬性爲虛屬性,在子類中可重寫,該屬性是隻讀屬性。
(3).Create()方法:建立用於執行對稱算法的指定加密對象。
public static SymmetricAlgorithm Create(string algName) { return (SymmetricAlgorithm) CryptoConfig.CreateFromName(algName); }
該方法CryptoConfig.CreateFromName()方法在前面一篇介紹過,在這裏就不作具體的介紹,Create()接收一個SymmetricAlgorithm類型的字符串參數,指定本次System.Security.Cryptography.SymmetricAlgorithm字符串。
(4).Mode屬性:獲取或設置對稱算法的運算模式。
public virtual CipherMode Mode { get { return this.ModeValue; } set { if (value < CipherMode.CBC || CipherMode.CFB < value) throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidCipherMode")); this.ModeValue = value; } }
該屬性是一個虛屬性,獲取和設置密碼代碼,拉取準備數據,由代碼能夠看出,該屬性含有一個枚舉類型CipherMode,咱們接下來了解一下這個枚舉類型:
CipherMode枚舉類型:指定用於加密的塊加密模式。
[ComVisible(true)] public enum CipherMode { CBC = 1, ECB = 2, OFB = 3, CFB = 4, CTS = 5 }
CBC(密碼塊鏈):該模式引入類反饋;ECB(電子密碼本):該模式分別加密每一個塊;OFB(輸出反饋):該模式將少許遞增的純文本處理改爲密碼文本,而不是以此處理整個塊;CFB(密碼反饋):該模式將少許遞增的純文本處理成密碼文本,而不是一次處理整個塊;CTS(密碼文本竊用):該模式處理任何長度的純文本併產生長度與純文本長度匹配的密碼文本。
(5).Padding屬性: 獲取或設置對稱算法中使用的填充模式。
public virtual PaddingMode Padding { get { return this.PaddingValue; } set { if (value < PaddingMode.None || PaddingMode.ISO10126 < value) throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidPaddingMode")); this.PaddingValue = value; } }
該屬性是對稱算法中使用的填充模式,默認值爲 PKCS7。該屬性可讀可寫,填充數據的部分塊。由該屬性可知一個枚舉類型PaddingMode。
PaddingMode枚舉:指定當消息數據塊較短時要應用的填充類型,比加密操做所需的所有字節數。
[ComVisible(true)] public enum PaddingMode { None = 1, PKCS7 = 2, Zeros = 3, ANSIX923 = 4, ISO10126 = 5 }
該枚舉類型有5個成員, None = 1:不填充;PKCS7 = 2:PKCS#7填充字符串由字節序列組成,每一個字節都是等於添加的填充字節的總數; Zeros = 3:填充字符串由設置爲零的字節組成; ANSIX923 = 4:ANSI X 923填充字符串由長度前面填充零的字節序列組成;ISO10126 = 5:ISO10126填充字符串由長度以前的隨機數據組成。
ICryptoTransform定義基本的加密轉換運算,該接口的實例能夠將文純文本轉化成加密文本,或者將加密文本轉化爲純文本,每個ICryptoTransform都是單向的,只能被用於其建立的目的。該接口的屬性和方法以下:
/// <summary> /// 獲取輸入塊大小。 /// </summary> int InputBlockSize { get; } /// <summary> /// 獲取輸出塊大小。 /// </summary> int OutputBlockSize { get; } /// <summary> /// 獲取一個值,該值指示是否能夠轉換多個塊。 /// </summary> bool CanTransformMultipleBlocks { get; } /// <summary> /// 獲取一個值,該值指示是否可重複使用當前轉換。 /// </summary> bool CanReuseTransform { get; } /// <summary> /// 轉換輸入字節數組的指定區域,並將所獲得的轉換複製到輸出字節數組的指定區域。 /// </summary> int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset); /// <summary> /// 轉換指定字節數組的指定區域。 /// </summary> byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount);
ICryptoTransform接口實例並不能使用於本身,.NET提供了CryptoStream類,定義將數據流連接到加密轉換的流。建立CryptoStream的實例須要一個真實流、ICryptoTransform、CryptoStreamMode枚舉的值。
/// <summary> /// 加密數據 /// </summary> /// <param name="text"></param> /// <param name="sKey"></param> /// <returns></returns> public static string Encrypt(string text, string sKey) { if (string.IsNullOrEmpty(text)) { throw new ArgumentNullException(text); } if (string.IsNullOrEmpty(sKey)) { throw new ArgumentNullException(sKey); } MemoryStream ms = null; DESCryptoServiceProvider des = null; try { des = new DESCryptoServiceProvider(); var inputByteArray = Encoding.Default.GetBytes(text); var bKey = Encoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0, 8)); des.Key = bKey; des.IV = bKey; ms = new MemoryStream(); var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write); cs.Write(inputByteArray, 0, inputByteArray.Length); cs.FlushFinalBlock(); var ret = new StringBuilder(); foreach (byte b in ms.ToArray()) { ret.AppendFormat("{0:X2}", b); } return ret.ToString(); } catch (NotSupportedException nsex) { throw nsex; } catch (ArgumentNullException arnex) { throw arnex; } catch (EncoderFallbackException efex) { throw efex; } catch (ArgumentException arex) { throw arex; } catch (CryptographicException crex) { throw crex; } finally { if (ms != null) { ms.Close(); } if (des != null) { des.Clear(); } } }
/// <summary> /// 解密數據 /// </summary> /// <param name="text"></param> /// <param name="sKey"></param> /// <returns></returns> public static string Decrypt(string text, string sKey) { if (string.IsNullOrEmpty(text)) { throw new ArgumentNullException(text); } if (string.IsNullOrEmpty(sKey)) { throw new ArgumentNullException(sKey); } MemoryStream ms = null; DESCryptoServiceProvider des = null; try { des = new DESCryptoServiceProvider(); var len = text.Length / 2; byte[] inputByteArray = new byte[len]; int x; for (x = 0; x < len; x++) { var i = Convert.ToInt32(text.Substring(x * 2, 2), 16); inputByteArray[x] = (byte)i; } var bKey = Encoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0, 8)); des.Key = bKey; des.IV = bKey; ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write); cs.Write(inputByteArray, 0, inputByteArray.Length); cs.FlushFinalBlock(); return Encoding.Default.GetString(ms.ToArray()); } catch (NotSupportedException nsex) { throw nsex; } catch (ArgumentNullException arnex) { throw arnex; } catch (EncoderFallbackException efex) { throw efex; } catch (ArgumentException arex) { throw arex; } catch (CryptographicException crex) { throw crex; } finally { if (ms != null) { ms.Close(); } if (des != null) { des.Clear(); } } }
這篇博文主要講解.NET的對稱加密方式,從原理上講解和源碼分析,以及提供了對應的實例,輔助咱們去理解加密。若有錯誤和不足之處,歡迎評批指正。
DotNet加密方式解析--散列加密:http://www.cnblogs.com/pengze0902/p/6268700.html
DotNet加密方式解析--對稱加密:http://www.cnblogs.com/pengze0902/p/6268702.html
DotNet加密方式解析--數字簽名:http://www.cnblogs.com/pengze0902/p/6268709.html
DotNet加密方式解析--非對稱加密:http://www.cnblogs.com/pengze0902/p/6268705.html