This is an automated email from the ASF dual-hosted git repository. vanzin pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-crypto.git
The following commit(s) were added to refs/heads/master by this push: new d8cbe88 JaCoCo Increase for Streams (#99) d8cbe88 is described below commit d8cbe8860d6f23548522e1bf5e8c74d5fd89122e Author: aremily <arem...@users.noreply.github.com> AuthorDate: Wed May 6 20:37:37 2020 -0400 JaCoCo Increase for Streams (#99) --- .../crypto/stream/AbstractCipherStreamTest.java | 399 +++++++++++++++++++-- .../commons/crypto/stream/CtrCryptoStreamTest.java | 134 +++++++ .../stream/PositionedCryptoInputStreamTest.java | 37 +- 3 files changed, 540 insertions(+), 30 deletions(-) diff --git a/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java index 344fc0d..8d585a6 100644 --- a/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java @@ -17,6 +17,8 @@ */ package org.apache.commons.crypto.stream; +import static org.junit.Assert.assertEquals; + import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -27,10 +29,13 @@ import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; +import java.security.Key; import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; import java.util.Properties; import java.util.Random; +import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; @@ -44,9 +49,9 @@ import org.junit.Test; public abstract class AbstractCipherStreamTest { - private final int dataLen = 20000; - private final byte[] data = new byte[dataLen]; - private byte[] encData; + protected final int dataLen = 20000; + protected final byte[] data = new byte[dataLen]; + protected byte[] encData; private final Properties props = new Properties(); protected byte[] key = new byte[16]; protected byte[] iv = new byte[16]; @@ -98,6 +103,26 @@ public abstract class AbstractCipherStreamTest { doByteBufferWrite(AbstractCipherTest.JCE_CIPHER_CLASSNAME, baos, true); doByteBufferWrite(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, baos, true); } + + @Test(timeout = 120000) + public void testExceptions() throws Exception { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + doExceptionTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, baos, false); + doExceptionTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, baos, false); + + doExceptionTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, baos, true); + doExceptionTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, baos, true); + } + + @Test(timeout = 120000) + public void testFieldGetters() throws Exception { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + doFieldGetterTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, baos, false); + doFieldGetterTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, baos, false); + + doFieldGetterTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, baos, true); + doFieldGetterTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, baos, true); + } protected void doSkipTest(final String cipherClass, final boolean withChannel) throws IOException { @@ -110,9 +135,11 @@ public abstract class AbstractCipherStreamTest { new ByteArrayInputStream(encData), getCipher(cipherClass), defaultBufferSize, iv, withChannel)) { final byte[] result = new byte[dataLen]; - final int n1 = readAll(in, result, 0, dataLen / 3); + final int n1 = readAll(in, result, 0, dataLen / 5); - long skipped = in.skip(dataLen / 3); + Assert.assertEquals(in.skip(0), 0); + + long skipped = in.skip(dataLen / 5); final int n2 = readAll(in, result, 0, dataLen); Assert.assertEquals(dataLen, n1 + skipped + n2); @@ -197,46 +224,261 @@ public abstract class AbstractCipherStreamTest { getCipher(cipherClass), smallBufferSize, iv, withChannel); buf.clear(); byteBufferReadCheck(in, buf, 11); + in.close(); + + // Direct buffer, small buffer size, initial buffer position is 0, final read + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), smallBufferSize, iv, withChannel); + buf.clear(); + byteBufferFinalReadCheck(in, buf, 0); + in.close(); + + // Default buffer size, initial buffer position is 0, insufficient dest buffer length + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, withChannel); + buf = ByteBuffer.allocate(100); + byteBufferReadCheck(in, buf, 0); + in.close(); + + // Default buffer size, initial buffer position is 0 + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf = ByteBuffer.allocate(dataLen + 100); + byteBufferReadCheck(in, buf, 0); + in.close(); + + // Default buffer size, initial buffer position is not 0 + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 11); + in.close(); + + // Small buffer size, initial buffer position is 0 + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 0); + in.close(); + + // Small buffer size, initial buffer position is not 0 + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 11); + in.close(); + + // Direct buffer, default buffer size, initial buffer position is 0 + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf = ByteBuffer.allocateDirect(dataLen + 100); + byteBufferReadCheck(in, buf, 0); + in.close(); + + // Direct buffer, default buffer size, initial buffer position is not 0 + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 11); + in.close(); + + // Direct buffer, small buffer size, initial buffer position is 0 + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 0); + in.close(); + + // Direct buffer, small buffer size, initial buffer position is not 0 + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 11); + in.close(); + + // Direct buffer, default buffer size, initial buffer position is 0, final read + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf.clear(); + byteBufferFinalReadCheck(in, buf, 0); + in.close(); + + // Default buffer size, initial buffer position is 0, insufficient dest buffer length + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), key, + new IvParameterSpec(iv), withChannel); + buf = ByteBuffer.allocate(100); + byteBufferReadCheck(in, buf, 0); in.close(); } protected void doByteBufferWrite(final String cipherClass, - final ByteArrayOutputStream baos, final boolean withChannel) throws Exception { + final ByteArrayOutputStream baos, final boolean withChannel) + throws Exception { if (AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME.equals(cipherClass)) { if (!Crypto.isNativeCodeLoaded()) { return; // Skip this test if no JNI } } baos.reset(); - final CryptoOutputStream out = getCryptoOutputStream(baos, + CryptoOutputStream out = getCryptoOutputStream(baos, getCipher(cipherClass), defaultBufferSize, iv, withChannel); - ByteBuffer buf = ByteBuffer.allocateDirect(dataLen / 2); - buf.put(data, 0, dataLen / 2); - buf.flip(); - final int n1 = out.write(buf); - - buf.clear(); - buf.put(data, n1, dataLen / 3); - buf.flip(); - final int n2 = out.write(buf); - - buf.clear(); - buf.put(data, n1 + n2, dataLen - n1 - n2); - buf.flip(); - final int n3 = out.write(buf); - - Assert.assertEquals(dataLen, n1 + n2 + n3); + doByteBufferWrite(out, withChannel); + + baos.reset(); + CryptoCipher cipher = getCipher(cipherClass); + String transformation = cipher.getAlgorithm(); + out = getCryptoOutputStream(transformation, props, baos, key, + new IvParameterSpec(iv), withChannel); + doByteBufferWrite(out, withChannel); + out.write(1); + Assert.assertTrue(out.isOpen()); + + out = getCryptoOutputStream(transformation, props, baos, key, + new IvParameterSpec(iv), withChannel); + out.close(); + Assert.assertTrue(!out.isOpen()); + } - out.flush(); + protected void doExceptionTest(final String cipherClass, ByteArrayOutputStream baos, + final boolean withChannel) throws IOException { + if (AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME.equals(cipherClass)) { + if (!Crypto.isNativeCodeLoaded()) { + return; // Skip this test if no JNI + } + } + + InputStream in = null; + OutputStream out = null; + + // Test InvalidAlgorithmParameters + try { + in = getCryptoInputStream(transformation, props, new ByteArrayInputStream(encData), + new SecretKeySpec(key, "AES"), new GCMParameterSpec(0, new byte[0]), + withChannel); + Assert.fail("Expected IOException."); + } catch (IOException ex) { + Assert.assertEquals(ex.getMessage(),"Illegal parameters"); + } + + // Test InvalidAlgorithmParameters + try { + out = getCryptoOutputStream(transformation, props, baos, + new SecretKeySpec(key, "AES"), new GCMParameterSpec(0, + new byte[0]), withChannel); + Assert.fail("Expected IOException."); + } catch (IOException ex) { + Assert.assertEquals(ex.getMessage(),"Illegal parameters"); + } + + // Test Invalid Key + try { + in = getCryptoInputStream(transformation,props, new ByteArrayInputStream(encData), + new SecretKeySpec(new byte[10], "AES"), new IvParameterSpec(iv), withChannel); + Assert.fail("Expected IOException for Invalid Key"); + } catch (IOException ex) { + Assert.assertNotNull(ex); + } + + // Test Invalid Key + try { + out = getCryptoOutputStream(transformation, props, baos, new byte[10], + new IvParameterSpec(iv), withChannel); + Assert.fail("Expected IOException for Invalid Key"); + } catch (IOException ex) { + Assert.assertNotNull(ex); + } + + // Test reading a closed stream. + try { + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, withChannel); + in.close(); + in.read(); // Throw exception. + } catch (IOException ex) { + Assert.assertTrue(ex.getMessage().equals("Stream closed")); + } + + // Test closing a closed stream. + try { + in.close(); // Don't throw exception on double-close. + } catch (IOException ex) { + Assert.fail("Should not throw exception closing a closed stream."); + } + + // Test checking a closed stream. + try { + out = getCryptoOutputStream(transformation, props, baos, key, new IvParameterSpec(iv), + withChannel); + out.close(); + ((CryptoOutputStream)out).checkStream(); // Throw exception. + } catch (IOException ex) { + Assert.assertTrue(ex.getMessage().equals("Stream closed")); + } + + // Test closing a closed stream. + try { + out.close(); // Don't throw exception. + } catch (IOException ex) { + Assert.fail("Should not throw exception closing a closed stream."); + } + + // Test checkStreamCipher + try { + CryptoInputStream.checkStreamCipher(getCipher(cipherClass)); + } catch (IOException ex) { + Assert.assertTrue(ex.getMessage().equals("AES/CTR/NoPadding is required")); + } finally { + in.close(); + } - try (InputStream in = getCryptoInputStream( - new ByteArrayInputStream(encData), getCipher(cipherClass), - defaultBufferSize, iv, withChannel)) { - buf = ByteBuffer.allocate(dataLen + 100); - byteBufferReadCheck(in, buf, 0); + // Test unsupported operation handling. + try { + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, false); + in.mark(0); + assertEquals(false, in.markSupported()); + in.reset(); + Assert.fail("Expected IOException."); + } catch (IOException ex) { + Assert.assertTrue(ex.getMessage().equals("Mark/reset not supported")); + } finally { + in.close(); } } + protected void doFieldGetterTest(final String cipherClass, ByteArrayOutputStream baos, + final boolean withChannel) throws Exception { + if (AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME.equals(cipherClass)) { + if (!Crypto.isNativeCodeLoaded()) { + return; // Skip this test if no JNI + } + } + + CryptoCipher cipher = getCipher(cipherClass); + + CryptoInputStream in = getCryptoInputStream( + new ByteArrayInputStream(encData), cipher, defaultBufferSize, + iv, withChannel); + + Properties props = new Properties(); + String bufferSize = Integer.toString(defaultBufferSize / 2); + props.put(CryptoInputStream.STREAM_BUFFER_SIZE_KEY, bufferSize); + + Assert.assertEquals(CryptoInputStream.getBufferSize(props), Integer.parseInt(bufferSize)); + Assert.assertEquals(in.getBufferSize(), defaultBufferSize); + Assert.assertEquals(in.getCipher().getClass(), Class.forName(cipherClass)); + Assert.assertEquals(in.getKey().getAlgorithm(), "AES"); + Assert.assertEquals(in.getParams().getClass(), IvParameterSpec.class); + Assert.assertNotNull(in.getInput()); + + CryptoOutputStream out = getCryptoOutputStream(baos, getCipher(cipherClass), + defaultBufferSize, iv, withChannel); + + Assert.assertEquals(out.getOutBuffer().capacity(), defaultBufferSize + cipher.getBlockSize()); + Assert.assertEquals(out.getInBuffer().capacity(), defaultBufferSize); + Assert.assertEquals(out.getBufferSize(), defaultBufferSize); + } + private void byteBufferReadCheck(final InputStream in, final ByteBuffer buf, final int bufPos) throws Exception { buf.position(bufPos); @@ -249,6 +491,30 @@ public abstract class AbstractCipherStreamTest { final byte[] expectedData = new byte[n]; System.arraycopy(data, 0, expectedData, 0, n); Assert.assertArrayEquals(readData, expectedData); + + try { + in.read(readData, -1, 0); + Assert.fail("Expected IndexOutOfBoundsException."); + } catch (IndexOutOfBoundsException ex) { + Assert.assertNotNull(ex); + } + } + + private void byteBufferFinalReadCheck(final InputStream in, final ByteBuffer buf, final int bufPos) + throws Exception { + buf.position(bufPos); + int len = 0; + int n = 0; + do { + n = ((ReadableByteChannel) in).read(buf); + len += n; + } while (n > 0); + buf.rewind(); + byte[] readData = new byte[len + 1]; + buf.get(readData); + final byte[] expectedData = new byte[len + 1]; + System.arraycopy(data, 0, expectedData, 0, len + 1); + Assert.assertArrayEquals(readData, expectedData); } private void prepareData() throws IOException { @@ -270,6 +536,43 @@ public abstract class AbstractCipherStreamTest { } encData = baos.toByteArray(); } + + private void doByteBufferWrite(CryptoOutputStream out, boolean withChannel) throws Exception { + ByteBuffer buf = ByteBuffer.allocateDirect(dataLen / 2); + buf.put(data, 0, dataLen / 2); + buf.flip(); + final int n1 = out.write(buf); + + buf.clear(); + buf.put(data, n1, dataLen / 3); + buf.flip(); + final int n2 = out.write(buf); + + buf.clear(); + buf.put(data, n1 + n2, dataLen - n1 - n2 - 1); + buf.flip(); + final int n3 = out.write(buf); + + out.write(1); + + Assert.assertEquals(dataLen, n1 + n2 + n3 + 1); + + try { + out.write(data, 0, data.length + 1); + Assert.fail("Expected IndexOutOfBoundsException."); + } catch (IndexOutOfBoundsException ex) { + Assert.assertNotNull(ex); + } + + out.flush(); + + try (InputStream in = getCryptoInputStream( + new ByteArrayInputStream(encData), out.getCipher(), + defaultBufferSize, iv, withChannel)) { + buf = ByteBuffer.allocate(dataLen + 100); + byteBufferReadCheck(in, buf, 0); + } + } protected CryptoInputStream getCryptoInputStream(final ByteArrayInputStream bais, final CryptoCipher cipher, final int bufferSize, final byte[] iv, final boolean withChannel) @@ -282,6 +585,24 @@ public abstract class AbstractCipherStreamTest { return new CryptoInputStream(bais, cipher, bufferSize, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); } + + protected CryptoInputStream getCryptoInputStream(final String transformation, final Properties props, + final ByteArrayInputStream bais, final byte[] key, final AlgorithmParameterSpec params, + boolean withChannel) throws IOException { + if (withChannel) { + return new CryptoInputStream(transformation, props, Channels.newChannel(bais), new SecretKeySpec(key, "AES"), params); + } + return new CryptoInputStream(transformation, props, bais, new SecretKeySpec(key, "AES"), params); + } + + protected CryptoInputStream getCryptoInputStream(final String transformation, + final Properties props, final ByteArrayInputStream bais, final Key key, + final AlgorithmParameterSpec params, boolean withChannel) throws IOException { + if (withChannel) { + return new CryptoInputStream(transformation, props, Channels.newChannel(bais), key, params); + } + return new CryptoInputStream(transformation, props, bais, key, params); + } protected CryptoOutputStream getCryptoOutputStream( final ByteArrayOutputStream baos, final CryptoCipher cipher, final int bufferSize, @@ -294,6 +615,26 @@ public abstract class AbstractCipherStreamTest { return new CryptoOutputStream(baos, cipher, bufferSize, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); } + + protected CryptoOutputStream getCryptoOutputStream(final String transformation, + final Properties props, final ByteArrayOutputStream baos, final byte[] key, + final AlgorithmParameterSpec param, final boolean withChannel) throws IOException { + if (withChannel) { + return new CryptoOutputStream(transformation, props, Channels.newChannel(baos), + new SecretKeySpec(key, "AES"), param); + } + return new CryptoOutputStream(transformation, props, baos, new SecretKeySpec(key, "AES"), + param); + } + + protected CryptoOutputStream getCryptoOutputStream(final String transformation, + final Properties props, final ByteArrayOutputStream baos, final Key key, + final AlgorithmParameterSpec params, boolean withChannel) throws IOException { + if (withChannel) { + return new CryptoOutputStream(transformation, props, Channels.newChannel(baos), key, params); + } + return new CryptoOutputStream(transformation, props, baos, key, params); + } private int readAll(final InputStream in, final byte[] b, final int offset, final int len) throws IOException { diff --git a/src/test/java/org/apache/commons/crypto/stream/CtrCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CtrCryptoStreamTest.java index a2ee57d..22e16e9 100644 --- a/src/test/java/org/apache/commons/crypto/stream/CtrCryptoStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/stream/CtrCryptoStreamTest.java @@ -20,9 +20,21 @@ package org.apache.commons.crypto.stream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.channels.Channels; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Properties; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; +import org.apache.commons.crypto.Crypto; +import org.apache.commons.crypto.cipher.AbstractCipherTest; import org.apache.commons.crypto.cipher.CryptoCipher; +import org.apache.commons.crypto.stream.input.ChannelInput; +import org.apache.commons.crypto.stream.input.StreamInput; +import org.apache.commons.crypto.stream.output.ChannelOutput; +import org.junit.Assert; +import org.junit.Test; public class CtrCryptoStreamTest extends AbstractCipherStreamTest { @@ -41,6 +53,17 @@ public class CtrCryptoStreamTest extends AbstractCipherStreamTest { } return new CtrCryptoInputStream(bais, cipher, bufferSize, key, iv); } + + @Override + protected CtrCryptoInputStream getCryptoInputStream(final String transformation, final Properties props, + final ByteArrayInputStream bais, final byte[] key, final AlgorithmParameterSpec params, + boolean withChannel) throws IOException { + if (withChannel) { + return new CtrCryptoInputStream(props, Channels.newChannel(bais), key, + ((IvParameterSpec)params).getIV()); + } + return new CtrCryptoInputStream(props, bais, key, ((IvParameterSpec)params).getIV()); + } @Override protected CtrCryptoOutputStream getCryptoOutputStream( @@ -52,4 +75,115 @@ public class CtrCryptoStreamTest extends AbstractCipherStreamTest { } return new CtrCryptoOutputStream(baos, cipher, bufferSize, key, iv); } + + @Override + protected CtrCryptoOutputStream getCryptoOutputStream(final String transformation, + final Properties props, final ByteArrayOutputStream baos, final byte[] key, + final AlgorithmParameterSpec params, final boolean withChannel) throws IOException { + if (withChannel) { + return new CtrCryptoOutputStream(props, Channels.newChannel(baos), key, + ((IvParameterSpec)params).getIV()); + } + return new CtrCryptoOutputStream(props, baos, key, ((IvParameterSpec)params).getIV()); + } + + @Override + protected void doFieldGetterTest(final String cipherClass, final ByteArrayOutputStream baos, + final boolean withChannel) throws Exception { + if (AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME.equals(cipherClass)) { + if (!Crypto.isNativeCodeLoaded()) { + return; // Skip this test if no JNI + } + } + + StreamInput streamInput = new StreamInput(new ByteArrayInputStream(encData), 0); + try { + streamInput.seek(0); + Assert.fail("Expected UnsupportedOperationException."); + } catch (UnsupportedOperationException ex) { + Assert.assertEquals(ex.getMessage(), "Seek is not supported by this implementation"); + } + try { + streamInput.read(0, new byte[0], 0, 0); + Assert.fail("Expected UnsupportedOperationException."); + } catch (UnsupportedOperationException ex) { + Assert.assertEquals(ex.getMessage(), "Positioned read is not supported by this implementation"); + } + Assert.assertEquals(streamInput.available(), encData.length); + + ChannelInput channelInput = new ChannelInput(Channels.newChannel(new ByteArrayInputStream(encData))); + try { + channelInput.seek(0); + Assert.fail("Expected UnsupportedOperationException."); + } catch (UnsupportedOperationException ex) { + Assert.assertEquals(ex.getMessage(), "Seek is not supported by this implementation"); + } + try { + channelInput.read(0, new byte[0], 0, 0); + Assert.fail("Expected UnsupportedOperationException."); + } catch (UnsupportedOperationException ex) { + Assert.assertEquals(ex.getMessage(), "Positioned read is not supported by this implementation"); + } + Assert.assertEquals(channelInput.available(), 0); + + CtrCryptoInputStream in = new CtrCryptoInputStream(channelInput, getCipher(cipherClass), + defaultBufferSize, key, iv); + + Properties props = new Properties(); + String bufferSize = "4096"; + props.put(CryptoInputStream.STREAM_BUFFER_SIZE_KEY, bufferSize); + in.setStreamOffset(smallBufferSize); + + Assert.assertEquals(CryptoInputStream.getBufferSize(props), Integer.parseInt(bufferSize)); + Assert.assertEquals(smallBufferSize, in.getStreamOffset()); + Assert.assertEquals(in.getBufferSize(), 8192); + Assert.assertEquals(in.getCipher().getClass(), Class.forName(cipherClass)); + Assert.assertEquals(in.getKey().getAlgorithm(), "AES"); + Assert.assertEquals(in.getParams().getClass(), IvParameterSpec.class); + Assert.assertNotNull(in.getInput()); + + in.close(); + + CtrCryptoOutputStream out = new CtrCryptoOutputStream(new ChannelOutput( + Channels.newChannel(baos)), getCipher(cipherClass), + Integer.parseInt(bufferSize), key, iv); + out.setStreamOffset(smallBufferSize); + Assert.assertEquals(out.getStreamOffset(), smallBufferSize); + + out.close(); + } + + @Test(timeout = 120000) + public void testDecrypt() throws Exception { + doDecryptTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, false); + doDecryptTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, false); + + doDecryptTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, true); + doDecryptTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, true); + } + + protected void doDecryptTest(final String cipherClass, final boolean withChannel) + throws IOException { + + CtrCryptoInputStream in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, withChannel); + + ByteBuffer buf = ByteBuffer.allocateDirect(dataLen); + buf.put(encData); + buf.rewind(); + in.decrypt(buf, 0, dataLen); + byte[] readData = new byte[dataLen]; + byte[] expectedData = new byte[dataLen]; + buf.get(readData); + System.arraycopy(data, 0, expectedData, 0, dataLen); + Assert.assertArrayEquals(readData, expectedData); + + try { + in.decryptBuffer(buf); + Assert.fail("Expected IOException."); + } catch (IOException ex) { + Assert.assertEquals(ex.getCause().getClass(), ShortBufferException.class); + } + + } } diff --git a/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java index 52b9d2e..6293720 100644 --- a/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java @@ -93,6 +93,12 @@ public class PositionedCryptoInputStreamTest { Arrays.copyOf(encData, encData.length)), cipher, bufferSize, key, iv, 0); } + + private PositionedCryptoInputStream getCryptoInputStream(final int streamOffset) + throws IOException { + return new PositionedCryptoInputStream(props, new PositionedInputForTest( + Arrays.copyOf(encData, encData.length)), key, iv, streamOffset); + } @Test public void doTestJCE() throws Exception { @@ -107,9 +113,13 @@ public class PositionedCryptoInputStreamTest { protected void testCipher(final String cipherClass) throws Exception { doPositionedReadTests(cipherClass); + doPositionedReadTests(); doReadFullyTests(cipherClass); + doReadFullyTests(); doSeekTests(cipherClass); + doSeekTests(); doMultipleReadTest(cipherClass); + doMultipleReadTest(); } // when there are multiple positioned read actions and one read action, @@ -144,6 +154,12 @@ public class PositionedCryptoInputStreamTest { } } } + + private void doMultipleReadTest() throws Exception{ + PositionedCryptoInputStream in = getCryptoInputStream(0); + final String cipherClass = in.getCipher().getClass().getName(); + doMultipleReadTest(cipherClass); + } private void doPositionedReadTests(final String cipherClass) throws Exception { // test with different bufferSize when position = 0 @@ -161,6 +177,12 @@ public class PositionedCryptoInputStreamTest { testPositionedReadNone(cipherClass, -1, length, bufferSize); testPositionedReadNone(cipherClass, dataLen, length, bufferSize); } + + private void doPositionedReadTests() throws Exception { + PositionedCryptoInputStream in = getCryptoInputStream(0); + final String cipherClass = in.getCipher().getClass().getName(); + doPositionedReadTests(cipherClass); + } private void doReadFullyTests(final String cipherClass) throws Exception { // test with different bufferSize when position = 0 @@ -177,6 +199,12 @@ public class PositionedCryptoInputStreamTest { testReadFullyFailed(cipherClass, dataLen - length + 1, length, bufferSize); } + + private void doReadFullyTests() throws Exception { + PositionedCryptoInputStream in = getCryptoInputStream(0); + final String cipherClass = in.getCipher().getClass().getName(); + doReadFullyTests(cipherClass); + } private void doSeekTests(final String cipherClass) throws Exception { // test with different length when position = 0 @@ -188,6 +216,12 @@ public class PositionedCryptoInputStreamTest { // test exception when position = -1 testSeekFailed(cipherClass, -1, bufferSize); } + + private void doSeekTests() throws Exception{ + PositionedCryptoInputStream in = getCryptoInputStream(0); + final String cipherClass = in.getCipher().getClass().getName(); + doSeekTests(cipherClass); + } private void testSeekLoop(final String cipherClass, int position, final int length, final int bufferSize) throws Exception { @@ -254,7 +288,7 @@ public class PositionedCryptoInputStreamTest { // do the position read full until remain < length while (position + length <= total) { final byte[] bytes = new byte[length]; - in.readFully(position, bytes, 0, length); + in.readFully(position, bytes); compareByteArray(testData, position, bytes, length); position += length; } @@ -275,6 +309,7 @@ public class PositionedCryptoInputStreamTest { // excepted exception } in.close(); + in.close(); // Don't throw exception. } // compare the data from pos with length and data2 from 0 with length