2013-03-25 97 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

相关问题