简体   繁体   中英

Password protected zip file in java

I have created zip file using java as below snippet

import java.io.*;
import java.util.zip.*;

public class ZipCreateExample {
  public static void main(String[] args) throws IOException {
    System.out.print("Please enter file name to zip : ");
    BufferedReader input = new BufferedReader
        (new InputStreamReader(System.in));
    String filesToZip = input.readLine();
    File f = new File(filesToZip);
    if(!f.exists()) {
      System.out.println("File not found.");
      System.exit(0);
    }
    System.out.print("Please enter zip file name : ");
    String zipFileName = input.readLine();
    if (!zipFileName.endsWith(".zip"))
      zipFileName = zipFileName + ".zip";
    byte[] buffer = new byte[18024];
    try {
      ZipOutputStream out = new ZipOutputStream
          (new FileOutputStream(zipFileName));
      out.setLevel(Deflater.DEFAULT_COMPRESSION);
      FileInputStream in = new FileInputStream(filesToZip);
      out.putNextEntry(new ZipEntry(filesToZip));
      int len;
      while ((len = in.read(buffer)) > 0) {
        out.write(buffer, 0, len);
      }
      out.closeEntry();
      in.close();
      out.close();
    } catch (IllegalArgumentException iae) {
      iae.printStackTrace();
      System.exit(0);
    } catch (FileNotFoundException fnfe) {
      fnfe.printStackTrace();
      System.exit(0);
    } catch (IOException ioe) {
      ioe.printStackTrace();
      System.exit(0);
    }
  }
}

Now I want when I click on the zip file it should prompt me to type password and then decompress the zip file. Please any help,How should I go further?

Try the following code which is based onZip4j :

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.commons.io.FilenameUtils;

import java.io.File;

public class Zipper
{
    private String password;
    private static final String EXTENSION = "zip";

    public Zipper(String password)
    {
        this.password = password;
    }

    public void pack(String filePath) throws ZipException
    {
        ZipParameters zipParameters = new ZipParameters();
        zipParameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        zipParameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_ULTRA);
        zipParameters.setEncryptFiles(true);
        zipParameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
        zipParameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
        zipParameters.setPassword(password);
        String baseFileName = FilenameUtils.getBaseName(filePath);
        String destinationZipFilePath = baseFileName + "." + EXTENSION;
        ZipFile zipFile = new ZipFile(destinationZipFilePath);
        zipFile.addFile(new File(filePath), zipParameters);
    }

    public void unpack(String sourceZipFilePath, String extractedZipFilePath) throws ZipException
    {
        ZipFile zipFile = new ZipFile(sourceZipFilePath + "." + EXTENSION);

        if (zipFile.isEncrypted())
        {
            zipFile.setPassword(password);
        }

        zipFile.extractAll(extractedZipFilePath);
    }
}

FilenameUtils is from Apache Commons IO .

Example usage:

public static void main(String[] arguments) throws ZipException
{
    Zipper zipper = new Zipper("password");
    zipper.pack("encrypt-me.txt");
    zipper.unpack("encrypt-me", "D:\\");
}

