目的
Java標準のjava.util.zipは暗号化に対応していません。
なので暗号化zipをしようとすると別途ライブラリが必要になります。
色々試したのですが、結局は一番メジャーらしいzip4jを使うことにしました。
zip4j
公式サイトはこちら
Maven Repositoryはこちら
最新のバージョンは1.3.2のようです。
コード
依存ライブラリを定義
pom.xml
<dependencies>
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
暗号化zip部分
このライブラリに限らないのですが、zipエントリを作る際、実際に存在するファイルの属性を取得して利用しているため、バイト配列だけでは直接zipエントリを作成できません。
なので、Fileクラスの匿名クラスを使って対処します。
ただ、階層構造をもったzipファイルを作ろうとすると面倒なので、その場合は一時的にローカル出力したファイルを圧縮した方が楽かもしれません。
Zip.java
package com.company;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
public class Zip {
public byte[] encryptZip(final String fileName, final byte[] input, String password) throws IOException, ZipException {
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
parameters.setEncryptFiles(true);
parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
parameters.setPassword(password);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try (net.lingala.zip4j.io.ZipOutputStream zipOutputStream = new net.lingala.zip4j.io.ZipOutputStream(byteArrayOutputStream)) {
File file = new File(fileName) {
@Override
public boolean exists() {return true;}
@Override
public boolean isDirectory() {return false;}
@Override
public String getAbsolutePath() {return fileName;}
@Override
public boolean isHidden() {return false;}
@Override
public long lastModified() {return System.currentTimeMillis();}
@Override
public long length() {return input.length;}
};
zipOutputStream.putNextEntry(file, parameters);
zipOutputStream.write(input);
zipOutputStream.closeEntry();
zipOutputStream.finish();
}
return byteArrayOutputStream.toByteArray();
}
}
呼び出し
あとはファイル名と暗号化zip圧縮したいバイト配列、パスワードを渡すだけです
Main.java
public static void main(String[] args) {
Zip zip = new Zip();
try {
byte[] encrypted = zip.encryptZip("hoge.txt", new byte[]{0x30, 0x30}, "testPwd");
try(FileOutputStream stream = new FileOutputStream(".\test.zip")) {
stream.write(encrypted);
}
} catch (IOException | ZipException e) {
e.printStackTrace();
}
}
全部オンメモリで処理したい場合はこうなるかなと。