< prev index next >

src/java.base/share/classes/java/util/zip/ZipInputStream.java

Print this page

        

@@ -57,10 +57,12 @@
     // one entry
     private boolean entryEOF = false;
 
     private ZipCoder zc;
 
+    private ZipCryption zipCryption;
+
     /**
      * Check to make sure that this stream has not been closed
      */
     private void ensureOpen() throws IOException {
         if (closed) {

@@ -111,17 +113,30 @@
      * @return the next ZIP file entry, or null if there are no more entries
      * @exception ZipException if a ZIP file error has occurred
      * @exception IOException if an I/O error has occurred
      */
     public ZipEntry getNextEntry() throws IOException {
+        return getNextEntry(null);
+    }
+
+    /**
+     * Reads the next ZIP file entry and positions the stream at the
+     * beginning of the entry data.
+     * @param zipCryption ZIP encrypt/decrypt engine. zip decryption will not
+     * work if this value set to null.
+     * @return the next ZIP file entry, or null if there are no more entries
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public ZipEntry getNextEntry(ZipCryption zipCryption) throws IOException {
         ensureOpen();
         if (entry != null) {
             closeEntry();
         }
         crc.reset();
         inf.reset();
-        if ((entry = readLOC()) == null) {
+        if ((entry = readLOC(zipCryption)) == null) {
             return null;
         }
         if (entry.method == STORED) {
             remaining = entry.size;
         }

@@ -211,10 +226,13 @@
             }
             len = in.read(b, off, len);
             if (len == -1) {
                 throw new ZipException("unexpected EOF");
             }
+            if (zipCryption != null) {
+                zipCryption.decryptBytes(b, off, len);
+            }
             crc.update(b, off, len);
             remaining -= len;
             if (remaining == 0 && entry.crc != crc.getValue()) {
                 throw new ZipException(
                     "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) +

@@ -271,20 +289,22 @@
     private byte[] b = new byte[256];
 
     /*
      * Reads local file (LOC) header for next entry.
      */
-    private ZipEntry readLOC() throws IOException {
+    private ZipEntry readLOC(ZipCryption zipCryption) throws IOException {
+        this.zipCryption = zipCryption;
+
         try {
             readFully(tmpbuf, 0, LOCHDR);
         } catch (EOFException e) {
             return null;
         }
         if (get32(tmpbuf, 0) != LOCSIG) {
             return null;
         }
-        // get flag first, we need check EFS.
+        // get flag first, we need check EFS and encryption.
         flag = get16(tmpbuf, LOCFLG);
         // get the entry name and create the ZipEntry first
         int len = get16(tmpbuf, LOCNAM);
         int blen = b.length;
         if (len > blen) {

@@ -296,13 +316,14 @@
         readFully(b, 0, len);
         // Force to use UTF-8 if the EFS bit is ON, even the cs is NOT UTF-8
         ZipEntry e = createZipEntry(((flag & EFS) != 0)
                                     ? zc.toStringUTF8(b, len)
                                     : zc.toString(b, len));
+        e.flag = flag;
         // now get the remaining fields for the entry
-        if ((flag & 1) == 1) {
-            throw new ZipException("encrypted ZIP entry not supported");
+        if (((flag & 1) == 1) && (zipCryption == null)) {
+            throw new ZipException("ZipCryption is required.");
         }
         e.method = get16(tmpbuf, LOCHOW);
         e.xdostime = get32(tmpbuf, LOCTIM);
         if ((flag & 8) == 8) {
             /* "Data Descriptor" present */

@@ -320,10 +341,26 @@
             byte[] extra = new byte[len];
             readFully(extra, 0, len);
             e.setExtra0(extra,
                         e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL);
         }
+
+        if (zipCryption != null) {
+            zipCryption.reset();
+            super.setZipCryption(zipCryption);
+
+            byte[] encryptionHeader =
+                          new byte[zipCryption.getEncryptionHeaderSize()];
+            readFully(encryptionHeader, 0, encryptionHeader.length);
+            zipCryption.decryptBytes(encryptionHeader);
+
+            if (!zipCryption.isValid(e, encryptionHeader)) {
+                throw new ZipException("possibly incorrect passphrase");
+            }
+
+        }
+
         return e;
     }
 
     /**
      * Creates a new <code>ZipEntry</code> object for the specified

@@ -353,11 +390,12 @@
      * compatibility."""
      */
     private void readEnd(ZipEntry e) throws IOException {
         int n = inf.getRemaining();
         if (n > 0) {
-            ((PushbackInputStream)in).unread(buf, len - n, n);
+            ((PushbackInputStream)in).unread(
+                           (zipCryption == null) ? buf : originBuf, len - n, n);
         }
         if ((flag & 8) == 8) {
             /* "Data Descriptor" present */
             if (inf.getBytesWritten() > ZIP64_MAGICVAL ||
                 inf.getBytesRead() > ZIP64_MAGICVAL) {

@@ -394,10 +432,13 @@
         if (e.size != inf.getBytesWritten()) {
             throw new ZipException(
                 "invalid entry size (expected " + e.size +
                 " but got " + inf.getBytesWritten() + " bytes)");
         }
+        if (zipCryption != null) {
+            e.csize -= zipCryption.getEncryptionHeaderSize();
+        }
         if (e.csize != inf.getBytesRead()) {
             throw new ZipException(
                 "invalid entry compressed size (expected " + e.csize +
                 " but got " + inf.getBytesRead() + " bytes)");
         }
< prev index next >