Password protected zip file in java
Solution 1:
Try the following code which is based on Zip4j
:
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:\\");
}
Solution 2:
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)
Solution 3:
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.
Solution 4:
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);