You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by da...@apache.org on 2013/05/16 21:45:46 UTC
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
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;
}