< prev index next >

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

Print this page

        

@@ -321,11 +321,37 @@
      * @throws ZipException if a ZIP format error has occurred
      * @throws IOException if an I/O error has occurred
      * @throws IllegalStateException if the zip file has been closed
      */
     public InputStream getInputStream(ZipEntry entry) throws IOException {
+        return getInputStream(entry, null);
+    }
+
+    /**
+     * Returns an input stream for reading the contents of the specified
+     * zip file entry.
+     * <p>
+     * Closing this ZIP file will, in turn, close all input streams that
+     * have been returned by invocations of this method.
+     *
+     * @param entry the zip file entry
+     * @param zipCryption instance of ZipCryption
+     * @return the input stream for reading the contents of the specified
+     * zip file entry.
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public InputStream getInputStream(ZipEntry entry, ZipCryption zipCryption)
+                                                            throws IOException {
         Objects.requireNonNull(entry, "entry");
+
+        if ((entry.flag & 1) == 1) {
+            Objects.requireNonNull(entry, "Passphrase is required");
+            zipCryption.reset();
+        }
+
         int pos = -1;
         ZipFileInputStream in = null;
         synchronized (this) {
             ensureOpen();
             if (!zc.isUTF8() && (entry.flag & EFS) != 0) {

@@ -334,13 +360,23 @@
                 pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
             }
             if (pos == -1) {
                 return null;
             }
-            in = new ZipFileInputStream(zsrc.cen, pos);
+            in = new ZipFileInputStream(zsrc.cen, pos, zipCryption);
             switch (CENHOW(zsrc.cen, pos)) {
             case STORED:
+                if((entry.flag & 1) == 1) {
+                   byte[] encryptionHeader =
+                                new byte[zipCryption.getEncryptionHeaderSize()];
+                   in.readRaw(encryptionHeader, 0, encryptionHeader.length);
+                   zipCryption.decryptBytes(encryptionHeader);
+
+                   if (!zipCryption.isValid(entry, encryptionHeader)) {
+                       throw new ZipException("possibly incorrect passphrase");
+                   }
+                }
                 synchronized (streams) {
                     streams.put(in, null);
                 }
                 return in;
             case DEFLATED:

@@ -352,10 +388,22 @@
                 }
                 if (size <= 0) {
                     size = 4096;
                 }
                 Inflater inf = getInflater();
+
+                if((entry.flag & 1) == 1) {
+                   byte[] encryptionHeader =
+                                new byte[zipCryption.getEncryptionHeaderSize()];
+                   in.readRaw(encryptionHeader, 0, encryptionHeader.length);
+                   zipCryption.decryptBytes(encryptionHeader);
+
+                   if (!zipCryption.isValid(entry, encryptionHeader)) {
+                       throw new ZipException("possibly incorrect passphrase");
+                   }
+                }
+
                 InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size);
                 synchronized (streams) {
                     streams.put(is, inf);
                 }
                 return is;

@@ -655,22 +703,25 @@
    private class ZipFileInputStream extends InputStream {
         private volatile boolean closeRequested = false;
         private   long pos;     // current position within entry data
         protected long rem;     // number of remaining bytes within entry
         protected long size;    // uncompressed size of this entry
+        private ZipCryption zipCryption; // ZIP encrypt/decrypt engine
 
-        ZipFileInputStream(byte[] cen, int cenpos) throws IOException {
+        ZipFileInputStream(byte[] cen, int cenpos, ZipCryption zipCryption)
+                                                            throws IOException {
             rem = CENSIZ(cen, cenpos);
             size = CENLEN(cen, cenpos);
             pos = CENOFF(cen, cenpos);
             // zip64
             if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL ||
                 pos == ZIP64_MAGICVAL) {
                 checkZIP64(cen, cenpos);
             }
             // negative for lazy initialization, see getDataOffset();
             pos = - (pos + ZipFile.this.zsrc.locpos);
+            this.zipCryption = zipCryption;
         }
 
         private void checkZIP64(byte[] cen, int cenpos) throws IOException {
             int off = cenpos + CENHDR + CENNAM(cen, cenpos);
             int end = off + CENEXT(cen, cenpos);

@@ -728,10 +779,20 @@
             }
             return pos;
         }
 
         public int read(byte b[], int off, int len) throws IOException {
+            len = readRaw(b, off, len);
+
+            if (zipCryption != null) {
+                zipCryption.decryptBytes(b, off, len);
+            }
+
+            return len;
+        }
+
+        public int readRaw(byte b[], int off, int len) throws IOException {
             synchronized (ZipFile.this) {
                 ensureOpenOrZipException();
                 initDataOffset();
                 if (rem == 0) {
                     return -1;

@@ -1177,12 +1238,10 @@
                     zerror("invalid CEN header (bad signature)");
                 int method = CENHOW(cen, pos);
                 int nlen   = CENNAM(cen, pos);
                 int elen   = CENEXT(cen, pos);
                 int clen   = CENCOM(cen, pos);
-                if ((CENFLG(cen, pos) & 1) != 0)
-                    zerror("invalid CEN header (encrypted entry)");
                 if (method != STORED && method != DEFLATED)
                     zerror("invalid CEN header (bad compression method: " + method + ")");
                 if (pos + CENHDR + nlen > limit)
                     zerror("invalid CEN header (bad header size)");
                 // Record the CEN offset and the name hash in our hash cell.
< prev index next >