[Git][java-team/zip4j][upstream] New upstream version 2.6.4
Andrius Merkys
gitlab at salsa.debian.org
Fri Oct 23 15:03:22 BST 2020
Andrius Merkys pushed to branch upstream at Debian Java Maintainers / zip4j
Commits:
9e32a231 by Andrius Merkys at 2020-10-23T09:33:42-04:00
New upstream version 2.6.4
- - - - -
15 changed files:
- README.md
- pom.xml
- src/main/java/net/lingala/zip4j/crypto/AESDecrypter.java
- src/main/java/net/lingala/zip4j/crypto/AESEncrpyter.java → src/main/java/net/lingala/zip4j/crypto/AESEncrypter.java
- src/main/java/net/lingala/zip4j/crypto/AesCipherUtil.java
- src/main/java/net/lingala/zip4j/exception/ZipException.java
- src/main/java/net/lingala/zip4j/headers/HeaderWriter.java
- src/main/java/net/lingala/zip4j/io/inputstream/CipherInputStream.java
- src/main/java/net/lingala/zip4j/io/inputstream/ZipInputStream.java
- src/main/java/net/lingala/zip4j/io/outputstream/AesCipherOutputStream.java
- src/main/java/net/lingala/zip4j/tasks/AbstractAddFileToZipTask.java
- src/main/java/net/lingala/zip4j/tasks/AbstractModifyFileTask.java
- src/main/java/net/lingala/zip4j/util/InternalZipConstants.java
- src/test/java/net/lingala/zip4j/ZipFileZip64IT.java
- src/test/java/net/lingala/zip4j/io/inputstream/ZipInputStreamIT.java
Changes:
=====================================
README.md
=====================================
@@ -71,7 +71,7 @@ Zip4j supports JDK 7 as well. In cases where the feature/class from JDK 8 is mis
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
- <version>2.6.3</version>
+ <version>2.6.4</version>
</dependency>
```
=====================================
pom.xml
=====================================
@@ -6,7 +6,7 @@
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
- <version>2.6.4-SNAPSHOT</version>
+ <version>2.6.5-SNAPSHOT</version>
<name>Zip4j</name>
<description>Zip4j - A Java library for zip files and streams</description>
@@ -31,7 +31,7 @@
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
- <junit.version>4.12</junit.version>
+ <junit.version>4.13.1</junit.version>
<lombok.version>1.18.8</lombok.version>
<assertj.version>3.12.2</assertj.version>
<mockito.version>2.28.2</mockito.version>
=====================================
src/main/java/net/lingala/zip4j/crypto/AESDecrypter.java
=====================================
@@ -17,8 +17,6 @@
package net.lingala.zip4j.crypto;
import net.lingala.zip4j.crypto.PBKDF2.MacBasedPRF;
-import net.lingala.zip4j.crypto.PBKDF2.PBKDF2Engine;
-import net.lingala.zip4j.crypto.PBKDF2.PBKDF2Parameters;
import net.lingala.zip4j.crypto.engine.AESEngine;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.AESExtraDataRecord;
@@ -29,10 +27,11 @@ import java.util.Arrays;
import static net.lingala.zip4j.crypto.AesCipherUtil.prepareBuffAESIVBytes;
import static net.lingala.zip4j.util.InternalZipConstants.AES_BLOCK_SIZE;
+/**
+ * AES Decrypter supports AE-1 and AE-2 decryption for AES-CTR with 128, 192, or 256 Key Strength
+ */
public class AESDecrypter implements Decrypter {
- public static final int PASSWORD_VERIFIER_LENGTH = 2;
-
private AESExtraDataRecord aesExtraDataRecord;
private char[] password;
private AESEngine aesEngine;
@@ -51,34 +50,19 @@ public class AESDecrypter implements Decrypter {
}
private void init(byte[] salt, byte[] passwordVerifier) throws ZipException {
- AesKeyStrength aesKeyStrength = aesExtraDataRecord.getAesKeyStrength();
-
if (password == null || password.length <= 0) {
- throw new ZipException("empty or null password provided for AES Decryptor");
- }
-
- byte[] derivedKey = deriveKey(salt, password, aesKeyStrength.getKeyLength(), aesKeyStrength.getMacLength());
- if (derivedKey == null || derivedKey.length != (aesKeyStrength.getKeyLength() + aesKeyStrength.getMacLength()
- + PASSWORD_VERIFIER_LENGTH)) {
- throw new ZipException("invalid derived key");
+ throw new ZipException("empty or null password provided for AES decryption");
}
- byte[] aesKey = new byte[aesKeyStrength.getKeyLength()];
- byte[] macKey = new byte[aesKeyStrength.getMacLength()];
- byte[] derivedPasswordVerifier = new byte[PASSWORD_VERIFIER_LENGTH];
-
- System.arraycopy(derivedKey, 0, aesKey, 0, aesKeyStrength.getKeyLength());
- System.arraycopy(derivedKey, aesKeyStrength.getKeyLength(), macKey, 0, aesKeyStrength.getMacLength());
- System.arraycopy(derivedKey, aesKeyStrength.getKeyLength() + aesKeyStrength.getMacLength(), derivedPasswordVerifier,
- 0, PASSWORD_VERIFIER_LENGTH);
-
+ final AesKeyStrength aesKeyStrength = aesExtraDataRecord.getAesKeyStrength();
+ final byte[] derivedKey = AesCipherUtil.derivePasswordBasedKey(salt, password, aesKeyStrength);
+ final byte[] derivedPasswordVerifier = AesCipherUtil.derivePasswordVerifier(derivedKey, aesKeyStrength);
if (!Arrays.equals(passwordVerifier, derivedPasswordVerifier)) {
throw new ZipException("Wrong Password", ZipException.Type.WRONG_PASSWORD);
}
- aesEngine = new AESEngine(aesKey);
- mac = new MacBasedPRF("HmacSHA1");
- mac.init(macKey);
+ aesEngine = AesCipherUtil.getAESEngine(derivedKey, aesKeyStrength);
+ mac = AesCipherUtil.getMacBasedPRF(derivedKey, aesKeyStrength);
}
@Override
@@ -102,12 +86,6 @@ public class AESDecrypter implements Decrypter {
return len;
}
- private byte[] deriveKey(byte[] salt, char[] password, int keyLength, int macLength) {
- PBKDF2Parameters p = new PBKDF2Parameters("HmacSHA1", "ISO-8859-1", salt, 1000);
- PBKDF2Engine e = new PBKDF2Engine(p);
- return e.deriveKey(password, keyLength + macLength + PASSWORD_VERIFIER_LENGTH);
- }
-
public byte[] getCalculatedAuthenticationBytes() {
return mac.doFinal();
}
=====================================
src/main/java/net/lingala/zip4j/crypto/AESEncrpyter.java → src/main/java/net/lingala/zip4j/crypto/AESEncrypter.java
=====================================
@@ -17,8 +17,6 @@
package net.lingala.zip4j.crypto;
import net.lingala.zip4j.crypto.PBKDF2.MacBasedPRF;
-import net.lingala.zip4j.crypto.PBKDF2.PBKDF2Engine;
-import net.lingala.zip4j.crypto.PBKDF2.PBKDF2Parameters;
import net.lingala.zip4j.crypto.engine.AESEngine;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.enums.AesKeyStrength;
@@ -28,9 +26,10 @@ import java.security.SecureRandom;
import static net.lingala.zip4j.crypto.AesCipherUtil.prepareBuffAESIVBytes;
import static net.lingala.zip4j.util.InternalZipConstants.AES_BLOCK_SIZE;
-public class AESEncrpyter implements Encrypter {
-
- private static final int PASSWORD_VERIFIER_LENGTH = 2;
+/**
+ * AES Encrypter supports AE-1 and AE-2 encryption using AES-CTR with either 128 or 256 Key Strength
+ */
+public class AESEncrypter implements Encrypter {
private char[] password;
private AesKeyStrength aesKeyStrength;
@@ -48,7 +47,7 @@ public class AESEncrpyter implements Encrypter {
private byte[] derivedPasswordVerifier;
private byte[] saltBytes;
- public AESEncrpyter(char[] password, AesKeyStrength aesKeyStrength) throws ZipException {
+ public AESEncrypter(char[] password, AesKeyStrength aesKeyStrength) throws ZipException {
if (password == null || password.length == 0) {
throw new ZipException("input password is empty or null");
}
@@ -66,45 +65,16 @@ public class AESEncrpyter implements Encrypter {
}
private void init() throws ZipException {
- int keyLength = aesKeyStrength.getKeyLength();
- int macLength = aesKeyStrength.getMacLength();
- int saltLength = aesKeyStrength.getSaltLength();
-
- saltBytes = generateSalt(saltLength);
- byte[] keyBytes = deriveKey(saltBytes, password, keyLength, macLength);
-
- if (keyBytes == null || keyBytes.length != (keyLength + macLength + PASSWORD_VERIFIER_LENGTH)) {
- throw new ZipException("invalid key generated, cannot decrypt file");
- }
-
- byte[] aesKey = new byte[keyLength];
- byte[] macKey = new byte[macLength];
- derivedPasswordVerifier = new byte[PASSWORD_VERIFIER_LENGTH];
-
- System.arraycopy(keyBytes, 0, aesKey, 0, keyLength);
- System.arraycopy(keyBytes, keyLength, macKey, 0, macLength);
- System.arraycopy(keyBytes, keyLength + macLength, derivedPasswordVerifier, 0, PASSWORD_VERIFIER_LENGTH);
-
- aesEngine = new AESEngine(aesKey);
- mac = new MacBasedPRF("HmacSHA1");
- mac.init(macKey);
- }
-
- private byte[] deriveKey(byte[] salt, char[] password, int keyLength, int macLength) throws ZipException {
- try {
- PBKDF2Parameters p = new PBKDF2Parameters("HmacSHA1", "ISO-8859-1",
- salt, 1000);
- PBKDF2Engine e = new PBKDF2Engine(p);
- return e.deriveKey(password, keyLength + macLength + PASSWORD_VERIFIER_LENGTH);
- } catch (Exception e) {
- throw new ZipException(e);
- }
+ saltBytes = generateSalt(aesKeyStrength.getSaltLength());
+ byte[] derivedKey = AesCipherUtil.derivePasswordBasedKey(saltBytes, password, aesKeyStrength);
+ derivedPasswordVerifier = AesCipherUtil.derivePasswordVerifier(derivedKey, aesKeyStrength);
+ aesEngine = AesCipherUtil.getAESEngine(derivedKey, aesKeyStrength);
+ mac = AesCipherUtil.getMacBasedPRF(derivedKey, aesKeyStrength);
}
public int encryptData(byte[] buff) throws ZipException {
-
if (buff == null) {
- throw new ZipException("input bytes are null, cannot perform AES encrpytion");
+ throw new ZipException("input bytes are null, cannot perform AES encryption");
}
return encryptData(buff, 0, buff.length);
}
=====================================
src/main/java/net/lingala/zip4j/crypto/AesCipherUtil.java
=====================================
@@ -1,6 +1,89 @@
package net.lingala.zip4j.crypto;
+import net.lingala.zip4j.crypto.PBKDF2.MacBasedPRF;
+import net.lingala.zip4j.crypto.PBKDF2.PBKDF2Engine;
+import net.lingala.zip4j.crypto.PBKDF2.PBKDF2Parameters;
+import net.lingala.zip4j.crypto.engine.AESEngine;
+import net.lingala.zip4j.exception.ZipException;
+import net.lingala.zip4j.model.enums.AesKeyStrength;
+
+import static net.lingala.zip4j.util.InternalZipConstants.AES_HASH_CHARSET;
+import static net.lingala.zip4j.util.InternalZipConstants.AES_HASH_ITERATIONS;
+import static net.lingala.zip4j.util.InternalZipConstants.AES_MAC_ALGORITHM;
+import static net.lingala.zip4j.util.InternalZipConstants.AES_PASSWORD_VERIFIER_LENGTH;
+
public class AesCipherUtil {
+ private static final int START_INDEX = 0;
+
+ /**
+ * Derive Password-Based Key for AES according to AE-1 and AE-2 Specifications
+ *
+ * @param salt Salt used for PBKDF2
+ * @param password Password used for PBKDF2 containing characters matching ISO-8859-1 character set
+ * @param aesKeyStrength Requested AES Key and MAC Strength
+ * @return Derived Password-Based Key
+ * @throws ZipException Thrown when Derived Key is not valid
+ */
+ public static byte[] derivePasswordBasedKey(final byte[] salt, final char[] password, final AesKeyStrength aesKeyStrength) throws ZipException {
+ final PBKDF2Parameters parameters = new PBKDF2Parameters(AES_MAC_ALGORITHM, AES_HASH_CHARSET, salt, AES_HASH_ITERATIONS);
+ final PBKDF2Engine engine = new PBKDF2Engine(parameters);
+
+ final int keyLength = aesKeyStrength.getKeyLength();
+ final int macLength = aesKeyStrength.getMacLength();
+ final int derivedKeyLength = keyLength + macLength + AES_PASSWORD_VERIFIER_LENGTH;
+ final byte[] derivedKey = engine.deriveKey(password, derivedKeyLength);
+ if (derivedKey != null && derivedKey.length == derivedKeyLength) {
+ return derivedKey;
+ } else {
+ final String message = String.format("Derived Key invalid for Key Length [%d] MAC Length [%d]", keyLength, macLength);
+ throw new ZipException(message);
+ }
+ }
+
+ /**
+ * Derive Password Verifier using Derived Key and requested AES Key Strength
+ *
+ * @param derivedKey Derived Key
+ * @param aesKeyStrength AES Key Strength
+ * @return Derived Password Verifier
+ */
+ public static byte[] derivePasswordVerifier(final byte[] derivedKey, final AesKeyStrength aesKeyStrength) {
+ byte[] derivedPasswordVerifier = new byte[AES_PASSWORD_VERIFIER_LENGTH];
+ final int keyMacLength = aesKeyStrength.getKeyLength() + aesKeyStrength.getMacLength();
+ System.arraycopy(derivedKey, keyMacLength, derivedPasswordVerifier, START_INDEX, AES_PASSWORD_VERIFIER_LENGTH);
+ return derivedPasswordVerifier;
+ }
+
+ /**
+ * Get MAC-Based PRF using default HMAC Algorithm defined in AE-1 and AE-2 Specification
+ *
+ * @param derivedKey Derived Key
+ * @param aesKeyStrength AES Key Strength
+ * @return Initialized MAC-Based PRF
+ */
+ public static MacBasedPRF getMacBasedPRF(final byte[] derivedKey, final AesKeyStrength aesKeyStrength) {
+ final int macLength = aesKeyStrength.getMacLength();
+ final byte[] macKey = new byte[macLength];
+ System.arraycopy(derivedKey, aesKeyStrength.getKeyLength(), macKey, START_INDEX, macLength);
+ final MacBasedPRF macBasedPRF = new MacBasedPRF(AES_MAC_ALGORITHM);
+ macBasedPRF.init(macKey);
+ return macBasedPRF;
+ }
+
+ /**
+ * Get AES Engine using derived key and requested AES Key Strength
+ *
+ * @param derivedKey Derived Key
+ * @param aesKeyStrength AES Key Strength
+ * @return AES Engine configured with AES Key
+ * @throws ZipException Thrown on AESEngine initialization failures
+ */
+ public static AESEngine getAESEngine(final byte[] derivedKey, final AesKeyStrength aesKeyStrength) throws ZipException {
+ final int keyLength = aesKeyStrength.getKeyLength();
+ final byte[] aesKey = new byte[keyLength];
+ System.arraycopy(derivedKey, START_INDEX, aesKey, START_INDEX, keyLength);
+ return new AESEngine(aesKey);
+ }
public static void prepareBuffAESIVBytes(byte[] buff, int nonce) {
buff[0] = (byte) nonce;
=====================================
src/main/java/net/lingala/zip4j/exception/ZipException.java
=====================================
@@ -56,6 +56,7 @@ public class ZipException extends IOException {
CHECKSUM_MISMATCH,
UNKNOWN_COMPRESSION_METHOD,
FILE_NOT_FOUND,
+ UNSUPPORTED_ENCRYPTION,
UNKNOWN
}
}
=====================================
src/main/java/net/lingala/zip4j/headers/HeaderWriter.java
=====================================
@@ -201,9 +201,11 @@ public class HeaderWriter {
zipModel.getZip64EndOfCentralDirectoryLocator().setTotalNumberOfDiscs(1);
}
- writeZip64EndOfCentralDirectoryRecord(zipModel, sizeOfCentralDir, offsetCentralDir, byteArrayOutputStream,
- rawIO);
- writeZip64EndOfCentralDirectoryLocator(zipModel, byteArrayOutputStream, rawIO);
+ Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = buildZip64EndOfCentralDirectoryRecord(zipModel,
+ sizeOfCentralDir, offsetCentralDir);
+ zipModel.setZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord);
+ writeZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord, byteArrayOutputStream,rawIO);
+ writeZip64EndOfCentralDirectoryLocator(zipModel.getZip64EndOfCentralDirectoryLocator(), byteArrayOutputStream, rawIO);
}
writeEndOfCentralDirectoryRecord(zipModel, sizeOfCentralDir, offsetCentralDir, byteArrayOutputStream, rawIO, charset);
@@ -235,9 +237,11 @@ public class HeaderWriter {
zipModel.getZip64EndOfCentralDirectoryLocator().setOffsetZip64EndOfCentralDirectoryRecord(offsetCentralDir
+ sizeOfCentralDir);
- writeZip64EndOfCentralDirectoryRecord(zipModel, sizeOfCentralDir, offsetCentralDir, byteArrayOutputStream,
- rawIO);
- writeZip64EndOfCentralDirectoryLocator(zipModel, byteArrayOutputStream, rawIO);
+ Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = buildZip64EndOfCentralDirectoryRecord(zipModel,
+ sizeOfCentralDir, offsetCentralDir);
+ zipModel.setZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord);
+ writeZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord, byteArrayOutputStream,rawIO);
+ writeZip64EndOfCentralDirectoryLocator(zipModel.getZip64EndOfCentralDirectoryLocator(), byteArrayOutputStream, rawIO);
}
writeEndOfCentralDirectoryRecord(zipModel, sizeOfCentralDir, offsetCentralDir, byteArrayOutputStream, rawIO, charset);
@@ -550,56 +554,30 @@ public class HeaderWriter {
}
}
- private void writeZip64EndOfCentralDirectoryRecord(ZipModel zipModel, int sizeOfCentralDir, long offsetCentralDir,
- ByteArrayOutputStream byteArrayOutputStream, RawIO rawIO)
- throws IOException {
-
- byte[] emptyShortByte = {0, 0};
-
- rawIO.writeIntLittleEndian(byteArrayOutputStream,
- (int) HeaderSignature.ZIP64_END_CENTRAL_DIRECTORY_RECORD.getValue());
- rawIO.writeLongLittleEndian(byteArrayOutputStream, (long) 44);
-
- if (zipModel.getCentralDirectory() != null &&
- zipModel.getCentralDirectory().getFileHeaders() != null &&
- zipModel.getCentralDirectory().getFileHeaders().size() > 0) {
- rawIO.writeShortLittleEndian(byteArrayOutputStream,
- zipModel.getCentralDirectory().getFileHeaders().get(0).getVersionMadeBy());
-
- rawIO.writeShortLittleEndian(byteArrayOutputStream,
- zipModel.getCentralDirectory().getFileHeaders().get(0).getVersionNeededToExtract());
- } else {
- byteArrayOutputStream.write(emptyShortByte);
- byteArrayOutputStream.write(emptyShortByte);
- }
-
- rawIO.writeIntLittleEndian(byteArrayOutputStream,
- zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
- rawIO.writeIntLittleEndian(byteArrayOutputStream, zipModel.getEndOfCentralDirectoryRecord()
- .getNumberOfThisDiskStartOfCentralDir());
-
- long numEntries = zipModel.getCentralDirectory().getFileHeaders().size();
- long numEntriesOnThisDisk = numEntries;
- if (zipModel.isSplitArchive()) {
- numEntriesOnThisDisk = countNumberOfFileHeaderEntriesOnDisk(zipModel.getCentralDirectory().getFileHeaders(),
- zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
- }
-
- rawIO.writeLongLittleEndian(byteArrayOutputStream, numEntriesOnThisDisk);
- rawIO.writeLongLittleEndian(byteArrayOutputStream, numEntries);
- rawIO.writeLongLittleEndian(byteArrayOutputStream, sizeOfCentralDir);
- rawIO.writeLongLittleEndian(byteArrayOutputStream, offsetCentralDir);
+ private void writeZip64EndOfCentralDirectoryRecord(Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord,
+ ByteArrayOutputStream byteArrayOutputStream, RawIO rawIO) throws IOException {
+ rawIO.writeIntLittleEndian(byteArrayOutputStream, (int) zip64EndOfCentralDirectoryRecord.getSignature().getValue());
+ rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getSizeOfZip64EndCentralDirectoryRecord());
+ rawIO.writeShortLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getVersionMadeBy());
+ rawIO.writeShortLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getVersionNeededToExtract());
+ rawIO.writeIntLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getNumberOfThisDisk());
+ rawIO.writeIntLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getNumberOfThisDiskStartOfCentralDirectory());
+ rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectoryOnThisDisk());
+ rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectory());
+ rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getSizeOfCentralDirectory());
+ rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getOffsetStartCentralDirectoryWRTStartDiskNumber());
}
- private void writeZip64EndOfCentralDirectoryLocator(ZipModel zipModel, ByteArrayOutputStream byteArrayOutputStream,
+ private void writeZip64EndOfCentralDirectoryLocator(Zip64EndOfCentralDirectoryLocator zip64EndOfCentralDirectoryLocator,
+ ByteArrayOutputStream byteArrayOutputStream,
RawIO rawIO) throws IOException {
rawIO.writeIntLittleEndian(byteArrayOutputStream, (int) HeaderSignature.ZIP64_END_CENTRAL_DIRECTORY_LOCATOR.getValue());
rawIO.writeIntLittleEndian(byteArrayOutputStream,
- zipModel.getZip64EndOfCentralDirectoryLocator().getNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord());
+ zip64EndOfCentralDirectoryLocator.getNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord());
rawIO.writeLongLittleEndian(byteArrayOutputStream,
- zipModel.getZip64EndOfCentralDirectoryLocator().getOffsetZip64EndOfCentralDirectoryRecord());
+ zip64EndOfCentralDirectoryLocator.getOffsetZip64EndOfCentralDirectoryRecord());
rawIO.writeIntLittleEndian(byteArrayOutputStream,
- zipModel.getZip64EndOfCentralDirectoryLocator().getTotalNumberOfDiscs());
+ zip64EndOfCentralDirectoryLocator.getTotalNumberOfDiscs());
}
@@ -680,4 +658,39 @@ public class HeaderWriter {
return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
}
+
+ private Zip64EndOfCentralDirectoryRecord buildZip64EndOfCentralDirectoryRecord(ZipModel zipModel, int sizeOfCentralDir,
+ long offsetCentralDir) throws ZipException {
+
+ Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = new Zip64EndOfCentralDirectoryRecord();
+
+ zip64EndOfCentralDirectoryRecord.setSignature(HeaderSignature.ZIP64_END_CENTRAL_DIRECTORY_RECORD);
+ zip64EndOfCentralDirectoryRecord.setSizeOfZip64EndCentralDirectoryRecord(44);
+
+ if (zipModel.getCentralDirectory() != null &&
+ zipModel.getCentralDirectory().getFileHeaders() != null &&
+ zipModel.getCentralDirectory().getFileHeaders().size() > 0) {
+ FileHeader firstFileHeader = zipModel.getCentralDirectory().getFileHeaders().get(0);
+ zip64EndOfCentralDirectoryRecord.setVersionMadeBy(firstFileHeader.getVersionMadeBy());
+ zip64EndOfCentralDirectoryRecord.setVersionNeededToExtract(firstFileHeader.getVersionNeededToExtract());
+ }
+
+ zip64EndOfCentralDirectoryRecord.setNumberOfThisDisk(zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
+ zip64EndOfCentralDirectoryRecord.setNumberOfThisDiskStartOfCentralDirectory(zipModel.getEndOfCentralDirectoryRecord()
+ .getNumberOfThisDiskStartOfCentralDir());
+
+ long numEntries = zipModel.getCentralDirectory().getFileHeaders().size();
+ long numEntriesOnThisDisk = numEntries;
+ if (zipModel.isSplitArchive()) {
+ numEntriesOnThisDisk = countNumberOfFileHeaderEntriesOnDisk(zipModel.getCentralDirectory().getFileHeaders(),
+ zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
+ }
+
+ zip64EndOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(numEntriesOnThisDisk);
+ zip64EndOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectory(numEntries);
+ zip64EndOfCentralDirectoryRecord.setSizeOfCentralDirectory(sizeOfCentralDir);
+ zip64EndOfCentralDirectoryRecord.setOffsetStartCentralDirectoryWRTStartDiskNumber(offsetCentralDir);
+
+ return zip64EndOfCentralDirectoryRecord;
+ }
}
\ No newline at end of file
=====================================
src/main/java/net/lingala/zip4j/io/inputstream/CipherInputStream.java
=====================================
@@ -5,6 +5,7 @@ import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.util.InternalZipConstants;
+import net.lingala.zip4j.util.Zip4jUtil;
import java.io.IOException;
import java.io.InputStream;
@@ -24,7 +25,7 @@ abstract class CipherInputStream<T extends Decrypter> extends InputStream {
this.decrypter = initializeDecrypter(localFileHeader, password);
this.localFileHeader = localFileHeader;
- if (getCompressionMethod(localFileHeader) == CompressionMethod.DEFLATE) {
+ if (Zip4jUtil.getCompressionMethod(localFileHeader).equals(CompressionMethod.DEFLATE)) {
lastReadRawDataCache = new byte[InternalZipConstants.BUFF_SIZE];
}
}
@@ -76,18 +77,6 @@ abstract class CipherInputStream<T extends Decrypter> extends InputStream {
}
}
- private CompressionMethod getCompressionMethod(LocalFileHeader localFileHeader) throws ZipException {
- if (localFileHeader.getCompressionMethod() != CompressionMethod.AES_INTERNAL_ONLY) {
- return localFileHeader.getCompressionMethod();
- }
-
- if (localFileHeader.getAesExtraDataRecord() == null) {
- throw new ZipException("AesExtraDataRecord not present in localheader for aes encrypted data");
- }
-
- return localFileHeader.getAesExtraDataRecord().getCompressionMethod();
- }
-
public T getDecrypter() {
return decrypter;
}
=====================================
src/main/java/net/lingala/zip4j/io/inputstream/ZipInputStream.java
=====================================
@@ -194,8 +194,11 @@ public class ZipInputStream extends InputStream {
if (localFileHeader.getEncryptionMethod() == EncryptionMethod.AES) {
return new AesCipherInputStream(zipEntryInputStream, localFileHeader, password);
- } else {
+ } else if (localFileHeader.getEncryptionMethod() == EncryptionMethod.ZIP_STANDARD) {
return new ZipStandardCipherInputStream(zipEntryInputStream, localFileHeader, password);
+ } else {
+ final String message = String.format("Entry [%s] Strong Encryption not supported", localFileHeader.getFileName());
+ throw new ZipException(message, ZipException.Type.UNSUPPORTED_ENCRYPTION);
}
}
@@ -290,7 +293,7 @@ public class ZipInputStream extends InputStream {
}
if (localFileHeader.getEncryptionMethod().equals(EncryptionMethod.AES)) {
- return InternalZipConstants.AES_AUTH_LENGTH + AESDecrypter.PASSWORD_VERIFIER_LENGTH
+ return InternalZipConstants.AES_AUTH_LENGTH + InternalZipConstants.AES_PASSWORD_VERIFIER_LENGTH
+ localFileHeader.getAesExtraDataRecord().getAesKeyStrength().getSaltLength();
} else if (localFileHeader.getEncryptionMethod().equals(EncryptionMethod.ZIP_STANDARD)) {
return InternalZipConstants.STD_DEC_HDR_SIZE;
=====================================
src/main/java/net/lingala/zip4j/io/outputstream/AesCipherOutputStream.java
=====================================
@@ -1,6 +1,6 @@
package net.lingala.zip4j.io.outputstream;
-import net.lingala.zip4j.crypto.AESEncrpyter;
+import net.lingala.zip4j.crypto.AESEncrypter;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
@@ -9,7 +9,7 @@ import java.io.OutputStream;
import static net.lingala.zip4j.util.InternalZipConstants.AES_BLOCK_SIZE;
-class AesCipherOutputStream extends CipherOutputStream<AESEncrpyter> {
+class AesCipherOutputStream extends CipherOutputStream<AESEncrypter> {
private byte[] pendingBuffer = new byte[AES_BLOCK_SIZE];
private int pendingBufferLength = 0;
@@ -19,13 +19,13 @@ class AesCipherOutputStream extends CipherOutputStream<AESEncrpyter> {
}
@Override
- protected AESEncrpyter initializeEncrypter(OutputStream outputStream, ZipParameters zipParameters, char[] password) throws IOException, ZipException {
- AESEncrpyter encrypter = new AESEncrpyter(password, zipParameters.getAesKeyStrength());
+ protected AESEncrypter initializeEncrypter(OutputStream outputStream, ZipParameters zipParameters, char[] password) throws IOException, ZipException {
+ AESEncrypter encrypter = new AESEncrypter(password, zipParameters.getAesKeyStrength());
writeAesEncryptionHeaderData(encrypter);
return encrypter;
}
- private void writeAesEncryptionHeaderData(AESEncrpyter encrypter) throws IOException {
+ private void writeAesEncryptionHeaderData(AESEncrypter encrypter) throws IOException {
writeHeaders(encrypter.getSaltBytes());
writeHeaders(encrypter.getDerivedPasswordVerifier());
}
=====================================
src/main/java/net/lingala/zip4j/tasks/AbstractAddFileToZipTask.java
=====================================
@@ -107,7 +107,7 @@ public abstract class AbstractAddFileToZipTask<T> extends AsyncZipTask<T> {
zipOutputStream.putNextEntry(zipParameters);
- if (!fileToAdd.isDirectory()) {
+ if (fileToAdd.exists() && !fileToAdd.isDirectory()) {
try (InputStream inputStream = new FileInputStream(fileToAdd)) {
while ((readLen = inputStream.read(readBuff)) != -1) {
zipOutputStream.write(readBuff, 0, readLen);
=====================================
src/main/java/net/lingala/zip4j/tasks/AbstractModifyFileTask.java
=====================================
@@ -12,6 +12,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Random;
@@ -73,7 +74,8 @@ abstract class AbstractModifyFileTask<T> extends AsyncZipTask<T> {
List<FileHeader> cloneAndSortFileHeadersByOffset(List<FileHeader> allFileHeaders) {
List<FileHeader> clonedFileHeaders = new ArrayList<>(allFileHeaders);
- clonedFileHeaders.sort((o1, o2) -> {
+ //noinspection Java8ListSort
+ Collections.sort(clonedFileHeaders, (o1, o2) -> {
if (o1.getFileName().equals(o2.getFileName())) {
return 0;
}
=====================================
src/main/java/net/lingala/zip4j/util/InternalZipConstants.java
=====================================
@@ -32,6 +32,10 @@ public final class InternalZipConstants {
public static final int AES_AUTH_LENGTH = 10;
public static final int AES_BLOCK_SIZE = 16;
public static final int AES_EXTRA_DATA_RECORD_SIZE = 11;
+ public static final String AES_MAC_ALGORITHM = "HmacSHA1";
+ public static final String AES_HASH_CHARSET = "ISO-8859-1";
+ public static final int AES_HASH_ITERATIONS = 1000;
+ public static final int AES_PASSWORD_VERIFIER_LENGTH = 2;
public static final int MIN_SPLIT_LENGTH = 65536;
public static final long ZIP_64_SIZE_LIMIT = 4294967295L;
=====================================
src/test/java/net/lingala/zip4j/ZipFileZip64IT.java
=====================================
@@ -139,13 +139,27 @@ public class ZipFileZip64IT extends AbstractIT {
@Test
public void testZip64WhenAddingFilesWithNewlyInstantiatedZipFile() throws IOException {
+ testZip64WhenAddingMultipleFiles(true);
+ }
+
+ @Test
+ public void testZip64WhenAddingFilesWithAlreadyInstantiatedZipFile() throws IOException {
+ testZip64WhenAddingMultipleFiles(false);
+ }
+
+ private void testZip64WhenAddingMultipleFiles(boolean reinitializeZipFile) throws IOException {
File testFileToAdd = TestUtils.generateFileOfSize(temporaryFolder, 1073741824); // 1 GB
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
+ ZipFile zipFile = new ZipFile(generatedZipFile);
for (int i = 0; i < 6; i++) {
zipParameters.setFileNameInZip(Integer.toString(i));
- new ZipFile(generatedZipFile).addFile(testFileToAdd, zipParameters);
+
+ if (reinitializeZipFile) {
+ zipFile = new ZipFile(generatedZipFile);
+ }
+ zipFile.addFile(testFileToAdd, zipParameters);
}
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 6, false);
=====================================
src/test/java/net/lingala/zip4j/io/inputstream/ZipInputStreamIT.java
=====================================
@@ -2,6 +2,7 @@ package net.lingala.zip4j.io.inputstream;
import net.lingala.zip4j.AbstractIT;
import net.lingala.zip4j.ZipFile;
+import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
@@ -9,7 +10,9 @@ import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.InternalZipConstants;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.FileInputStream;
@@ -27,6 +30,9 @@ import static org.assertj.core.api.Assertions.assertThat;
public class ZipInputStreamIT extends AbstractIT {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
@Test
public void testExtractStoreWithoutEncryption() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.STORE);
@@ -199,6 +205,17 @@ public class ZipInputStreamIT extends AbstractIT {
}
}
+ @Test
+ public void testExtractZipStrongEncryptionThrowsException() throws IOException {
+ expectedException.expect(ZipException.class);
+ expectedException.expectMessage("Entry [test.txt] Strong Encryption not supported");
+
+ File strongEncryptionFile = getTestArchiveFromResources("strong_encrypted.zip");
+ try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(strongEncryptionFile))) {
+ zipInputStream.getNextEntry();
+ }
+ }
+
private void extractZipFileWithInputStreams(File zipFile, char[] password) throws IOException {
extractZipFileWithInputStreams(zipFile, password, 4096, AesVersion.TWO);
}
View it on GitLab: https://salsa.debian.org/java-team/zip4j/-/commit/9e32a231c12d7b9dc85b971a5e4d57253535b520
--
View it on GitLab: https://salsa.debian.org/java-team/zip4j/-/commit/9e32a231c12d7b9dc85b971a5e4d57253535b520
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20201023/8cab29d7/attachment.html>
More information about the pkg-java-commits
mailing list