--- old/src/java.base/share/classes/java/util/zip/ZipInputStream.java 2015-12-16 21:59:35.958223390 +0900 +++ new/src/java.base/share/classes/java/util/zip/ZipInputStream.java 2015-12-16 21:59:35.710224123 +0900 @@ -59,6 +59,8 @@ private ZipCoder zc; + private ZipCryption zipCryption; + /** * Check to make sure that this stream has not been closed */ @@ -113,13 +115,25 @@ * @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 instance of ZipCryption + * @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) { @@ -213,6 +227,9 @@ 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()) { @@ -273,7 +290,9 @@ /* * 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) { @@ -282,7 +301,7 @@ 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); @@ -298,9 +317,10 @@ 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); @@ -322,6 +342,22 @@ 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; } @@ -355,7 +391,8 @@ 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 */ @@ -396,6 +433,9 @@ "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 +