xyiong
xyiong

Reputation: 373

Java - AES encrypting a zip file causes it to be corrupted

I am trying to encrypt a zip file with a password using AES-256 encryption. Below is the code that I am running.

import java.io.*;
import java.security.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;


public class Main {
    public static void encryptAndClose(FileInputStream fis, FileOutputStream fos) 
            throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {

        // Length is 16 byte
        SecretKeySpec sks = new SecretKeySpec("1234567890123456".getBytes(), "AES");
        // Create cipher
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, sks);      

        // Wrap the output stream for encoding
        CipherOutputStream cos = new CipherOutputStream(fos, cipher);       

        //wrap output with buffer stream
        BufferedOutputStream bos = new BufferedOutputStream(cos);     

        //wrap input with buffer stream
        BufferedInputStream bis = new BufferedInputStream(fis); 

        // Write bytes
        int b;
        byte[] d = new byte[8];
        while((b = bis.read(d)) != -1) {
            bos.write(d, 0, b);
        }
        // Flush and close streams.
        bos.flush();
        bos.close();
        bis.close();
    }


    public static void decryptAndClose(FileInputStream fis, FileOutputStream fos) 
            throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {

        SecretKeySpec sks = new SecretKeySpec("1234567890123456".getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, sks);

        CipherInputStream cis = new CipherInputStream(fis, cipher);

        //wrap input with buffer stream
        BufferedInputStream bis = new BufferedInputStream(cis); 

        //wrap output with buffer stream
        BufferedOutputStream bos = new BufferedOutputStream(fos);       

        int b;
        byte[] d = new byte[8];
        while((b = bis.read(d)) != -1) {
            bos.write(d, 0, b);
        }
        bos.flush();
        bos.close();
        bis.close();
    }
    
    
    static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
        if (fileToZip.isHidden()) {
            return;
        }
        if (fileToZip.isDirectory()) {
            if (fileName.endsWith("/")) {
                zipOut.putNextEntry(new ZipEntry(fileName));
                zipOut.closeEntry();
            } else {
                zipOut.putNextEntry(new ZipEntry(fileName + "/"));
                zipOut.closeEntry();
            }
            File[] children = fileToZip.listFiles();
            for (File childFile : children) {
                zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);
            }
            return;
        }
        FileInputStream fis = new FileInputStream(fileToZip);
        ZipEntry zipEntry = new ZipEntry(fileName);
        zipOut.putNextEntry(zipEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
            zipOut.write(bytes, 0, length);
        }
        fis.close();
    }
    
    static void unZipFile(ZipEntry zipEntry,File destDir,ZipInputStream zis, byte[] buffer) throws IOException{
        while (zipEntry != null) {
            File newFile = newFile(destDir, zipEntry);
            if (zipEntry.isDirectory()) {
                if (!newFile.isDirectory() && !newFile.mkdirs()) {
                    throw new IOException("Failed to create directory " + newFile);
                }
            } else {
                // fix for Windows-created archives
                File parent = newFile.getParentFile();
                if (!parent.isDirectory() && !parent.mkdirs()) {
                    throw new IOException("Failed to create directory " + parent);
                }
                
                // write file content
                FileOutputStream fos = new FileOutputStream(newFile);
                int len;
                while ((len = zis.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                }
                fos.close();
            }
        zipEntry = zis.getNextEntry();
       }
    }
    public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
        File destFile = new File(destinationDir, zipEntry.getName());

        String destDirPath = destinationDir.getCanonicalPath();
        String destFilePath = destFile.getCanonicalPath();

        if (!destFilePath.startsWith(destDirPath + File.separator)) {
            throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
        }

        return destFile;
    }
    
    public static void main(String[]args) {
        
        //compress to zip.
        String sourceFile = "C:\\test";
        FileOutputStream fos;
        try {
            fos = new FileOutputStream("C:\\test\\test.zip");
            ZipOutputStream zipOut = new ZipOutputStream(fos);
            File fileToZip = new File(sourceFile);

            zipFile(fileToZip, fileToZip.getName(), zipOut);
            zipOut.close();
            fos.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //encrypt the zip.
        String outDir = "C:/test";
        String outFilename = "test-encrypt.zip";
        
        String inDir = "C:/test";
        String inFilename = "test.zip";
        
        File output= new File(outDir, outFilename);

        File input= new File(inDir, inFilename);

        if (input.exists()) {
            System.out.println("test");
            FileInputStream inStream;
            try {
                inStream = new FileInputStream(input);
                FileOutputStream outStream = new FileOutputStream(output);
    
                encryptAndClose(inStream, outStream);   
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

The intent of the code is to create a zip file then encrypt the generated zip file with AES. The code can successfully generate a zip file that can be zipped and unzipped with WinZip or 7zip.

However, when it tries to encrypt the generated zip file, the code instead causes the file (e.g.test-encrypt.zip) to be corrupted and cannot be opened by programs like WinZip or 7zip.

I wish to do this without using zip4j if possible. Is there any problem with my code or understanding of the code?

This is my first time working with encryption and any help would be much appreciated!

Upvotes: 0

Views: 801

Answers (2)

Oleg Cherednik
Oleg Cherednik

Reputation: 18255

Java does not support zip file encryption. Anyway, it supports very limited activities with zip files. You have to try to make you work with zip file much more easy. E.g. you can check zip4jvm

Create (or open existed) zip archive and add some regular files and/or directories with AES 256bit encryption.

Path zip = Paths.get("filename.zip");
Collection<Path> paths = Arrays.asList(
        Paths.get("/bikes/ducati-panigale-1199.jpg"),
        Paths.get("/bikes/honda-cbr600rr.jpg"),
        Paths.get("/cars"),
        Paths.get("/saint-petersburg.jpg"));
ZipEntrySettings settings = ZipEntrySettings.builder()
                                            .encryption(Encryption.AES_256, "password".toCharArray())
                                            .build();
ZipIt.zip(zip).entrySettings(settings).add(paths);

To get more details about AES encryptions in zip you can check AesEncoder.java

Upvotes: 0

Ishan
Ishan

Reputation: 537

If you create a ZIP first, and then encrypt the ZIP file using AES algorithm or whatever algorithm, the output file won't remain a ZIP. It won't be following the ZIP standard format. So, it won't be possible to unzip.

You need to first Decrypt the file and get back the original ZIP, and then only that original zip can be opened/unzipped using any wellknown zip handling software.

Encrypting a ZIP file will result in the bytes inside the file changed, which will result in the software not recognizing the file header, necessary ZipEntry record structure, etc.

The best option is to provide a password at the time of creating the zip, so that it cannot be unzipped without a password. OR Encrypt the original files, and then put the encrypted files inside the Zip. But, don't encrypt the ZIP file.

Upvotes: 2

Related Questions