Fix issue #410: DecryptingPartInputStream could return more data than requested, causing segfaults in BitmapFactory on Android 4.4.

This commit is contained in:
Simeon Morgan 2013-11-12 12:57:47 +11:00
parent f9c7687ce2
commit 546dd5485c

View File

@ -24,6 +24,7 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.util.Arrays;
import java.lang.System;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
@ -53,6 +54,7 @@ public class DecryptingPartInputStream extends FileInputStream {
private boolean done; private boolean done;
private long totalDataSize; private long totalDataSize;
private long totalRead; private long totalRead;
private byte[] overflowBuffer;
public DecryptingPartInputStream(File file, MasterSecret masterSecret) throws FileNotFoundException { public DecryptingPartInputStream(File file, MasterSecret masterSecret) throws FileNotFoundException {
super(file); super(file);
@ -122,6 +124,26 @@ public class DecryptingPartInputStream extends FileInputStream {
} }
private int readIncremental(byte[] buffer, int offset, int length) throws IOException { private int readIncremental(byte[] buffer, int offset, int length) throws IOException {
int readLength = 0;
//Use data from overflow buffer first if present
if (null != overflowBuffer) {
if (overflowBuffer.length > length) {
System.arraycopy(overflowBuffer, 0, buffer, offset, length);
overflowBuffer = Arrays.copyOfRange(overflowBuffer, length, overflowBuffer.length);
return length;
} else if (overflowBuffer.length == length) {
System.arraycopy(overflowBuffer, 0, buffer, offset, length);
overflowBuffer = null;
return length;
} else {
System.arraycopy(overflowBuffer, 0, buffer, offset, overflowBuffer.length);
readLength += overflowBuffer.length;
offset += readLength;
length -= readLength;
overflowBuffer = null;
}
}
if (length + totalRead > totalDataSize) if (length + totalRead > totalDataSize)
length = (int)(totalDataSize - totalRead); length = (int)(totalDataSize - totalRead);
@ -131,7 +153,20 @@ public class DecryptingPartInputStream extends FileInputStream {
try { try {
mac.update(internalBuffer, 0, read); mac.update(internalBuffer, 0, read);
return cipher.update(internalBuffer, 0, read, buffer, offset);
//data retrieved using cipher.update doesn't always match cipher.getOutputSize (but should never be larger)
int outputLen = cipher.getOutputSize(read);
byte[] transientBuffer = new byte[outputLen];
outputLen = cipher.update(internalBuffer, 0, read, transientBuffer, 0);
if (outputLen <= length) {
System.arraycopy(transientBuffer, 0, buffer, offset, outputLen);
readLength += outputLen;
} else {
System.arraycopy(transientBuffer, 0, buffer, offset, length);
overflowBuffer = Arrays.copyOfRange(transientBuffer, length, outputLen);
readLength += length;
}
return readLength;
} catch (ShortBufferException e) { } catch (ShortBufferException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }