2013-04-28 33 views
1

解密它時,我得到了下面的錯誤,我能夠但是對數據進行加密:加密和解密使用的Blowfish錯誤 - 與解密時輸入長度必須是多個的8填充密碼

錯誤

HTTP Status 500 - Request processing failed; nested exception is javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher 

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894) 
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728) 

這是我的加密和解密代碼

//secret key 8 
    private static String strkey ="Blowfish"; 

修訂

//encrypt using blowfish algorithm 
    public static byte[] encrypt(String Data)throws Exception{ 

     SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish"); 
     Cipher cipher = Cipher.getInstance("Blowfish"); 
     cipher.init(Cipher.ENCRYPT_MODE, key); 

     return (cipher.doFinal(Data.getBytes("UTF8"))); 

    } 

    //decrypt using blow fish algorithm 
    public static String decrypt(byte[] encryptedData)throws Exception{ 
     SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish"); 
     Cipher cipher = Cipher.getInstance("Blowfish"); 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     byte[] decrypted = cipher.doFinal(encryptedData); 
     return new String(decrypted); 

    } 

回答

3

如果您在主要方法中運行加密和解密方法,它將起作用。但是,如果加密的結果放入一個url中,然後url參數被解密,它將會失敗。

加密後,字節數組包含URLS(non-ascii)字符集之外的值,因此當將值填充到url中時,該值被編碼。而且你收到一個用於解密的損壞版本。

作爲一個例子,當我從一個加密的字節數組創建一個字符串時,它看起來像這個Ž¹Qêz¦,但是如果我把它放入一個URL,它會變成Ž%0B¹Qêz¦

正如其他評論中所建議的,修復程序是添加編碼/解碼步驟。加密後,值應該被編碼爲包含ascii字符的格式。 Base 64是一個很好的選擇。所以你在url中返回加密和編碼值。當你收到參數時,首先解碼然後解密,然後你會得到原始數據。

以下是關於實施的一些說明。

  1. 使用類似普通編解碼器的庫。這是我選擇的武器,本課程專門爲http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64.html

  2. 在進行加密和解密的類中,有一個Base64的共享實例。要實例化它,使用new Base64(true);這會產生url安全字符串。

  3. 您的加密和解密方法簽名應接受並返回字符串,而不是字節數組。

  4. 所以你加密的最後一行將成爲像return base64.encodeToString(cipher.doFinal(Data.getBytes("UTF8")));您現在可以安全地在URL

  5. 通過加密值在你解密,你的第一步是進行解碼。所以,第一行會成爲像byte[] encryptedData = base64.decodeBase64(encrypted);

我只是把你的代碼,增加了一些基本的東西64,結果是這樣的:

import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 

import org.apache.commons.codec.binary.Base64; 


public class Test { 

    private static String strkey ="Blowfish"; 
    private static Base64 base64 = new Base64(true); 

    //encrypt using blowfish algorithm 
    public static String encrypt(String Data)throws Exception{ 

     SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish"); 
     Cipher cipher = Cipher.getInstance("Blowfish"); 
     cipher.init(Cipher.ENCRYPT_MODE, key); 

     return base64.encodeToString(cipher.doFinal(Data.getBytes("UTF8"))); 

    } 

    //decrypt using blow fish algorithm 
    public static String decrypt(String encrypted)throws Exception{ 
     byte[] encryptedData = base64.decodeBase64(encrypted); 
     SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish"); 
     Cipher cipher = Cipher.getInstance("Blowfish"); 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     byte[] decrypted = cipher.doFinal(encryptedData); 
     return new String(decrypted); 

    } 

    public static void main(String[] args) throws Exception { 
     String data = "will this work?"; 
     String encoded = encrypt(data); 
     System.out.println(encoded); 
     String decoded = decrypt(encoded); 
     System.out.println(decoded); 
    } 
} 

希望這回答了你的問題。

+0

我在類中得到以下錯誤構造函數Base64(布爾)未定義爲私有靜態Base64 base64 =新Base64(true); – devdar 2013-04-29 23:35:42

+0

你能給我一些關於這個問題的建議嗎http://stackoverflow.com/questions/16290808/spring-mvc-url-mapping-in-controller-for-dynamic-urls?noredirect=1#comment23324237_16290808 – devdar 2013-04-30 10:54:55

+0

你還可以看看在這個問題對我來說http://stackoverflow.com/questions/16305926/springmvc-looping-through-list-data-passed-from-the-view – devdar 2013-04-30 22:04:28

1

不能創建一個字符串出隨機的(在這種情況下加密)字節你是在爲你的加密方法的最後一行做 - 你需要創建一個Base64 encoded string代替(然後您需要在解密方法中解碼回字節數組)。或者,只需讓您的加密方法返回一個字節數組,並讓您的解密方法接受一個字節數組作爲其參數。

+0

我不知道我完全理解我應該刪除cipher.doFinal,只是做Data.getBytes(「UTF8」)? – devdar 2013-04-28 03:31:17

+1

刪除'new String'部分,保留'return cipher.doFinal(Data.getBytes(「UTF8」))'部分;改變'encrypt',以便它返回一個'byte []'而不是一個'String',並且改變'decrypt',這樣就需要'byte [] encryptedData' – 2013-04-28 03:33:19

+0

我更新了代碼,但是我得到了同樣的錯誤 – devdar 2013-04-28 03:46:34

1

問題出在您從原始加密的byte[]數據中創建String實例的方式。您需要通過parseHexBinaryprintHexBinary方法或使用同一對象的parseBase64BinaryprintBase64Binary方法使用javax.xml.bind.DatatypeConverter提供的binhex編碼。

另一個建議的話,從來不依賴於默認模式和填充,總是顯式的。根據您的需求,使用類似Cipher.getInstance("Blowfish/CBC/PKCS5Padding")的東西。

+0

的所有好建議。 – 2013-04-28 22:14:22

相關問題