文章出處

    離過年又近了一天,回家已是近在咫尺,有人歡喜有人愁,因為過幾天就得經歷每年一度的裝逼大戲,親戚朋友加同學的各方顯擺,所以得靠一劑年終獎來裝飾一個安穩的年,在這里我想起了一個題目“論裝逼的技術性和重要性”。

   都是老司機了,不扯淡,站在外面的都進來,然后請后面的把門關一下,我們接著出發。

   上一篇主要介紹.NET的散列加密,散列算法主要用于簽名等操作,在我們的項目中,如果對加密沒有特別的要求,一般都是采用的對稱加密方式,因為這種加密方式相較其他加密方式較為簡單,但是這種加密方式比較的高效,所以今天就介紹一下.NET的對稱加密方式。

一.DotNet對稱加密概述:

   對稱加密是采用單密鑰加密方式,這也就意味著加密和解密都是用同一個密鑰。根據密碼學的相關定義,對稱加密系統的組成部分有5個,分別是明文空間,密文空間,密鑰空間,加密空間,解密算法。接下來用一個示意圖來表示一下:

  

   DotNet對稱加密算法的核心是一個密碼函數,該函數將固定大小的消息數據塊(純文本)轉換成加密數據庫(加密文本)。轉化為加密文本或重建為純文本都需要密鑰,加密是可逆的,或者說是雙向的過程,可以使用密鑰來反轉加密效果并重建純文本。

   大多數對稱加密算法是在不同的密碼模式下運行,在密碼函數處理數據之前,這些模式指定了準備這些數據的不同方式。密碼模式有:電子代碼薄模式,密碼塊鏈接,密碼反饋模式。

   有關塊值填充的內容在下面會講解到。

二.DotNet對稱加密類解析:

   1.對稱加密分類:

      (1).在.NET中對稱加密算法分類有如下結構圖:

      (2).對于.NET對稱加密算法的說明如下表格:

算法名稱

算法說明

DES加密算法 采用的是分組加密方式,使用56位密鑰加密64位明文,最后產生64位密文
3DES加密算法 采用168位的密鑰,三重加密,速度比較的慢
TripleDES加密算法 用兩個密鑰對數據進行3次加密/解密運算
RC2加密算法 運用密鑰長度可變,對明文采取64位分組加密
RC4加密算法 運用一個密鑰長度可變的面向字節流的加密算法,以隨機置換為基礎
RC5加密算法 運用一種分組長度、密鑰長度、加密迭代輪數都可變的分組加密算法。(包含密鑰擴展、加密算法、解密算法)
RC6加密算法 RC6繼承了RC5的循環移位思想,RC6是輸入的明文由原先2個區擴展為4個塊區
Rijndael加密算法 運用反復運算的加密算法,允許數據區塊及密鑰的長度可變。數據區塊與密鑰長度的變動時各自獨立的

   2.DotNet對稱加密核心對象解析:

     在.NET中對稱算法的層次結構如下圖:

      Ⅰ.SymmetricAlgorithm類解析:

          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定義基本的加密轉換運算,該接口的實例可以將文純文本轉化成加密文本,或者將加密文本轉化為純文本,每一個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枚舉的值。

三.DotNet對稱加密實例:

   1.DES算法加密實例:

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

    2.DES算法解密實例:

        /// <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


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()