解密时收到javax.crypto.IllegalBlockSizeException错误

时间:2013-01-31 07:02:45

标签: java aes encryption

我正在尝试加密/解密文件中的文本但我收到以下错误:

  

Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher

我正在使用带有AES / ECB / PKCS5Padding的AES 128位。知道我为什么会收到这个错误吗? 这是我的代码:

public class AES_Encryption  {

public static void main(String[] args) throws Exception {
    String str = new Scanner(new File("src//plainText.txt")).useDelimiter("\\Z").next();
    FileWriter fstream = new FileWriter("src//cipherText.txt");
    BufferedWriter out = new BufferedWriter(fstream);
    FileWriter fstream2 = new FileWriter("src//decrpytedText.txt");
    BufferedWriter out2 = new BufferedWriter(fstream2);
    System.out.println("" + str);


    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(128);
    Key key = keyGen.generateKey();
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] cipherText = cipher.doFinal(str.getBytes());
    String ct = new String(cipherText);
    System.out.println( new String(cipherText, "UTF8") );
    out.append(ct);
    out.close();


    String cipherT = new Scanner(new File("src//cipherText.txt")).useDelimiter("\\Z").next();
    cipher.init(Cipher.DECRYPT_MODE, key);

    //byte[] decVal = Base64.decode(cipherT.getBytes());
    byte[] newPlainText = cipher.doFinal(cipherT.getBytes());
    String dt = new String(newPlainText, "UTF8");
    out2.append(dt);
    out2.close();
}

}

2 个答案:

答案 0 :(得分:3)

您的错误是将密文视为字符串:

String ct = new String(cipherText); // <--- Noooo!

字节数组中的值不能表示为默认字符集中的字符。

始终将密文视为字节数组,即使在读取或写入文件时也是如此。

答案 1 :(得分:1)

Cipher API documentaion中提到的以下情况下获得IllegalBlockSizeException:

  

IllegalBlockSizeException - 如果此密码是块密码,则未请求填充(仅在加密模式下),以及数据的总输入长度   由此密码处理的不是块大小的倍数

在您的情况下,您正在正确加密字符串,但在解密时,您将cipherText视为String然后 您将cipherT.getBytes()字节数组放在doFinal Cipher方法中。 String的字节数组转换与以二进制模式从文件读取字节数组不同。 String API documentaion中提到的String.toBytes()的功能和限制如下:

  

使用平台的默认字符集将此String编码为字节序列,并将结果存储到新的字节数组中。该   当此字符串无法编码时此方法的行为   默认字符集未指定。 CharsetEncoder类应该是   在需要更多控制编码过程时使用。

我建议您阅读二进制模式下的cipherText.txt File,然后在doFinal Cipher方法中读取文件后输入的字节数组。我已按以下方式修改了您的代码:

public class AES_Encryption  {
public static void main(String[] args) throws Exception {
    String str = new Scanner(new File("plainText.txt")).useDelimiter("\\t").next();
    FileOutputStream fstream = new FileOutputStream("cipherText.txt");
    BufferedOutputStream out = new BufferedOutputStream(fstream);
    FileOutputStream fstream2 = new FileOutputStream("decrpytedText.txt");
    BufferedOutputStream out2 = new BufferedOutputStream(fstream2);
    System.out.println("INPUT String:\n" + str);


    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(128);
    Key key = keyGen.generateKey();
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] cipherText = cipher.doFinal(str.getBytes());
    System.out.println("ENCRYPTED String:\n"+new String(cipherText, "UTF8") );
    out.write(cipherText);
    out.flush();
    out.close();


    //String cipherT = new Scanner(new File("cipherText.txt")).nextLine();
    BufferedInputStream bfin = new BufferedInputStream(new FileInputStream(new File("cipherText.txt")));//To read the file in Binary Mode.
    cipher.init(Cipher.DECRYPT_MODE, key);
    int BUFFERSIZE = 1024;
    byte[] readBytes = new byte[BUFFERSIZE];
    byte[] data = null;
    int totalRead = -1;
    while( (totalRead = bfin.read(readBytes))!=-1)
    {
        byte[] temp = new byte[(data == null ? totalRead : data.length)];
        System.arraycopy((data==null ? readBytes : data),0,temp,0, temp.length); 
        data = new byte[(data == null ? 0 : data.length) + totalRead];
        System.arraycopy(temp, 0, data, 0, temp.length);
        System.arraycopy(readBytes, 0, data, data.length - temp.length, totalRead);
    }
    if (data!=null)
    {
        byte[] newPlainText = cipher.doFinal(data);
        out2.write(newPlainText);
        out2.flush();
        System.out.println("DECRYPTED String:\n"+new String(newPlainText,"UTF8"));
    }
    else
    {
        System.out.println("No Data Found");
    }
    //String dt = new String(newPlainText, "UTF8");
    out2.close();
}
}

我希望这可以帮助你解决你得到的异常......