Trying to Unencrypt zipped files. Some work and others don't. Those that don't work give the error when trying to close the ZipInputStream.
This was working fine when creating files on the user's computer, but I want to avoid this security risk. I thought I had all of the risks handled by deleting files in finally, but witnessed a situation where the files were not deleted. Therefore, I would like to avoid this possibility altogether. Used Using streams to decrypt and unzip to limit memory usage? to get my code to this point.
I've read several places about padding and such, but I'll admit I've inherited this code and I'm still on the learning curve.
final File file = new File(path, fileName);
Key key = new SecretKeySpec(secret, "AES");
final Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
try (FileInputStream fis = new FileInputStream(file); CipherInputStream cis = new CipherInputStream(fis, cipher); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(cis))) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
List<String> lines;
try ( ByteArrayOutputStream output = new ByteArrayOutputStream(2048)) {
int len;
while ((len = zis.read(buffer)) > 0) {
output.write(buffer, 0, len);
}
try (ByteArrayInputStream bais = new ByteArrayInputStream(output.toByteArray()); Reader reader = new InputStreamReader(bais)) {
lines = readFile(reader);
}
}
//Do something with lines of the file...
}
}
The error I get is below and is thrown on this last line (the end of the try-with-resources block.
java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
at javax.crypto.CipherInputStream.close(CipherInputStream.java:321)
at java.io.BufferedInputStream.close(BufferedInputStream.java:472)
at java.io.PushbackInputStream.close(PushbackInputStream.java:379)
at java.util.zip.InflaterInputStream.close(InflaterInputStream.java:227)
at java.util.zip.ZipInputStream.close(ZipInputStream.java:265)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:1970)
at javax.crypto.CipherInputStream.close(CipherInputStream.java:314)
I've debugged and walked through the code. The files that throw this error are unencrypted and unzipped and read properly. All of the data is read out and the "lines" are complete in every way. It just doesn't close the ZipInputStream. Any ideas?
My problem was that I was decrypting, but without rewriting to a ByteArrayOutputStream first before trying to unzip.
My code corrected and working:
public void decrypt(final byte[] secret, final File encryptedFile ) throws IOException {
final ByteArrayOutputStream baos;
try {
final Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, modelEncryptor.getKey());
try (FileInputStream fis = new FileInputStream(encryptedFile); CipherInputStream cis = new CipherInputStream(fis, cipher)) {
baos = new ByteArrayOutputStream();
byte[] buff = new byte[8];
int numRead = cis.read(buff);
while (numRead != -1) {
baos.write(buff, 0, numRead); //I was trying to combine this write with the unzipping write.
numRead = cis.read(buff);
}
}
} catch (Exception ex) {
throw new IOException("Unable to decrypt " + encryptedFile, ex);
}
try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ZipInputStream zipIn = new ZipInputStream(new BufferedInputStream(bais))) {
ZipEntry entry;
while ((entry = zipIn.getNextEntry()) != null) {
int BUFFER = 2048;
ByteArrayOutputStream fos = new ByteArrayOutputStream(2048);
try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER)) {
int count;
byte data[] = new byte[BUFFER];
while ((count = zipIn.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
}
dest.flush();
}
final List<String> lines = Arrays.asList(fos.toString().split("\r\n"));
//Do something with lines...
}
}
baos.close();
}
By separating the decrypting from the unzipping, everything works great now. Hope this helps someone else someday.
P.S. I changed nothing on the encrypting side.