--- old/src/java.base/share/classes/java/util/zip/ZipFile.java 2015-12-16 21:59:35.263225444 +0900 +++ new/src/java.base/share/classes/java/util/zip/ZipFile.java 2015-12-16 21:59:35.053226065 +0900 @@ -323,7 +323,33 @@ * @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. + *

+ * 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) { @@ -336,9 +362,19 @@ 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); } @@ -354,6 +390,18 @@ 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); @@ -657,8 +705,10 @@ 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); @@ -669,6 +719,7 @@ } // negative for lazy initialization, see getDataOffset(); pos = - (pos + ZipFile.this.zsrc.locpos); + this.zipCryption = zipCryption; } private void checkZIP64(byte[] cen, int cenpos) throws IOException { @@ -730,6 +781,16 @@ } 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(); @@ -1179,8 +1240,6 @@ 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)