Return-Path: X-Original-To: apmail-commons-commits-archive@minotaur.apache.org Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 4B13DD738 for ; Thu, 16 May 2013 19:46:09 +0000 (UTC) Received: (qmail 13876 invoked by uid 500); 16 May 2013 19:46:09 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 13821 invoked by uid 500); 16 May 2013 19:46:09 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 13814 invoked by uid 99); 16 May 2013 19:46:09 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 16 May 2013 19:46:08 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 16 May 2013 19:46:07 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 0793523888E3; Thu, 16 May 2013 19:45:47 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1483531 - in /commons/proper/compress/trunk/src/main/java/org/apache/commons/compress: archivers/sevenz/Coders.java archivers/sevenz/SevenZFile.java utils/CRC32VerifyingInputStream.java Date: Thu, 16 May 2013 19:45:46 -0000 To: commits@commons.apache.org From: damjan@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130516194547.0793523888E3@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: damjan Date: Thu May 16 19:45:46 2013 New Revision: 1483531 URL: http://svn.apache.org/r1483531 Log: Decrypt lazily, on the first read(), otherwise the password strengthening calculations only allow us to traverse 7z archives using getNextEntry() at a rate of about 1 per second with 100% CPU usage. Go back to extending InputStream after all, its semantics are necessary. Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/Coders.java commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/Coders.java URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/Coders.java?rev=1483531&r1=1483530&r2=1483531&view=diff ============================================================================== --- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/Coders.java (original) +++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/Coders.java Thu May 16 19:45:46 2013 @@ -119,73 +119,99 @@ class Coders { static class AES256SHA256Decoder extends CoderBase { @Override InputStream decode(final InputStream in, final Coder coder, - String password) throws IOException { - final int byte0 = 0xff & coder.properties[0]; - final int numCyclesPower = byte0 & 0x3f; - final int byte1 = 0xff & coder.properties[1]; - final int ivSize = ((byte0 >> 6) & 1) + (byte1 & 0x0f); - final int saltSize = ((byte0 >> 7) & 1) + (byte1 >> 4); - //debug("numCyclesPower=" + numCyclesPower + ", saltSize=" + saltSize + ", ivSize=" + ivSize); - if (2 + saltSize + ivSize > coder.properties.length) { - throw new IOException("Salt size + IV size too long"); - } - final byte[] salt = new byte[saltSize]; - System.arraycopy(coder.properties, 2, salt, 0, saltSize); - final byte[] iv = new byte[16]; - System.arraycopy(coder.properties, 2 + saltSize, iv, 0, ivSize); - - if (password == null) { - throw new IOException("Cannot read encrypted files without a password"); - } - final byte[] passwordBytes = password.getBytes("UTF-16LE"); - final byte[] aesKeyBytes; - if (numCyclesPower == 0x3f) { - aesKeyBytes = new byte[32]; - System.arraycopy(salt, 0, aesKeyBytes, 0, saltSize); - System.arraycopy(passwordBytes, 0, aesKeyBytes, saltSize, - Math.min(passwordBytes.length, aesKeyBytes.length - saltSize)); - } else { - final MessageDigest digest; - try { - digest = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException noSuchAlgorithmException) { - IOException ioe = new IOException("SHA-256 is unsupported by your Java implementation"); - ioe.initCause(noSuchAlgorithmException); - throw ioe; -// TODO: simplify when Compress requires Java 1.6 -// throw new IOException("SHA-256 is unsupported by your Java implementation", -// noSuchAlgorithmException); - } - final byte[] extra = new byte[8]; - for (long j = 0; j < (1L << numCyclesPower); j++) { - digest.update(salt); - digest.update(passwordBytes); - digest.update(extra); - for (int k = 0; k < extra.length; k++) { - ++extra[k]; - if (extra[k] != 0) { - break; + final String password) throws IOException { + return new InputStream() { + private boolean isInitialized = false; + private CipherInputStream cipherInputStream = null; + + private CipherInputStream init() throws IOException { + if (isInitialized) { + return cipherInputStream; + } + final int byte0 = 0xff & coder.properties[0]; + final int numCyclesPower = byte0 & 0x3f; + final int byte1 = 0xff & coder.properties[1]; + final int ivSize = ((byte0 >> 6) & 1) + (byte1 & 0x0f); + final int saltSize = ((byte0 >> 7) & 1) + (byte1 >> 4); + //debug("numCyclesPower=" + numCyclesPower + ", saltSize=" + saltSize + ", ivSize=" + ivSize); + if (2 + saltSize + ivSize > coder.properties.length) { + throw new IOException("Salt size + IV size too long"); + } + final byte[] salt = new byte[saltSize]; + System.arraycopy(coder.properties, 2, salt, 0, saltSize); + final byte[] iv = new byte[16]; + System.arraycopy(coder.properties, 2 + saltSize, iv, 0, ivSize); + + if (password == null) { + throw new IOException("Cannot read encrypted files without a password"); + } + final byte[] passwordBytes = password.getBytes("UTF-16LE"); + final byte[] aesKeyBytes; + if (numCyclesPower == 0x3f) { + aesKeyBytes = new byte[32]; + System.arraycopy(salt, 0, aesKeyBytes, 0, saltSize); + System.arraycopy(passwordBytes, 0, aesKeyBytes, saltSize, + Math.min(passwordBytes.length, aesKeyBytes.length - saltSize)); + } else { + final MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException noSuchAlgorithmException) { + IOException ioe = new IOException("SHA-256 is unsupported by your Java implementation"); + ioe.initCause(noSuchAlgorithmException); + throw ioe; + // TODO: simplify when Compress requires Java 1.6 +// throw new IOException("SHA-256 is unsupported by your Java implementation", +// noSuchAlgorithmException); + } + final byte[] extra = new byte[8]; + for (long j = 0; j < (1L << numCyclesPower); j++) { + digest.update(salt); + digest.update(passwordBytes); + digest.update(extra); + for (int k = 0; k < extra.length; k++) { + ++extra[k]; + if (extra[k] != 0) { + break; + } + } } + aesKeyBytes = digest.digest(); } + + final SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES"); + try { + final Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv)); + cipherInputStream = new CipherInputStream(in, cipher); + isInitialized = true; + return cipherInputStream; + } catch (GeneralSecurityException generalSecurityException) { + IOException ioe = new IOException("Decryption error " + + "(do you have the JCE Unlimited Strength Jurisdiction Policy Files installed?)"); + ioe.initCause(generalSecurityException); + throw ioe; + // TODO: simplify when Compress requires Java 1.6 +// throw new IOException("Decryption error " + +// "(do you have the JCE Unlimited Strength Jurisdiction Policy Files installed?)", +// generalSecurityException); + } + } + + @Override + public int read() throws IOException { + return init().read(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return init().read(); + } + + @Override + public void close() { } - aesKeyBytes = digest.digest(); - } - - final SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES"); - try { - Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv)); - return new CipherInputStream(in, cipher); - } catch (GeneralSecurityException generalSecurityException) { - IOException ioe = new IOException("Decryption error " + - "(do you have the JCE Unlimited Strength Jurisdiction Policy Files installed?)"); - ioe.initCause(generalSecurityException); - throw ioe; -// TODO: simplify when Compress requires Java 1.6 -// throw new IOException("Decryption error " + -// "(do you have the JCE Unlimited Strength Jurisdiction Policy Files installed?)", -// generalSecurityException); - } + }; } } } Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java?rev=1483531&r1=1483530&r2=1483531&view=diff ============================================================================== --- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java (original) +++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java Thu May 16 19:45:46 2013 @@ -21,7 +21,6 @@ import java.io.ByteArrayInputStream; import java.io.DataInput; import java.io.DataInputStream; import java.io.File; -import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; @@ -927,11 +926,12 @@ public class SevenZFile { return value; } - private static class BoundedInputStream extends FilterInputStream { + private static class BoundedInputStream extends InputStream { + private final InputStream in; private long bytesRemaining; public BoundedInputStream(final InputStream in, final long size) { - super(in); + this.in = in; bytesRemaining = size; } Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java?rev=1483531&r1=1483530&r2=1483531&view=diff ============================================================================== --- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java (original) +++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java Thu May 16 19:45:46 2013 @@ -17,18 +17,18 @@ */ package org.apache.commons.compress.utils; -import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.CRC32; -public class CRC32VerifyingInputStream extends FilterInputStream { +public class CRC32VerifyingInputStream extends InputStream { + private final InputStream in; private long bytesRemaining; private final int expectedCrc32; private final CRC32 crc32 = new CRC32(); public CRC32VerifyingInputStream(final InputStream in, final long size, final int expectedCrc32) { - super(in); + this.in = in; this.expectedCrc32 = expectedCrc32; this.bytesRemaining = size; }