Standard Java API does not support password protected zip files. Fortunately good guys have already implemented such ability for us. Please take a look on this article that explains how to create password protected zip.
(The link was dead, latest archived version: https://web.archive.org/web/20161029174700/http://java.sys-con.com/node/1258827 )

Sample code below will zip and password protect your file. This REST service accepts bytes of the original file. It zips the byte array and password protects it. Then it sends bytes of password protected zipped file as response. The code is a sample of sending and receiving binary bytes to and from a REST service, and also of zipping a file with password protect. The bytes are zipped from stream, so no files are ever stored on the server.

  • Uses JAX-RS API using Jersey API in java
  • Client is using Jersey-client API.
  • Uses zip4j 1.3.2 open source library, and apache commons io.


    @PUT
    @Path("/bindata/protect/qparam")
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response zipFileUsingPassProtect(byte[] fileBytes, @QueryParam(value = "pass") String pass,
            @QueryParam(value = "inputFileName") String inputFileName) {

        System.out.println("====2001==== Entering zipFileUsingPassProtect");
        System.out.println("fileBytes size = " + fileBytes.length);
        System.out.println("password = " + pass);
        System.out.println("inputFileName = " + inputFileName);

        byte b[] = null;
        try {
            b = zipFileProtected(fileBytes, inputFileName, pass);
        } catch (IOException e) {
            e.printStackTrace();
            return Response.status(Status.INTERNAL_SERVER_ERROR).build();
        }
        System.out.println(" ");
        System.out.println("++++++++++++++++++++++++++++++++");
        System.out.println(" ");
        return Response.ok(b, MediaType.APPLICATION_OCTET_STREAM)
                .header("content-disposition", "attachment; filename = " + inputFileName + ".zip").build();

    }

    private byte[] zipFileProtected(byte[] fileBytes, String fileName, String pass) throws IOException {

        ByteArrayInputStream inputByteStream = null;
        ByteArrayOutputStream outputByteStream = null;
        net.lingala.zip4j.io.ZipOutputStream outputZipStream = null;

        try {
            //write the zip bytes to a byte array
            outputByteStream = new ByteArrayOutputStream();
            outputZipStream = new net.lingala.zip4j.io.ZipOutputStream(outputByteStream);

            //input byte stream to read the input bytes
            inputByteStream = new ByteArrayInputStream(fileBytes);

            //init the zip parameters
            ZipParameters zipParams = new ZipParameters();
            zipParams.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
            zipParams.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
            zipParams.setEncryptFiles(true);
            zipParams.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
            zipParams.setPassword(pass);
            zipParams.setSourceExternalStream(true);
            zipParams.setFileNameInZip(fileName);

            //create zip entry
            outputZipStream.putNextEntry(new File(fileName), zipParams);
            IOUtils.copy(inputByteStream, outputZipStream);
            outputZipStream.closeEntry();

            //finish up
            outputZipStream.finish();

            IOUtils.closeQuietly(inputByteStream);
            IOUtils.closeQuietly(outputByteStream);
            IOUtils.closeQuietly(outputZipStream);

            return outputByteStream.toByteArray();

        } catch (ZipException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(inputByteStream);
            IOUtils.closeQuietly(outputByteStream);
            IOUtils.closeQuietly(outputZipStream);
        }
        return null;
    }

Unit test below:


    @Test
    public void testPassProtectZip_with_params() {
        byte[] inputBytes = null;
        try {
            inputBytes = FileUtils.readFileToByteArray(new File(inputFilePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("bytes read into array. size = " + inputBytes.length);

        Client client = ClientBuilder.newClient();

        WebTarget target = client.target("http://localhost:8080").path("filezip/services/zip/bindata/protect/qparam");
        target = target.queryParam("pass", "mypass123");
        target = target.queryParam("inputFileName", "any_name_here.pdf");

        Invocation.Builder builder = target.request(MediaType.APPLICATION_OCTET_STREAM);

        Response resp = builder.put(Entity.entity(inputBytes, MediaType.APPLICATION_OCTET_STREAM));
        System.out.println("response = " + resp.getStatus());
        Assert.assertEquals(Status.OK.getStatusCode(), resp.getStatus());

        byte[] zipBytes = resp.readEntity(byte[].class);
        try {
            FileUtils.writeByteArrayToFile(new File(responseFilePathPasswordZipParam), zipBytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Feel free to use and modify. Please let me know if you find any errors. Hope this helps.

Edit 1 - Using QueryParam but you may use HeaderParam for PUT instead to hide passwd from plain sight. Modify the test method accordingly.

Edit 2 - REST path is filezip/services/zip/bindata/protect/qparam

filezip is name of war. services is the url mapping in web.xml. zip is class level path annotation. bindata/protect/qparam is the method level path annotation.

There is no default Java API to create a password protected file. There is another example about how to do it here .

In new version of Zip4j , class Zip4jConstants was removed. Use EncryptionMethod and AesKeyStrength class instead. Documentation : https://github.com/srikanth-lingala/zip4j

ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256); 

List<File> filesToAdd = Arrays.asList(
    new File("somefile"), 
    new File("someotherfile")
);

ZipFile zipFile = new ZipFile("filename.zip", "password".toCharArray());
zipFile.addFiles(filesToAdd, zipParameters);

Library Zip4J seems to be the preferred answer. In case the privacy of the password is highly recommended, one might close a security gap in class ZipFile , which carries the password in plain text , even after the ZipFile is closed. Following method destroys the password.

public static void destroyZipPassword(ZipFile zip) throws DestroyFailedException
{
    try
    {
        Field fdPwd = ZipFile.class.getDeclaredField("password");
        fdPwd.setAccessible(true);
        char[] password = (char[]) fdPwd.get(zip);
        Arrays.fill(password, (char) 0);
    }
    catch (Exception e)
    {
        e.printStackTrace();
        throw new DestroyFailedException(e.getMessage());
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM