乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      使用X.509數(shù)字證書加密解密實務(wù)(三)-- 使用RSA證書結(jié)合對稱加密技術(shù)加密長數(shù)據(jù)

       趨明 2012-03-12
      .
      一、  使用證書結(jié)合對稱加密算法加、解密長數(shù)據(jù)

      上一章節(jié)討論了如何使用RSA證書加密數(shù)據(jù),文中提到:“Dotnet的RSA實現(xiàn)有個特點,它必須要在明文中添加一些隨機數(shù),所以明文不能把128字節(jié)占滿,實際測試,明文最多為117字節(jié),留下的空間用來填充隨機數(shù)”。也就是說對于1024位密鑰的RSA來說,一次只能加密128字節(jié)的數(shù)據(jù),對于Dotnet的RSA實現(xiàn)更是只能加密117個字節(jié)的數(shù)據(jù)。


      這就引出一個問題,超過128字節(jié)(或者說超過117字節(jié))的數(shù)據(jù)怎么加密?

      有個辦法,就是把數(shù)據(jù)明文拆分為合適大小的數(shù)據(jù)塊之后逐塊加密,解密時逐塊的解密再拼接。事實上,DES(包括TripleDES)算法采用的就是這個辦法,DES算法每次把數(shù)據(jù)明文拆分為8字節(jié)為單位的數(shù)據(jù)塊,一次加密一個數(shù)據(jù)塊,下一個數(shù)據(jù)塊使用密鑰和前一個數(shù)據(jù)塊的加密結(jié)果再進行加密,如此逐塊的進行加密,解密時也一樣,逐塊解密再拼接為明文。Dotnet提供的DES算法實現(xiàn)的DESCryptoServiceProvider(或TripleDESCryptoServiceProvider)類把這些拆分、加密、解密、拼接的過程都在內(nèi)部實現(xiàn),不需要開發(fā)人員自己去處理,對于開發(fā)人員可以認(rèn)為DES可以直接一次性的加密長數(shù)據(jù)。

      既然DES可以這么做,為什么RSA算法不這么做,直接在實現(xiàn)RSA算法的RSACryptoServiceProvider類中自動分拆加密解密拼接長數(shù)據(jù)呢?

      先來看一下對稱算法(以DES為代表)和非對稱算法(以RSA為代表)的各自特點。
      • 對稱算法:加密方和解密方使用同一個密鑰,必然有個密鑰傳送過程,密鑰的保密性有較大風(fēng)險。算法相對簡單,加密解密速度很快。
      • 非對稱算法:加密方使用密鑰對中的公鑰,解密方使用密鑰對中的私鑰。

      算法復(fù)雜,加解密速度慢。RSA算法之所以不這么做,是因為RSA算法的復(fù)雜性導(dǎo)致的加密解密的速度很慢,不提倡使用RSA加密長數(shù)據(jù),所以dotnet的RSA實現(xiàn)也沒有這么做。當(dāng)然開發(fā)者可以自己寫代碼實現(xiàn)拆分加密解密拼接的過程,實現(xiàn)用RSA加密長數(shù)據(jù)的功能。但是這不是個好辦法,比較現(xiàn)實的方法是:不對稱加密技術(shù)結(jié)合對稱加密技術(shù)加密長數(shù)據(jù)。

      具體思路是這樣:

      加密方生成對稱加密的密鑰key(包括key和IV),然后對稱算法使用這個key去加密長數(shù)據(jù),之后再用解密方提供的非對稱算法的公鑰publickey加密剛才生成的對稱密鑰key,最后把加密后的長數(shù)據(jù)和加密后的對稱密鑰key拼接在一起發(fā)送給解密方。

      解密方接收到后,首先分解數(shù)據(jù),把加密后的對稱密鑰key和加密后的長數(shù)據(jù)兩部分分解開。之后使用非對稱算法的私鑰解密,獲得對稱密鑰key。最后用對稱密鑰key解密加密的長數(shù)據(jù)。

      下面以前面章節(jié)生成的RSA的證書結(jié)合TripleDES算法為例描述不對稱加密技術(shù)結(jié)合對稱加密技術(shù)加密長數(shù)據(jù)的具體實現(xiàn)過程。

      RSA結(jié)合TripleDES算法加密解密過程
      單擊顯示全圖,Ctrl+滾輪縮放圖片


      1、 生成證書、分發(fā)RSA證書

      由解密方申請X.509的RSA證書,或者使用前面“使用makecert工具獲得”章節(jié)生成的MyTestCert。解密方要把自己的RSA證書導(dǎo)出為cer類型的只含有公鑰的證書分發(fā)給所有可能需要給自己發(fā)送加密消息的加密方。

      System.Security.Cryptography. TripleDESCryptoServiceProvider類是dotnet中實現(xiàn)TripleDES算法的主要的類。


      2、 加密方生成TripleDES算法key和IV

      TripleDESCryptoServiceProvider類只有一個構(gòu)造方法TripleDESCryptoServiceProvider(),這個方法把一些屬性初始化:

      KeySize(加密密鑰長度,以位為單位)= 192(24字節(jié))

      BlockSize(加密處理的數(shù)據(jù)塊大小,以位為單位)= 64(8字節(jié))

      FeedbackSize(加密數(shù)據(jù)塊后返回的數(shù)據(jù)大小,以位為單位)= 64(8字節(jié))

      TripleDESCryptoServiceProvider構(gòu)造方法同時會初始化一組隨機的key和IV。

      默認(rèn)的TripleDESCryptoServiceProvider的key為24字節(jié)(也可以生成16字節(jié)的key),IV為8字節(jié),加密數(shù)據(jù)塊為8字節(jié)。

      生成key和IV的代碼很簡單:
      復(fù)制  保存
      TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
      byte[] keyArray = tDESalg.Key;
      byte[] IVArray = tDESalg.IV;



      3、 使用RSA公鑰加密TripleDES算法的key和IV

      3.1.獲得RSA公鑰

      加密方獲得的是解密方提供的只含有公鑰的cer證書,要通過讀取cer證書文件來獲得RSA公鑰(當(dāng)然,也可以把證書加載到證書儲存區(qū),然后到證書儲存區(qū)讀取證書獲得公鑰)。
      復(fù)制  保存
      //從只包含公鑰的證書文件載入證書
      X509Certificate2 myX509Certificate2 = new X509Certificate2(@"..\..\..\MyTestCert.cer");
      
      //從證書中獲得含公鑰的RSACryptoServiceProvider
      RSACryptoServiceProvider publickeyProvider 
          = (RSACryptoServiceProvider) myX509Certificate2.PublicKey.Key;



      3.2.RSA加密key和IV

      Key和IV都是是以byte[]形式存在,要把它們兩個連接在一起后加密,就要考慮到解密后怎么把它們兩個能夠準(zhǔn)確的分割開。

      Byte[]就是字節(jié)數(shù)組, key和IV又TripleDESCryptoServiceProvider類隨機生成的,每個字節(jié)可以是任意值,如果直接把key和IV的byte[]直接連在一起,加密解密后,拆分它們時,根據(jù)key和IV本身的內(nèi)容就無法分割,沒有區(qū)分兩部分內(nèi)容的標(biāo)識。當(dāng)然可以通過key和IV本身的長度去拆分,但是key的長度也不是完全確定的,DES算法的key是8位,TripleDES算法的key是16位或24位的,所以通過長度拆分也不是好辦法。

      一般的做法是在key和IV直接增加一個分隔符,兩部分?jǐn)?shù)據(jù)通過分隔符連接起來,以后拆分的時候根據(jù)分隔符來拆分分隔符兩邊的不同部分就行了。

      問題又來了,既然兩邊的內(nèi)容是隨機生成的,可能是任何值,如何保證兩邊的內(nèi)容不跟分隔符相同呢,如果碰巧要兩邊的內(nèi)容出現(xiàn)跟分隔符相同的部分就麻煩了,拆分出來的數(shù)據(jù)肯定不對了。

      可以對需要連接的內(nèi)容做一個變換,把它們轉(zhuǎn)換成另一種編碼,而分隔符采用這種編碼中不可能有的字符就行了。

      一般的選擇是base64編碼,這種編碼只含有64個字符,就是:大寫的A-Z、小寫的a-z、數(shù)字0-9、'+' 和 '/'。進一步了解base64編碼,請參考:http://www.cnblogs.com/chnking/archive/2007/08/12/852669.html

      把key和IV分別就行base64編碼,然后設(shè)置一個分隔符(比如“&szlig;à”這樣的base64中不可能有的字符),把它們連接后再進行加密。
      復(fù)制  保存
      //使用RSA公鑰加密TripleDES算法的key和IV
      string keyandIV = Convert.ToBase64String(keyArray) + separator + Convert.ToBase64String(IVArray);
      
      //用RSA公鑰加密TripleDES算法的key和IV
      byte[] keyandIVBytesEncrypted = publickeyProvider.Encrypt(encoding.GetBytes(keyandIV), false);
      
      //加密后的key和IV再轉(zhuǎn)為base64的字符串
      string keyandIVStrEncrypted = Convert.ToBase64String(keyandIVBytesEncrypted);



      4、 使用對稱密鑰加密長數(shù)據(jù)
      復(fù)制  保存
      //建立一個MemoryStream,這里面存放加密后的數(shù)據(jù)流
      MemoryStream mStream = new MemoryStream();
      
      // 使用MemoryStream 和key、IV新建一個CryptoStream 對象
      CryptoStream cStream = new CryptoStream(mStream,
          new TripleDESCryptoServiceProvider().CreateEncryptor(keyArray, IVArray),
          CryptoStreamMode.Write);
      
      //將明文字符串轉(zhuǎn)成指定代碼頁的byte[]
      byte[] plainTextArray = encoding.GetBytes(plaintext);
      
      // 將加密后的字節(jié)流寫入到MemoryStream
      cStream.Write(plainTextArray, 0, plainTextArray.Length);
      
      //把緩沖區(qū)中的最后狀態(tài)更新到MemoryStream,并清除cStream的緩存區(qū)
      cStream.FlushFinalBlock();
      
      // 把加密后的數(shù)據(jù)流轉(zhuǎn)成Base64的字符串
      string longDataStrEncrypted = Convert.ToBase64String(mStream.ToArray());
      
      // 關(guān)閉兩個streams.
      cStream.Close();
      mStream.Close();

      待加密的數(shù)據(jù)可能有兩種形式,一種是二進制的數(shù)據(jù),本身就是一組字節(jié)流,這樣的數(shù)據(jù)可以跳過這一步,直接進入加密步驟。還有一種情況是字符串?dāng)?shù)據(jù),字符串中同樣的字符使用不同的代碼頁會生成不同的字節(jié)碼,所以從字符串到字節(jié)流的轉(zhuǎn)換是需要指定使用何種編碼的。在解密之后,要從字節(jié)流轉(zhuǎn)換到字符串就要使用相同的代碼頁解碼,否則就會出現(xiàn)亂碼。

      實際上凡是在byte[]類型跟string類型直接進行轉(zhuǎn)換時,都需要指定代碼頁,因為每種代碼頁對相同字符的編碼是不一樣的,就是說同一個字符在不同的代碼頁中是對應(yīng)到不同的二進制碼。

      在本例的加密解密過程中有大量的byte[]類型跟string類型之間的轉(zhuǎn)換,所以在例子中使用了預(yù)先定義了一個Encoding類型的對象encoding,utf-8代碼頁的,本例中所有涉及byte[]類型跟string類型之間的轉(zhuǎn)換都采用同一個Encoding,保證都是用同樣的代碼頁進行轉(zhuǎn)換。


      5、 連接加密后的對稱密鑰連接加密后的長數(shù)據(jù)

      跟連接key和IV的情況一樣,加密后的對稱密鑰和加密后的長數(shù)據(jù)也需要連接起來,同樣是通過一樣的分隔符連接。
      復(fù)制  保存
      //把加密的長數(shù)據(jù)用分隔符同加密后的DES的密鑰連接為一個字符串
      string resultEncryptedStr = longDataStrEncrypted + separator + keyandIVStrEncrypted;
      
      //加密的數(shù)據(jù)跟加密后的key、IV連接后的base64字符串再被轉(zhuǎn)成byte[]以便傳送
      byte[] resultEncryptedBytes = encoding.GetBytes(resultEncryptedStr);



      加密過程數(shù)據(jù)存在形式變化:

      RSA結(jié)合DES加密解密大數(shù)據(jù)數(shù)據(jù)存在形式變化過程&#8232;--加密過程
      單擊顯示全圖,Ctrl+滾輪縮放圖片

      上面是加密過程,下面是解密過程。


      6、 拆分加密后的對稱密鑰連接加密后的長數(shù)據(jù)

      解密過程中需要多次使用到分拆字符串功能,寫個分拆字符串的方法:
      復(fù)制  保存
      /// <summary>
      /// 根據(jù)分隔符,將分隔符兩邊的字符串分開
      /// </summary>
      /// <param name="value">帶分隔符的字符串</param>
      /// <param name="separator">分隔符</param>
      /// <returns></returns>
      private static string[] splitByString(string value, string separator)
      {
          int separatorPos = value.IndexOf(separator);
          string[] returnValue = new string[2];
          returnValue[0] = value.Substring(0, separatorPos);
          returnValue[1] = value.Substring(separatorPos + separator.Length);
          return returnValue;
      }

      解密方使用上面的方法把收到的數(shù)據(jù)分拆為加密的長數(shù)據(jù)和加密的對稱密鑰兩部分
      復(fù)制  保存
      //分拆加密的長數(shù)據(jù)和加密的對稱密鑰
      string[] EncryptedDataArray = splitByString(encoding.GetString(cryptographic), separator);
      //加密的長數(shù)據(jù)
      string longDataStrEncrypted = EncryptedDataArray[0];
      //加密的對稱密鑰
      string keyandIVStrEncrypted = EncryptedDataArray[1];



      7、 解密TripleDES算法的key和IV

      7.1.獲得RSA公鑰

      解密方獲可以從自己的pfx證書文件來獲得RSA私鑰(當(dāng)然,也可以把證書加載到證書儲存區(qū),然后到證書儲存區(qū)讀取證書獲得私鑰鑰)。載入含有私鑰的證書時,需要提供私鑰保護密碼。
      復(fù)制  保存
      //從證書文件載入證書,如果含有私鑰的,需要提供保存證書時設(shè)置的密碼
      X509Certificate2 myX509Certificate2 
          = new X509Certificate2(@"..\..\..\MyTestCert.pfx", "password");
      //從證書中獲得含私鑰的RSACryptoServiceProvider
      RSACryptoServiceProvider privatekeyProvider = (RSACryptoServiceProvider) myX509Certificate2.PrivateKey;


      7.2.RSA解密key和IV
      復(fù)制  保存
      //加密的對稱密鑰base64字符串轉(zhuǎn)成byte[]
      byte[] keyandIVBytesEncrypted = Convert.FromBase64String(keyandIVStrEncrypted);
      //解密加密的對稱密鑰并轉(zhuǎn)成字符串
      string keyandIV = encoding.GetString((publickeyProvider.Decrypt(keyandIVBytesEncrypted, false)));
      //拆分key和IV
      string[] keyIVArray = splitByString(keyandIV, separator);
      //把key從base64字符串復(fù)原為byte[]的原始形式
      byte[] keyArray = Convert.FromBase64String(keyIVArray[0]);
      //把IV從base64字符串復(fù)原為byte[]的原始形式
      byte[] IVArray = Convert.FromBase64String(keyIVArray[1]);



      8、 使用對稱密鑰加密加密的長數(shù)據(jù)
      復(fù)制  保存
      byte[] longDataBytesEncrypted = Convert.FromBase64String(longDataStrEncrypted);
      // 建立一個MemoryStream,這里面存放加密后的數(shù)據(jù)流
      MemoryStream msDecrypt = new MemoryStream(longDataBytesEncrypted);
      // 使用MemoryStream 和key、IV新建一個CryptoStream 對象
      CryptoStream csDecrypt = new CryptoStream(msDecrypt,
          new TripleDESCryptoServiceProvider().CreateDecryptor(keyArray, IVArray),
          CryptoStreamMode.Read);
      // 根據(jù)密文byte[]的長度(可能比加密前的明文長),新建一個存放解密后明文的byte[]
      byte[] DecryptDataArray = new byte[longDataBytesEncrypted.Length];
      // 把解密后的數(shù)據(jù)讀入到DecryptDataArray
      csDecrypt.Read(DecryptDataArray, 0, DecryptDataArray.Length);
      msDecrypt.Close();
      csDecrypt.Close();



      9、 得到明文長數(shù)據(jù)
      復(fù)制  保存
      //解密后的長數(shù)據(jù)byte[]轉(zhuǎn)成字符串
      string resultSrt = encoding.GetString(DecryptDataArray);
      //去掉字符串后的"\0"字符
      int offset = resultSrt.IndexOf("\0");
      string longData = resultSrt.Substring(0, offset);


      最后獲得長數(shù)據(jù)的明文,有一點需要注意。

      DES加密是以8字節(jié)為一個數(shù)據(jù)塊,如果明文的長度不是8字節(jié)的整數(shù)倍,DES會在明文后面添加值為0的字節(jié)湊足8字節(jié)的數(shù)據(jù)塊,然后加密。這樣的數(shù)據(jù)解密后,添加的”\0”仍然存在,需要去掉。 


      解密過程數(shù)據(jù)存在形式變化:

      RSA結(jié)合DES加密解密大數(shù)據(jù)數(shù)據(jù)存在形式變化過程&#8232;-- 解密過程
      單擊顯示全圖,Ctrl+滾輪縮放圖片


      參考:

      .NET中管理數(shù)字證書(Digital Certificate)的一些類
      http://blog./demonfox/archive/2007/01/23/92487.aspx

      創(chuàng)建X509證書,并獲取證書密鑰的一點研究
      http://www.cnblogs.com/BoKeRen/archive/2007/07/12/814904.html

      本文全部源代碼下載
      http://files.cnblogs.com/chnking/encryptlongdata.rar

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多