[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