2013-03-25 58 views
1

我需要此錯誤的幫助:給定最終塊未正確填充。從標題中可以看出,我正在與AES合作。AES錯誤:鑑於最終塊未正確填充

這裏是行的代碼,其中的錯誤:

byte[] decrypted = cipher.doFinal(bytes); 

下面是完整的代碼:

public class AESCrypt { 
private final Cipher cipher; 
private final SecretKeySpec key; 
private String encryptedText, decryptedText; 

public AESCrypt(String password) throws Exception { 
    // hash password with SHA-256 and crop the output to 128-bit for key 
    MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
    digest.update(password.getBytes("UTF-8")); 
    byte[] keyBytes = new byte[16]; 
    System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length); 

    cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    key = new SecretKeySpec(keyBytes, "AES"); 
} 

public String encrypt(String plainText) throws Exception { 
    byte[] iv = new byte[cipher.getBlockSize()]; 
    new SecureRandom().nextBytes(iv); 
    AlgorithmParameterSpec spec = new IvParameterSpec(iv); 
    cipher.init(Cipher.ENCRYPT_MODE, key, spec); 
    byte[] encrypted = cipher.doFinal(plainText.getBytes()); 
    encryptedText = asHex(encrypted); 
    return encryptedText; 
} 

public String decrypt(String cryptedText) throws Exception { 
    byte[] iv = new byte[cipher.getBlockSize()]; 
    AlgorithmParameterSpec spec = new IvParameterSpec(iv); 
    cipher.init(Cipher.DECRYPT_MODE, key, spec); 
    // decrypt the message 
    byte[] bytes = cryptedText.getBytes("UTF-8"); 
    byte[] decrypted = cipher.doFinal(bytes); 
    decryptedText = asHex(decrypted); 
    System.out.println("Desifrovani tekst: " + decryptedText + "\n"); 

    return decryptedText; 
} 

public static String asHex(byte buf[]) { 
    StringBuilder strbuf = new StringBuilder(buf.length * 2); 
    int i; 
    for (i = 0; i < buf.length; i++) { 
     if (((int) buf[i] & 0xff) < 0x10) { 
      strbuf.append("0"); 
     } 
     strbuf.append(Long.toString((int) buf[i] & 0xff, 16)); 
    } 
    return strbuf.toString(); 
} 

public static void main(String[] args) throws Exception { 

    System.out.print("....AES....\n"); 

    String message = "MESSAGE"; 
    String password = "PASSWORD"; 

    System.out.println("MSG:" + message); 

    AESCrypt aes = new AESCrypt(password); 
    String encryptedText = aes.encrypt(message).toString(); 
    System.out.println("SIFROVANA PORUKA: " + encryptedText); 
    String decryptedText = aes.decrypt(encryptedText).toString();  
    System.out.print("DESIFROVANA PORUKA: " + decryptedText); 
} 

}

+0

我會建議你使用Apache Commons編解碼器[十六進制](http://commons.apache.org/proper/commons- codec/apidocs/org/apache/commons/codec/binary/Hex.html)而不是滾動自己的十六進制編碼器和解碼器 – 2013-03-25 21:25:42

+0

我在互聯網上看過很多例子,其中人們使用BASE64Decoder和BASE64Encoder?但似乎我不能使用它。 – Zookey 2013-03-25 21:51:07

+0

因爲它們位於sun名稱空間中,所以使用它們並不是一個最佳實踐,並且可能不一定在JDK的所有實現中都有。如果你想在沒有庫的情況下進行Base64編碼和解碼,並且你正在支持Java 6+,請使用[本答案](http://stackoverflow.com/a/2054226/1904979)中概述的JAXB – 2013-03-25 21:54:00

回答

2

根據你的評論,你很接近獲得加密工作。

你需要從你的加密/解密方法移動IV代碼到其他地方,像這樣

public AlgorithmParameterSpec getIV() { 
AlgorithmParameterSpec ivspec; 
byte[] iv = new byte[cipher.getBlockSize()]; 
new SecureRandom().nextBytes(iv); 
ivspec = new IvParameterSpec(iv); 
} 

那麼ivspec傳遞到兩個加密和解密方法(使它們看起來像encrypt(String,AlgorithmParameterSpec)) ,這樣你的加密和解密都有相同的iv。

而且,不要對decryptedByteArray調用printBase64Binary,而是調用new String(decryptedByteArray, "UTF-8")

+0

非常感謝。這工作。 :)) – Zookey 2013-03-26 13:33:53

+2

一旦你初始化這個類,它的IV是固定的。這種結構違反了CBC的每個關鍵的IV規則,IV不能重複,IV不可預測。因此它在語義上不安全。 – jbtule 2013-03-26 13:47:05

+0

沒錯,一個更好的構造是將IV加密或解密的方法傳遞出去,或者傳遞IV或者附加在一個地方或者另一個地方。這也有一個問題,即程序的兩個獨立運行將有兩個單獨的IV,這將導致解密損壞。我已經編輯了這個問題來反映一個更好的方法來做到這一點 – 2013-03-26 13:57:32

0

你有兩個問題,第一你編碼輸出到一個十六進制字符串,但不解碼解碼方法。其次,你生成一個隨機的IV,但不要再次使用它來解碼。

public byte[] encrypt(String plainText) throws Exception { 
    byte[] iv = new byte[cipher.getBlockSize()];  
    AlgorithmParameterSpec spec = new IvParameterSpec(iv); 
    cipher.init(Cipher.ENCRYPT_MODE, key, spec); 
    return cipher.doFinal(plainText.getBytes()); 
} 

public String decrypt(byte[] cryptedText) throws Exception { 
    byte[] iv = new byte[cipher.getBlockSize()]; 
    AlgorithmParameterSpec spec = new IvParameterSpec(iv); 
    cipher.init(Cipher.DECRYPT_MODE, key, spec); 
    // decrypt the message 
    byte[] decrypted = cipher.doFinal(cryptedText); 
    decryptedText = new String(decrypted, "UTF-8"); 
    return decryptedText; 
} 



String decryptedText = aes.decrypt(aes.encrypt(message)).toString();  
+0

第一個問題(不解碼十六進制輸出)是問題中的錯誤的原因,但第二個問題(IV問題)將導致第一個解密明文塊上的亂碼明文輸出。 – 2013-03-25 21:24:42

+1

這就是說,這個答案中的代碼有兩個問題:1,它使用一個全零字符串作爲IV,這從安全角度來看是不好的.2。調用'getBytes()時它沒有指定字符串編碼',當解密另一端的文本時會導致問題 – 2013-03-25 21:29:18

+0

使用此代碼時,它爲加密文本提供所有時間相同的輸出。 – Zookey 2013-03-25 21:45:10

相關問題