Java
zip
Zip4j

Zip4jでバイト配列を暗号化zip圧縮する

More than 3 years have passed since last update.

目的

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();
        }
    }

全部オンメモリで処理したい場合はこうなるかなと。