rsa加解密的內容超長的問題解決


一. 現象:
     有一段老代碼用來加密的,但是在使用key A的時候,拋出了異常: javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes老代碼已經做了分段的加密,應該是已經考慮了加密長度的問題才對。換了另一個線上代碼中的key B,正常加密沒有異常。

二. 解決:
     老代碼如下:
private static String  encryptByPublicKey(String plainText String publicKey)  throws Exception {
  int MAX_ENCRYPT_BLOCK =  128 ;
  byte[] data = plainText.getBytes( "utf-8") ;
  Key e = RSASignature. getPublicKey(publicKey) ;
  //  對數據加密
  Cipher cipher = Cipher. getInstance( "RSA") ;
  cipher.init(Cipher. ENCRYPT_MODE e) ;
  int inputLen = data. length ;
  ByteArrayOutputStream out =  new ByteArrayOutputStream() ;
  int offSet =  0 ;
  byte[] cache ;
  int i =  0 ;
  //  對數據分段加密
  while (inputLen - offSet >  0) {
    if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
      cache = cipher.doFinal(data offSet MAX_ENCRYPT_BLOCK) ;
    else {
      cache = cipher.doFinal(data offSet inputLen - offSet) ;
    }
    out.write(cache 0 cache. length) ;
    i++ ;
    offSet = i * MAX_ENCRYPT_BLOCK ;
  }
  byte[] encryptedData = out.toByteArray() ;
  out.close() ;
  return Base64. encodeBase64String(encryptedData) ;
}
     MAX_ENCRYPT_BLOCK值換為64就解決了問題。按報錯提示的改為117也可以,不過為了湊整,選擇了64。

三. 原因:
     實際使用RSA加解密算法通常有兩種不同的方式,一種是使用對稱密鑰(比如 AES/ DES等加解密方法)加密數據,然后使用非對稱密鑰(RSA加解密密鑰)加密對稱密鑰;另一種是直接使用非對稱密鑰加密數據。第一種方式安全性高,復雜度也高,不存在加密數據長度限制問題,第二種方式安全性差一些,復雜度低,但是存在加密數據限制問題(即使用非對稱密鑰加密數據時,一次加密的數據長度是(密鑰長度/8-11))。
     目前雙方約定的方式為第二種方式,而對應於本次拋錯的密鑰,key長度為1024位,1024/8 - 11 = 117,所以一次加密內容不能超過117bytes。另一個密鑰沒有問題,因為key的長度為2048位, 2048 /8 - 11 = 245, 一次加密內容不能超過 245 bytes。而分段加密代碼中用128為單位分段,從而使得一個密鑰報錯,另一個不報錯。

四.擴展:
  1. 為什么一次加密的數據長度為 (密鑰長度/8-11) ?
    網上有說明文長度小於等於密鑰長度(Bytes)-11,這說法本身不太准確,會給人感覺RSA 1024只能加密117字節長度明文。實際上,RSA算法本身要求加密內容也就是明文長度m必須0<m<n,也就是說內容這個大整數不能超過n,否則就出錯。那么如果m=0是什么結果?普遍RSA加密器會直接返回全0結果。如果m>n,由於 m e  ≡ c (mod n) ,c為密文,m為明文,e和n組成公鑰,顯然當m>n時,m與m-n得出的密文一樣,無法解密,運算就會出錯。
    所以,RSA 1024 實際可加密的明文長度最大也是1024bits,但問題就來了:

    如果小於這個長度怎么辦?就需要進行padding,因為如果沒有padding,用戶無法確分解密后內容的真實長度,字符串之類的內容問題還不大,以0作為結束符,但對二進制數據就很難理解,因為不確定后面的0是內容還是內容結束符。

    只要用到padding,那么就要占用實際的明文長度,於是才有117字節的說法。我們一般使用的padding標准有NoPPadding、OAEPPadding、PKCS1Padding等,其中PKCS#1建議的padding就占用了11個字節。

    如果大於這個長度怎么辦?很多算法的padding往往是在后邊的,但PKCS的padding則是在前面的,此為有意設計,有意的把第一個字節置0以確保m的值小於n。

    這樣,128字節(1024bits)-減去11字節正好是117字節,但對於RSA加密來講,padding也是參與加密的,所以,依然按照1024bits去理解,但實際的明文只有117字節了。

    關於PKCS#1 padding規范可參考:RFC2313 chapter 8.1,我們在把明文送給RSA加密器前,要確認這個值是不是大於n,也就是如果接近n位長,那么需要先padding再分段加密。除非我們是“定長定量自己可控可理解”的加密不需要padding。
  2. 為什么有不同長度的key?
    看一下密鑰的生成過程:
    第一步,隨機選擇兩個不相等的質數p和q。
    第二步,計算p和q的乘積n。n即密鑰長度。
    第三步,計算n的歐拉函數φ(n)。
    第四步,隨機選擇一個整數e,條件是1< e < φ(n),且e與φ(n) 互質。
    第五步,計算e對於φ(n)的模反元素d。
    第六步,將n和e封裝成公鑰,n和d封裝成私鑰。
    加密(c為密文,m為明文):   m e  ≡ c (mod n)
    解密 (c為密文,m為明文)   c d  ≡ m (mod n)
    對極大整數做因數分解(由n,e推出d)的難度決定了RSA算法的可靠性。換言之,對一極大整數做因數分解愈困難,RSA算法愈可靠。假如有人找到一種快速因數分解的算法,那么RSA的可靠性就會極度下降。但找到這樣的算法的可能性是非常小的。今天只有短的RSA密鑰才可能被暴力破解。只要密鑰長度足夠長,用RSA加密的信息實際上是不能被解破的。目前一般為1024 bit以上的密鑰,推薦2048 bit以上。
  3. 對稱加密vs分對稱加密?
    對稱加密是最快速、最簡單的一種加密方式,加密(encryption)與解密(decryption)用的是同樣的密鑰(secret key)。對稱加密有很多種算法,由於它效率很高,所以被廣泛使用在很多加密協議的核心當中。對稱加密通常使用的是相對較小的密鑰,一般小於256 bit。因為密鑰越大,加密越強,但加密與解密的過程越慢。密鑰的大小既要照顧到安全性,也要照顧到效率,是一個trade-off。對稱加密的一大缺點是密鑰的管理與分配。
    非對稱加密為數據的加密與解密提供了一個非常安全的方法,它使用了一對密鑰,公鑰(public key)和私鑰(private key)。私鑰只能由一方安全保管,不能外泄,而公鑰則可以發給任何請求它的人。非對稱加密使用這對密鑰中的一個進行加密,而解密則需要另一個密鑰。雖然非對稱加密很安全,但是和對稱加密比起來,它非常的慢。
    將兩者結合起來,將對稱加密的密鑰使用非對稱加密的公鑰進行加密,然后發送出去,接收方使用私鑰進行解密得到對稱加密的密鑰,然后雙方可以使用對稱加密來進行溝通。

五.結論:
     優先選擇方案:使用對稱密鑰(比如 AES/ DES等加解密方法)加密數據,然后使用非對稱密鑰(RSA加解密密鑰)加密對稱密鑰。原問題中由於雙方約定了非對稱加密的方式,所以用分段加密來解決了問題,但是可以知道這樣是比較低效的。


免責聲明!

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



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