[英]Password protected zip file in java
我已经使用 java 创建了 zip 文件,如下所示
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);
}
}
}
现在我想要当我点击 zip 文件时,它应该提示我输入密码,然后解压缩 zip 文件。 请任何帮助,我应该如何走得更远?
尝试以下基于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
来自Apache Commons IO
。
用法示例:
public static void main(String[] arguments) throws ZipException
{
Zipper zipper = new Zipper("password");
zipper.pack("encrypt-me.txt");
zipper.unpack("encrypt-me", "D:\\");
}
标准 Java API 不支持受密码保护的 zip 文件。 幸运的是,好人已经为我们实现了这种能力。 请查看这篇文章,它解释了如何创建受密码保护的 zip。
(链接已死,最新存档版本: https : //web.archive.org/web/20161029174700/http : //java.sys-con.com/node/1258827 )
下面的示例代码将压缩和密码保护您的文件。 此 REST 服务接受原始文件的字节。 它压缩字节数组并用密码保护它。 然后它发送受密码保护的压缩文件字节作为响应。 该代码是向 REST 服务发送和接收二进制字节的示例,也是使用密码保护压缩文件的示例。 字节是从流中压缩的,因此服务器上永远不会存储任何文件。
@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;
}
单元测试如下:
@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();
}
}
随意使用和修改。 如果您发现任何错误,请告诉我。 希望这可以帮助。
编辑 1 - 使用 QueryParam 但您可以使用 HeaderParam 代替 PUT 来隐藏密码。 相应地修改测试方法。
编辑 2 - REST 路径是 filezip/services/zip/bindata/protect/qparam
filezip 是战争的名称。 services 是 web.xml 中的 url 映射。 zip 是类级别的路径注释。 bindata/protect/qparam 是方法级别的路径注释。
没有用于创建受密码保护的文件的默认 Java API。 有一个关于如何做到这一点另一个例子在这里。
在Zip4j的新版本中,除去类Zip4jConstants。 请改用EncryptionMethod和AesKeyStrength类。 文档: 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);
库Zip4J似乎是首选答案。 如果强烈建议保护密码的隐私,则可以关闭class ZipFile
的安全漏洞, class ZipFile
以纯文本形式携带密码,即使在 ZipFile 关闭后也是如此。 以下方法会破坏密码。
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());
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.