2013-06-21 97 views
13

解密,我得到一個解密錯誤的java類,當輸入長度必須是16的倍數:javax.crypto.IllegalBlockSizeException:帶襯墊的密碼

javax.crypto.IllegalBlockSizeException : 
    Input length must be multiple of 16 when decrypting with padded cipher. 

我能做些什麼來解決這個問題?

UPDATE:

我忘了說,它正在一次,當第二次即時試圖再次執行其拋出上述錯誤。

package com.tb.module.service; 
import java.security.Key; 
import java.security.spec.InvalidKeySpecException; 

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

import sun.misc.*; 

/** 
* This class is used for encrypt and decrypt the password field. 
* 
*/ 
public class PswdEnc { 

    private static final String ALGO = "AES"; 
    private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' }; 

    public static String encrypt(String Data) throws Exception { 
     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGO); 
     c.init(Cipher.ENCRYPT_MODE, key); 
     byte[] encVal = c.doFinal(Data.getBytes()); 
     String encryptedValue = new BASE64Encoder().encode(encVal); 
     return encryptedValue; 
    } 

    public static String decrypt(String encryptedData) throws Exception { 
     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGO); 
     c.init(Cipher.DECRYPT_MODE, key); 
     byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData); 
     byte[] decValue = c.doFinal(decordedValue); 
     String decryptedValue = new String(decValue); 
     return decryptedValue; 
    } 


    private static Key generateKey() throws Exception { 
     Key key = new SecretKeySpec(keyValue, ALGO); 
     return key; 
    } 

} 
+0

無論你解密是錯誤的大小。它需要是塊大小的倍數(16),否則它不能被解密。你如何得到你的解密數據? – thegrinner

+0

實際上,我在將密碼保存到sql數據庫之前先對密碼進行加密。然後當檢索我試圖解密它。 – baburao113

+0

您確定要保存的數據和您讀出的數據長度相同嗎? – thegrinner

回答

2

幾點意見:

import sun.misc.*;不要這樣做。它是非標準的,不保證在實現之間相同。還有其他可用的Base64轉換庫。

byte[] encVal = c.doFinal(Data.getBytes());您在這裏依賴於默認字符編碼。始終指定使用的字符編碼:byte[] encVal = c.doFinal(Data.getBytes("UTF-8"));默認值可能在不同的地方有所不同。

正如@thegrinner指出的,你需要明確地檢查你的字節數組的長度。如果存在差異,則逐字比較它們以查看差異在哪裏蔓延。

+0

*還有其他庫可以使用Base64轉換*>從Java 6開始,請嘗試'DatatypeConverter'。 –

57

您正在使用的算法「AES」是「AES/ECB/NoPadding」的縮寫。這意味着您使用128位密鑰大小的AES algorithmblock size,使用ECBmode of operationno padding

換句話說:您只能夠以128位或16字節的塊來加密數據。這就是爲什麼你會得到這種異常。

如果要以不是16字節的倍數的大小加密數據,則要麼必須使用某種填充或密碼流。例如,通過指定「AES/CBC/NoPadding」作爲算法,或者通過指定「AES/ECB/PKCS5」指定PKCS5填充,您可以使用CBC mode(一種有效地將分組密碼轉換爲stream cipher的操作模式)以特定的格式自動在數據末尾添加一些字節,以使密文的大小爲16字節的倍數,並且解密算法將理解它必須忽略一些數據。

在任何情況下,我強烈建議你現在就停下來幹什麼,去研究一些關於密碼學的介紹性資料。例如,檢查Crypto I on Coursera。你應該很好地理解選擇這種或那種模式的意義,他們的優點是什麼,最重要的是他們的弱點。沒有這些知識,建立非常容易中斷的系統是非常容易的。


更新:基於對這個問題您的意見,永遠不要在一個數據庫存放時加密密碼!!!!!你永遠不應該這樣做。您必須HASH密碼,妥善醃製,這與加密完全不同。真的,請不要做你想做的事......通過加密密碼,他們可以被解密。這意味着,作爲數據庫管理員,誰知道密鑰,您將能夠讀取存儲在數據庫中的每個密碼。要麼你知道這一點,而是在做一件非常非常糟糕的事情,或者你不知道這件事,並且應該感到震驚並停下來。

+0

我不知道我不應該加密密碼並將其存儲在數據庫中。謝謝(你的)信息。 – baburao113

+0

@ baburao113那麼你真的應該接受的答案 –

+6

+1已有所以加密 –

2

爲了解決問題一些改變,你必須在你的代碼做只是讓加密的返回類型()類的API是byte []數組和類通byte []數組的解密()API這樣做這可以解決16個異常的輸入長度倍數。

請參考下面的工作代碼:

public static byte[] encrypt(String value) { 
     byte[] encrypted = null; 
     try { 

      byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'}; 
      Key skeySpec = new SecretKeySpec(raw, "AES"); 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      byte[] iv = new byte[cipher.getBlockSize()]; 

      IvParameterSpec ivParams = new IvParameterSpec(iv); 
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams); 
      encrypted = cipher.doFinal(value.getBytes()); 
      System.out.println("encrypted string:" + encrypted.length); 

     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return encrypted; 
    } 

    public static byte[] decrypt(byte[] encrypted) { 
     byte[] original = null; 
     Cipher cipher = null; 
     try { 
      byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'}; 
      Key key = new SecretKeySpec(raw, "AES"); 
      cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher 
      byte[] ivByte = new byte[cipher.getBlockSize()]; 
      //This class specifies an initialization vector (IV). Examples which use 
      //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation. 
      IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte); 
      cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec); 
      original= cipher.doFinal(encrypted); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return original; 
    } 
0

那麼這是因爲

,你只能在128位或16個字節的塊數據進行加密。這就是爲什麼你會得到IllegalBlockSizeException異常。 ,一種方法是直接將數據加密到字符串中。

看看這個。嘗試和u就能解決這個

public static String decrypt(String encryptedData) throws Exception { 

    Key key = generateKey(); 
    Cipher c = Cipher.getInstance(ALGO); 
    c.init(Cipher.DECRYPT_MODE, key); 
    String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim(); 
    System.out.println("This is Data to be Decrypted" + decordedValue); 
    return decordedValue; 
} 

希望會有所幫助。