You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by di...@apache.org on 2016/04/26 05:38:48 UTC

[2/3] commons-crypto git commit: CRYPTO-12: Rename CryptoInputStream to CipherInputStream and CryptoOutputStream to CipherOutputStream (Xianda Ke via Dian Fu)

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java b/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java
deleted file mode 100644
index 3d3ac8d..0000000
--- a/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.crypto.stream;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.WritableByteChannel;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.util.Properties;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.ShortBufferException;
-
-import org.apache.commons.crypto.cipher.Cipher;
-import org.apache.commons.crypto.cipher.CipherTransformation;
-import org.apache.commons.crypto.stream.output.ChannelOutput;
-import org.apache.commons.crypto.stream.output.Output;
-import org.apache.commons.crypto.stream.output.StreamOutput;
-import org.apache.commons.crypto.utils.Utils;
-
-/**
- * CryptoOutputStream encrypts data and writes to the under layer output. It supports
- * any mode of operations such as AES CBC/CTR/GCM mode in concept. It is not thread-safe.
- */
-
-public class CryptoOutputStream extends OutputStream implements
-    WritableByteChannel {
-  private final byte[] oneByteBuf = new byte[1];
-
-  protected Output output;
-  protected final Cipher cipher;
-  protected final int bufferSize;
-
-  protected final byte[] key;
-  protected final byte[] initIV;
-  protected byte[] iv;
-
-  protected boolean closed;
-
-  /**
-   * Input data buffer. The data starts at inBuffer.position() and ends at
-   * inBuffer.limit().
-   */
-  protected ByteBuffer inBuffer;
-
-  /**
-   * Encrypted data buffer. The data starts at outBuffer.position() and ends at
-   * outBuffer.limit();
-   */
-  protected ByteBuffer outBuffer;
-
-  public CryptoOutputStream(CipherTransformation transformation,
-      Properties props, OutputStream out, byte[] key, byte[] iv)
-      throws IOException {
-    this(out, Utils.getCipherInstance(transformation, props),
-        Utils.getBufferSize(props), key, iv);
-  }
-
-  public CryptoOutputStream(CipherTransformation transformation,
-      Properties props, WritableByteChannel out, byte[] key, byte[] iv)
-      throws IOException {
-    this(out, Utils.getCipherInstance(transformation, props),
-        Utils.getBufferSize(props), key, iv);
-  }
-
-  public CryptoOutputStream(OutputStream out, Cipher cipher,
-      int bufferSize, byte[] key, byte[] iv) throws IOException {
-    this(new StreamOutput(out, bufferSize), cipher, bufferSize, key, iv);
-  }
-
-  public CryptoOutputStream(WritableByteChannel channel, Cipher cipher,
-      int bufferSize, byte[] key, byte[] iv) throws IOException {
-    this(new ChannelOutput(channel), cipher, bufferSize, key, iv);
-  }
-
-  protected CryptoOutputStream(Output output, Cipher cipher,
-      int bufferSize, byte[] key, byte[] iv)
-      throws IOException {
-
-    this.output = output;
-    this.bufferSize = Utils.checkBufferSize(cipher, bufferSize);
-    this.cipher = cipher;
-    this.key = key.clone();
-    this.initIV = iv.clone();
-    this.iv = iv.clone();
-    inBuffer = ByteBuffer.allocateDirect(this.bufferSize);
-    outBuffer = ByteBuffer.allocateDirect(this.bufferSize +
-        cipher.getTransformation().getAlgorithmBlockSize());
-
-    initCipher();
-  }
-
-  @Override
-  public void write(int b) throws IOException {
-    oneByteBuf[0] = (byte)(b & 0xff);
-    write(oneByteBuf, 0, oneByteBuf.length);
-  }
-
-  /**
-   * Encryption is buffer based.
-   * If there is enough room in {@link #inBuffer}, then write to this buffer.
-   * If {@link #inBuffer} is full, then do encryption and write data to the
-   * underlying stream.
-   * @param b the data.
-   * @param off the start offset in the data.
-   * @param len the number of bytes to write.
-   * @throws IOException
-   */
-  public void write(byte[] b, int off, int len) throws IOException {
-    checkStream();
-    if (b == null) {
-      throw new NullPointerException();
-    } else if (off < 0 || len < 0 || off > b.length ||
-        len > b.length - off) {
-      throw new IndexOutOfBoundsException();
-    }
-
-    while (len > 0) {
-      final int remaining = inBuffer.remaining();
-      if (len < remaining) {
-        inBuffer.put(b, off, len);
-        len = 0;
-      } else {
-        inBuffer.put(b, off, remaining);
-        off += remaining;
-        len -= remaining;
-        encrypt();
-      }
-    }
-  }
-
-  /**
-   * To flush, we need to encrypt the data in the buffer and write to the
-   * underlying stream, then do the flush.
-   */
-  @Override
-  public void flush() throws IOException {
-    checkStream();
-    encrypt();
-    output.flush();
-    super.flush();
-  }
-
-  @Override
-  public void close() throws IOException {
-    if (closed) {
-      return;
-    }
-
-    try {
-      encryptFinal();
-      output.close();
-      freeBuffers();
-      cipher.close();
-      super.close();
-    } finally {
-      closed = true;
-    }
-  }
-
-  @Override
-  public boolean isOpen() {
-    return !closed;
-  }
-
-  @Override
-  public int write(ByteBuffer src) throws IOException {
-    checkStream();
-    final int len = src.remaining();
-    int remaining = len;
-    while (remaining > 0) {
-      final int space = inBuffer.remaining();
-      if (remaining < space) {
-        inBuffer.put(src);
-        remaining = 0;
-      } else {
-        // to void copy twice, we set the limit to copy directly
-        final int oldLimit = src.limit();
-        final int newLimit = src.position() + space;
-        src.limit(newLimit);
-
-        inBuffer.put(src);
-
-        // restore the old limit
-        src.limit(oldLimit);
-
-        remaining -= space;
-        encrypt();
-      }
-    }
-
-    return len;
-  }
-
-  /** Initialize the cipher. */
-  protected void initCipher()
-      throws IOException {
-    try {
-      cipher.init(Cipher.ENCRYPT_MODE, key, iv);
-    } catch (InvalidKeyException e) {
-      throw new IOException(e);
-    } catch(InvalidAlgorithmParameterException e) {
-      throw new IOException(e);
-    }
-  }
-
-  /**
-   * Do the encryption, input is {@link #inBuffer} and output is
-   * {@link #outBuffer}.
-   */
-  protected void encrypt() throws IOException {
-
-    inBuffer.flip();
-    outBuffer.clear();
-
-    try {
-      cipher.update(inBuffer, outBuffer);
-    } catch (ShortBufferException e) {
-      throw new IOException(e);
-    }
-
-    inBuffer.clear();
-    outBuffer.flip();
-
-    // write to output
-    output.write(outBuffer);
-  }
-
-  /**
-   * Do final encryption of the last data
-   */
-  protected void encryptFinal() throws IOException {
-    inBuffer.flip();
-    outBuffer.clear();
-
-    try {
-      cipher.doFinal(inBuffer, outBuffer);
-    } catch (ShortBufferException e) {
-      throw new IOException(e);
-    } catch (IllegalBlockSizeException e) {
-      throw new IOException(e);
-    } catch( BadPaddingException e) {
-      throw new IOException(e);
-    }
-
-    inBuffer.clear();
-    outBuffer.flip();
-
-    // write to output
-    output.write(outBuffer);
-  }
-
-  protected void checkStream() throws IOException {
-    if (closed) {
-      throw new IOException("Stream closed");
-    }
-  }
-
-  /** Forcibly free the direct buffers. */
-  protected void freeBuffers() {
-    Utils.freeDirectBuffer(inBuffer);
-    Utils.freeDirectBuffer(outBuffer);
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/main/java/org/apache/commons/crypto/stream/PositionedCipherInputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/PositionedCipherInputStream.java b/src/main/java/org/apache/commons/crypto/stream/PositionedCipherInputStream.java
new file mode 100644
index 0000000..c6a4169
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/stream/PositionedCipherInputStream.java
@@ -0,0 +1,311 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.crypto.stream;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.util.Properties;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+
+import org.apache.commons.crypto.cipher.Cipher;
+import org.apache.commons.crypto.cipher.CipherFactory;
+import org.apache.commons.crypto.stream.input.Input;
+import org.apache.commons.crypto.utils.IOUtils;
+import org.apache.commons.crypto.utils.Utils;
+
+import static org.apache.commons.crypto.cipher.CipherTransformation.AES_CTR_NOPADDING;
+
+/**
+ * PositionedCipherInputStream provides the capability to decrypt the stream starting
+ * at random position as well as provides the foundation for positioned read for
+ * decrypting. This needs a stream cipher mode such as AES CTR mode.
+ */
+public class PositionedCipherInputStream extends CTRCipherInputStream {
+
+  /**
+   * DirectBuffer pool
+   */
+  private final Queue<ByteBuffer> bufferPool = new
+      ConcurrentLinkedQueue<ByteBuffer>();
+
+  /**
+   * Cipher pool
+   */
+  private final Queue<CipherState> cipherPool = new
+      ConcurrentLinkedQueue<CipherState>();
+
+  public PositionedCipherInputStream(Properties props, Input in,
+                                     byte[] key, byte[] iv, long streamOffset) throws IOException {
+    this(in, Utils.getCipherInstance(AES_CTR_NOPADDING, props),
+        Utils.getBufferSize(props), key, iv, streamOffset);
+  }
+
+  public PositionedCipherInputStream(
+      Input input,
+      Cipher cipher,
+      int bufferSize,
+      byte[] key,
+      byte[] iv,
+      long streamOffset) throws IOException {
+    super(input, cipher, bufferSize, key, iv, streamOffset);
+  }
+
+  /**
+   * Read upto the specified number of bytes from a given position
+   * within a stream and return the number of bytes read. This does not
+   * change the current offset of the stream, and is thread-safe.
+   */
+  public int read(long position, byte[] buffer, int offset, int length)
+      throws IOException {
+    checkStream();
+    final int n = input.read(position, buffer, offset, length);
+    if (n > 0) {
+      // This operation does not change the current offset of the file
+      decrypt(position, buffer, offset, n);
+    }
+    return n;
+  }
+
+  /**
+   * Read the specified number of bytes from a given position within a stream.
+   * This does not change the current offset of the stream and is thread-safe.
+   */
+  public void readFully(long position, byte[] buffer, int offset, int length)
+      throws IOException {
+    checkStream();
+    IOUtils.readFully(input, position, buffer, offset, length);
+    if (length > 0) {
+      // This operation does not change the current offset of the file
+      decrypt(position, buffer, offset, length);
+    }
+  }
+
+  public void readFully(long position, byte[] buffer) throws IOException {
+    readFully(position, buffer, 0, buffer.length);
+  }
+
+  /**
+   * Decrypt length bytes in buffer starting at offset. Output is also put
+   * into buffer starting at offset. It is thread-safe.
+   */
+  protected void decrypt(long position, byte[] buffer, int offset, int length)
+      throws IOException {
+    ByteBuffer inBuffer = getBuffer();
+    ByteBuffer outBuffer = getBuffer();
+    CipherState state = null;
+    try {
+      state = getCipherState();
+      byte[] iv = getInitIV().clone();
+      resetCipher(state, position, iv);
+      byte padding = getPadding(position);
+      inBuffer.position(padding); // Set proper position for input data.
+
+      int n = 0;
+      while (n < length) {
+        int toDecrypt = Math.min(length - n, inBuffer.remaining());
+        inBuffer.put(buffer, offset + n, toDecrypt);
+
+        // Do decryption
+        decrypt(state, inBuffer, outBuffer, padding);
+
+        outBuffer.get(buffer, offset + n, toDecrypt);
+        n += toDecrypt;
+        padding = postDecryption(state, inBuffer, position + n, iv);
+      }
+    } finally {
+      returnBuffer(inBuffer);
+      returnBuffer(outBuffer);
+      returnCipherState(state);
+    }
+  }
+
+  /**
+   * Do the decryption using inBuffer as input and outBuffer as output.
+   * Upon return, inBuffer is cleared; the decrypted data starts at
+   * outBuffer.position() and ends at outBuffer.limit();
+   */
+  private void decrypt(CipherState state, ByteBuffer inBuffer,
+      ByteBuffer outBuffer, byte padding) throws IOException {
+    Utils.checkState(inBuffer.position() >= padding);
+    if(inBuffer.position() == padding) {
+      // There is no real data in inBuffer.
+      return;
+    }
+    inBuffer.flip();
+    outBuffer.clear();
+    decryptBuffer(state, inBuffer, outBuffer);
+    inBuffer.clear();
+    outBuffer.flip();
+    if (padding > 0) {
+      /*
+       * The plain text and cipher text have a 1:1 mapping, they start at the
+       * same position.
+       */
+      outBuffer.position(padding);
+    }
+  }
+
+  private void decryptBuffer(CipherState state, ByteBuffer inBuffer, ByteBuffer outBuffer)
+      throws IOException {
+    int inputSize = inBuffer.remaining();
+    try {
+      int n = state.getCipher().update(inBuffer, outBuffer);
+      if (n < inputSize) {
+        /**
+         * Typically code will not get here. Cipher#update will consume all
+         * input data and put result in outBuffer.
+         * Cipher#doFinal will reset the cipher context.
+         */
+        state.getCipher().doFinal(inBuffer, outBuffer);
+        state.reset(true);
+      }
+    } catch (ShortBufferException e) {
+      throw new IOException(e);
+    } catch (IllegalBlockSizeException e) {
+      throw new IOException(e);
+    } catch (BadPaddingException e) {
+      throw new IOException(e);
+    }
+  }
+
+  /**
+   * This method is executed immediately after decryption. Check whether
+   * cipher should be updated and recalculate padding if needed.
+   */
+  private byte postDecryption(CipherState state, ByteBuffer inBuffer,
+      long position, byte[] iv) throws IOException {
+    byte padding = 0;
+    if (state.isReset()) {
+      /*
+       * This code is generally not executed since the cipher usually
+       * maintains cipher context (e.g. the counter) internally. However,
+       * some implementations can't maintain context so a re-init is necessary
+       * after each decryption call.
+       */
+      resetCipher(state, position, iv);
+      padding = getPadding(position);
+      inBuffer.position(padding);
+    }
+    return padding;
+  }
+
+  /** Calculate the counter and iv, reset the cipher. */
+  private void resetCipher(CipherState state, long position, byte[] iv)
+      throws IOException {
+    final long counter = getCounter(position);
+    Utils.calculateIV(getInitIV(), counter, iv);
+    try {
+      state.getCipher().init(Cipher.DECRYPT_MODE, getKey(), iv);
+    } catch (InvalidKeyException e) {
+      throw new IOException(e);
+    } catch (InvalidAlgorithmParameterException e) {
+      throw new IOException(e);
+    }
+    state.reset(false);
+  }
+
+  /** Get Cipher from pool */
+  private CipherState getCipherState() throws IOException {
+    CipherState state = cipherPool.poll();
+    if (state == null) {
+      Cipher cipher;
+      try {
+        cipher = CipherFactory.getInstance(getCipher().getTransformation(),
+            getCipher().getProperties());
+      } catch (GeneralSecurityException e) {
+        throw new IOException(e);
+      }
+      state = new CipherState(cipher);
+    }
+
+    return state;
+  }
+
+  /** Return Cipher to pool */
+  private void returnCipherState(CipherState state) {
+    if (state != null) {
+      cipherPool.add(state);
+    }
+  }
+
+  /** Get direct buffer from pool */
+  private ByteBuffer getBuffer() {
+    ByteBuffer buffer = bufferPool.poll();
+    if (buffer == null) {
+      buffer = ByteBuffer.allocateDirect(getBufferSize());
+    }
+
+    return buffer;
+  }
+
+  /** Return direct buffer to pool */
+  private void returnBuffer(ByteBuffer buf) {
+    if (buf != null) {
+      buf.clear();
+      bufferPool.add(buf);
+    }
+  }
+
+  @Override
+  public void close() throws IOException {
+    if (!isOpen()) {
+      return;
+    }
+
+    cleanBufferPool();
+    super.close();
+  }
+
+  /** Clean direct buffer pool */
+  private void cleanBufferPool() {
+    ByteBuffer buf;
+    while ((buf = bufferPool.poll()) != null) {
+      Utils.freeDirectBuffer(buf);
+    }
+  }
+
+  private class CipherState {
+    private Cipher cipher;
+    private boolean reset;
+
+    public CipherState(Cipher cipher) {
+      this.cipher = cipher;
+      this.reset = false;
+    }
+
+    public Cipher getCipher() {
+      return cipher;
+    }
+
+    public boolean isReset() {
+      return reset;
+    }
+
+    public void reset(boolean reset) {
+      this.reset = reset;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java b/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java
deleted file mode 100644
index 160f6ee..0000000
--- a/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.crypto.stream;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.util.Properties;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.ShortBufferException;
-
-import org.apache.commons.crypto.cipher.Cipher;
-import org.apache.commons.crypto.cipher.CipherFactory;
-import org.apache.commons.crypto.stream.input.Input;
-import org.apache.commons.crypto.utils.IOUtils;
-import org.apache.commons.crypto.utils.Utils;
-
-import static org.apache.commons.crypto.cipher.CipherTransformation.AES_CTR_NOPADDING;
-
-/**
- * PositionedCryptoInputStream provides the capability to decrypt the stream starting
- * at random position as well as provides the foundation for positioned read for
- * decrypting. This needs a stream cipher mode such as AES CTR mode.
- */
-public class PositionedCryptoInputStream extends CTRCryptoInputStream {
-
-  /**
-   * DirectBuffer pool
-   */
-  private final Queue<ByteBuffer> bufferPool = new
-      ConcurrentLinkedQueue<ByteBuffer>();
-
-  /**
-   * Cipher pool
-   */
-  private final Queue<CipherState> cipherPool = new
-      ConcurrentLinkedQueue<CipherState>();
-
-  public PositionedCryptoInputStream(Properties props, Input in,
-      byte[] key, byte[] iv, long streamOffset) throws IOException {
-    this(in, Utils.getCipherInstance(AES_CTR_NOPADDING, props),
-        Utils.getBufferSize(props), key, iv, streamOffset);
-  }
-
-  public PositionedCryptoInputStream(
-      Input input,
-      Cipher cipher,
-      int bufferSize,
-      byte[] key,
-      byte[] iv,
-      long streamOffset) throws IOException {
-    super(input, cipher, bufferSize, key, iv, streamOffset);
-  }
-
-  /**
-   * Read upto the specified number of bytes from a given position
-   * within a stream and return the number of bytes read. This does not
-   * change the current offset of the stream, and is thread-safe.
-   */
-  public int read(long position, byte[] buffer, int offset, int length)
-      throws IOException {
-    checkStream();
-    final int n = input.read(position, buffer, offset, length);
-    if (n > 0) {
-      // This operation does not change the current offset of the file
-      decrypt(position, buffer, offset, n);
-    }
-    return n;
-  }
-
-  /**
-   * Read the specified number of bytes from a given position within a stream.
-   * This does not change the current offset of the stream and is thread-safe.
-   */
-  public void readFully(long position, byte[] buffer, int offset, int length)
-      throws IOException {
-    checkStream();
-    IOUtils.readFully(input, position, buffer, offset, length);
-    if (length > 0) {
-      // This operation does not change the current offset of the file
-      decrypt(position, buffer, offset, length);
-    }
-  }
-
-  public void readFully(long position, byte[] buffer) throws IOException {
-    readFully(position, buffer, 0, buffer.length);
-  }
-
-  /**
-   * Decrypt length bytes in buffer starting at offset. Output is also put
-   * into buffer starting at offset. It is thread-safe.
-   */
-  protected void decrypt(long position, byte[] buffer, int offset, int length)
-      throws IOException {
-    ByteBuffer inBuffer = getBuffer();
-    ByteBuffer outBuffer = getBuffer();
-    CipherState state = null;
-    try {
-      state = getCipherState();
-      byte[] iv = getInitIV().clone();
-      resetCipher(state, position, iv);
-      byte padding = getPadding(position);
-      inBuffer.position(padding); // Set proper position for input data.
-
-      int n = 0;
-      while (n < length) {
-        int toDecrypt = Math.min(length - n, inBuffer.remaining());
-        inBuffer.put(buffer, offset + n, toDecrypt);
-
-        // Do decryption
-        decrypt(state, inBuffer, outBuffer, padding);
-
-        outBuffer.get(buffer, offset + n, toDecrypt);
-        n += toDecrypt;
-        padding = postDecryption(state, inBuffer, position + n, iv);
-      }
-    } finally {
-      returnBuffer(inBuffer);
-      returnBuffer(outBuffer);
-      returnCipherState(state);
-    }
-  }
-
-  /**
-   * Do the decryption using inBuffer as input and outBuffer as output.
-   * Upon return, inBuffer is cleared; the decrypted data starts at
-   * outBuffer.position() and ends at outBuffer.limit();
-   */
-  private void decrypt(CipherState state, ByteBuffer inBuffer,
-      ByteBuffer outBuffer, byte padding) throws IOException {
-    Utils.checkState(inBuffer.position() >= padding);
-    if(inBuffer.position() == padding) {
-      // There is no real data in inBuffer.
-      return;
-    }
-    inBuffer.flip();
-    outBuffer.clear();
-    decryptBuffer(state, inBuffer, outBuffer);
-    inBuffer.clear();
-    outBuffer.flip();
-    if (padding > 0) {
-      /*
-       * The plain text and cipher text have a 1:1 mapping, they start at the
-       * same position.
-       */
-      outBuffer.position(padding);
-    }
-  }
-
-  private void decryptBuffer(CipherState state, ByteBuffer inBuffer, ByteBuffer outBuffer)
-      throws IOException {
-    int inputSize = inBuffer.remaining();
-    try {
-      int n = state.getCipher().update(inBuffer, outBuffer);
-      if (n < inputSize) {
-        /**
-         * Typically code will not get here. Cipher#update will consume all
-         * input data and put result in outBuffer.
-         * Cipher#doFinal will reset the cipher context.
-         */
-        state.getCipher().doFinal(inBuffer, outBuffer);
-        state.reset(true);
-      }
-    } catch (ShortBufferException e) {
-      throw new IOException(e);
-    } catch (IllegalBlockSizeException e) {
-      throw new IOException(e);
-    } catch (BadPaddingException e) {
-      throw new IOException(e);
-    }
-  }
-
-  /**
-   * This method is executed immediately after decryption. Check whether
-   * cipher should be updated and recalculate padding if needed.
-   */
-  private byte postDecryption(CipherState state, ByteBuffer inBuffer,
-      long position, byte[] iv) throws IOException {
-    byte padding = 0;
-    if (state.isReset()) {
-      /*
-       * This code is generally not executed since the cipher usually
-       * maintains cipher context (e.g. the counter) internally. However,
-       * some implementations can't maintain context so a re-init is necessary
-       * after each decryption call.
-       */
-      resetCipher(state, position, iv);
-      padding = getPadding(position);
-      inBuffer.position(padding);
-    }
-    return padding;
-  }
-
-  /** Calculate the counter and iv, reset the cipher. */
-  private void resetCipher(CipherState state, long position, byte[] iv)
-      throws IOException {
-    final long counter = getCounter(position);
-    Utils.calculateIV(getInitIV(), counter, iv);
-    try {
-      state.getCipher().init(Cipher.DECRYPT_MODE, getKey(), iv);
-    } catch (InvalidKeyException e) {
-      throw new IOException(e);
-    } catch (InvalidAlgorithmParameterException e) {
-      throw new IOException(e);
-    }
-    state.reset(false);
-  }
-
-  /** Get Cipher from pool */
-  private CipherState getCipherState() throws IOException {
-    CipherState state = cipherPool.poll();
-    if (state == null) {
-      Cipher cipher;
-      try {
-        cipher = CipherFactory.getInstance(getCipher().getTransformation(),
-            getCipher().getProperties());
-      } catch (GeneralSecurityException e) {
-        throw new IOException(e);
-      }
-      state = new CipherState(cipher);
-    }
-
-    return state;
-  }
-
-  /** Return Cipher to pool */
-  private void returnCipherState(CipherState state) {
-    if (state != null) {
-      cipherPool.add(state);
-    }
-  }
-
-  /** Get direct buffer from pool */
-  private ByteBuffer getBuffer() {
-    ByteBuffer buffer = bufferPool.poll();
-    if (buffer == null) {
-      buffer = ByteBuffer.allocateDirect(getBufferSize());
-    }
-
-    return buffer;
-  }
-
-  /** Return direct buffer to pool */
-  private void returnBuffer(ByteBuffer buf) {
-    if (buf != null) {
-      buf.clear();
-      bufferPool.add(buf);
-    }
-  }
-
-  @Override
-  public void close() throws IOException {
-    if (!isOpen()) {
-      return;
-    }
-
-    cleanBufferPool();
-    super.close();
-  }
-
-  /** Clean direct buffer pool */
-  private void cleanBufferPool() {
-    ByteBuffer buf;
-    while ((buf = bufferPool.poll()) != null) {
-      Utils.freeDirectBuffer(buf);
-    }
-  }
-
-  private class CipherState {
-    private Cipher cipher;
-    private boolean reset;
-
-    public CipherState(Cipher cipher) {
-      this.cipher = cipher;
-      this.reset = false;
-    }
-
-    public Cipher getCipher() {
-      return cipher;
-    }
-
-    public boolean isReset() {
-      return reset;
-    }
-
-    public void reset(boolean reset) {
-      this.reset = reset;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/main/java/org/apache/commons/crypto/stream/input/ChannelInput.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/input/ChannelInput.java b/src/main/java/org/apache/commons/crypto/stream/input/ChannelInput.java
index ee24a0c..9aff624 100644
--- a/src/main/java/org/apache/commons/crypto/stream/input/ChannelInput.java
+++ b/src/main/java/org/apache/commons/crypto/stream/input/ChannelInput.java
@@ -23,7 +23,7 @@ import java.nio.channels.ReadableByteChannel;
 
 /**
  * The ChannelInput class takes a <code>ReadableByteChannel</code> object and
- * wraps it as <code>Input</code> object acceptable by <code>CryptoInputStream</code>.
+ * wraps it as <code>Input</code> object acceptable by <code>CipherInputStream</code>.
  */
 public class ChannelInput implements Input {
   private static final int SKIP_BUFFER_SIZE = 2048;

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/main/java/org/apache/commons/crypto/stream/input/Input.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/input/Input.java b/src/main/java/org/apache/commons/crypto/stream/input/Input.java
index a63c6ca..2971edb 100644
--- a/src/main/java/org/apache/commons/crypto/stream/input/Input.java
+++ b/src/main/java/org/apache/commons/crypto/stream/input/Input.java
@@ -21,7 +21,7 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 
 /**
- * The Input interface abstract the input source of <code>CryptoInputStream</code> so that
+ * The Input interface abstract the input source of <code>CipherInputStream</code> so that
  * different implementation of input can be used. The implementation Input interface will usually
  * wraps an input mechanism such as <code>InputStream</code> or <code>ReadableByteChannel</code>.
  */

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/main/java/org/apache/commons/crypto/stream/input/StreamInput.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/input/StreamInput.java b/src/main/java/org/apache/commons/crypto/stream/input/StreamInput.java
index ac3739b..c7e6771 100644
--- a/src/main/java/org/apache/commons/crypto/stream/input/StreamInput.java
+++ b/src/main/java/org/apache/commons/crypto/stream/input/StreamInput.java
@@ -23,7 +23,7 @@ import java.nio.ByteBuffer;
 
 /**
  * The StreamInput class takes a <code>InputStream</code> object and
- * wraps it as <code>Input</code> object acceptable by <code>CryptoInputStream</code>.
+ * wraps it as <code>Input</code> object acceptable by <code>CipherInputStream</code>.
  */
 public class StreamInput implements Input {
   private byte[] buf;

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/main/java/org/apache/commons/crypto/stream/output/ChannelOutput.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/output/ChannelOutput.java b/src/main/java/org/apache/commons/crypto/stream/output/ChannelOutput.java
index bae82a8..0a60217 100644
--- a/src/main/java/org/apache/commons/crypto/stream/output/ChannelOutput.java
+++ b/src/main/java/org/apache/commons/crypto/stream/output/ChannelOutput.java
@@ -23,7 +23,7 @@ import java.nio.channels.WritableByteChannel;
 
 /**
  * The ChannelOutput class takes a <code>WritableByteChannel</code> object and wraps it as 
- * <code>Output</code> object acceptable by <code>CryptoOutputStream</code> as the output target.
+ * <code>Output</code> object acceptable by <code>CipherOutputStream</code> as the output target.
  */
 public class ChannelOutput implements Output {
 

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/main/java/org/apache/commons/crypto/stream/output/Output.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/output/Output.java b/src/main/java/org/apache/commons/crypto/stream/output/Output.java
index 903fcea..c57a89e 100644
--- a/src/main/java/org/apache/commons/crypto/stream/output/Output.java
+++ b/src/main/java/org/apache/commons/crypto/stream/output/Output.java
@@ -21,7 +21,7 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 
 /**
- * The Output interface abstract the output target of <code>CryptoOutputStream</code> so that
+ * The Output interface abstract the output target of <code>CipherOutputStream</code> so that
  * different implementation of output can be used. The implementation Output interface will usually
  * wraps an output mechanism such as <code>OutputStream</code> or <code>WritableByteChannel</code>.
  */

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/main/java/org/apache/commons/crypto/stream/output/StreamOutput.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/output/StreamOutput.java b/src/main/java/org/apache/commons/crypto/stream/output/StreamOutput.java
index beead7f..ad067be 100644
--- a/src/main/java/org/apache/commons/crypto/stream/output/StreamOutput.java
+++ b/src/main/java/org/apache/commons/crypto/stream/output/StreamOutput.java
@@ -23,7 +23,7 @@ import java.nio.ByteBuffer;
 
 /**
  * The StreamOutput class takes a <code>OutputStream</code> object and wraps it as 
- * <code>Output</code> object acceptable by <code>CryptoOutputStream</code> as the output target.
+ * <code>Output</code> object acceptable by <code>CipherOutputStream</code> as the output target.
  */
 public class StreamOutput implements Output {
   private byte[] buf;

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java
new file mode 100644
index 0000000..6e2d864
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java
@@ -0,0 +1,456 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.crypto.stream;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.security.SecureRandom;
+import java.util.Properties;
+import java.util.Random;
+
+import org.apache.commons.crypto.cipher.Cipher;
+import org.apache.commons.crypto.cipher.CipherTransformation;
+import org.apache.commons.crypto.cipher.JceCipher;
+import org.apache.commons.crypto.cipher.Openssl;
+import org.apache.commons.crypto.cipher.OpensslCipher;
+import org.apache.commons.crypto.utils.ReflectionUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public abstract class AbstractCipherStreamTest {
+  private static final Log LOG= LogFactory.getLog(AbstractCipherStreamTest.class);
+
+  private final int dataLen = 20000;
+  private byte[] data = new byte[dataLen];
+  private byte[] encData;
+  private Properties props = new Properties();
+  protected byte[] key = new byte[16];
+  private byte[] iv = new byte[16];
+  private int count = 10000;
+  protected static int defaultBufferSize = 8192;
+  protected static int smallBufferSize = 1024;
+
+  private final String jceCipherClass = JceCipher.class.getName();
+  private final String opensslCipherClass = OpensslCipher.class.getName();
+  protected CipherTransformation transformation;
+
+  public abstract void setUp() throws IOException;
+
+  @Before
+  public void before() throws IOException {
+    Random random = new SecureRandom();
+    random.nextBytes(data);
+    random.nextBytes(key);
+    random.nextBytes(iv);
+    setUp();
+    prepareData();
+  }
+
+  /** Test skip. */
+  @Test(timeout=120000)
+  public void testSkip() throws Exception {
+    doSkipTest(jceCipherClass, false);
+    doSkipTest(opensslCipherClass, false);
+
+    doSkipTest(jceCipherClass, true);
+    doSkipTest(opensslCipherClass, true);
+  }
+
+  /** Test byte buffer read with different buffer size. */
+  @Test(timeout=120000)
+  public void testByteBufferRead() throws Exception {
+    doByteBufferRead(jceCipherClass, false);
+    doByteBufferRead(opensslCipherClass, false);
+
+    doByteBufferRead(jceCipherClass, true);
+    doByteBufferRead(opensslCipherClass, true);
+  }
+
+  /** Test byte buffer write. */
+  @Test(timeout=120000)
+  public void testByteBufferWrite() throws Exception {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    doByteBufferWrite(jceCipherClass, baos, false);
+    doByteBufferWrite(opensslCipherClass, baos, false);
+
+    doByteBufferWrite(jceCipherClass, baos, true);
+    doByteBufferWrite(opensslCipherClass, baos, true);
+  }
+
+  private void doSkipTest(String cipherClass, boolean withChannel) throws IOException {
+    InputStream in = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
+    byte[] result = new byte[dataLen];
+    int n1 = readAll(in, result, 0, dataLen / 3);
+
+    long skipped = in.skip(dataLen / 3);
+    int n2 = readAll(in, result, 0, dataLen);
+
+    Assert.assertEquals(dataLen, n1 + skipped + n2);
+    byte[] readData = new byte[n2];
+    System.arraycopy(result, 0, readData, 0, n2);
+    byte[] expectedData = new byte[n2];
+    System.arraycopy(data, dataLen - n2, expectedData, 0, n2);
+    Assert.assertArrayEquals(readData, expectedData);
+
+    try {
+      skipped = in.skip(-3);
+      Assert.fail("Skip Negative length should fail.");
+    } catch (IllegalArgumentException e) {
+      Assert.assertTrue(e.getMessage().contains("Negative skip length"));
+    }
+
+    // Skip after EOF
+    skipped = in.skip(3);
+    Assert.assertEquals(skipped, 0);
+
+    in.close();
+  }
+
+  private void doByteBufferRead(String cipherClass, boolean withChannel) throws Exception {
+    // Default buffer size, initial buffer position is 0
+    InputStream in = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
+    ByteBuffer buf = ByteBuffer.allocate(dataLen + 100);
+    byteBufferReadCheck(in, buf, 0);
+    in.close();
+
+    // Default buffer size, initial buffer position is not 0
+    in = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
+    buf.clear();
+    byteBufferReadCheck(in, buf, 11);
+    in.close();
+
+    // Small buffer size, initial buffer position is 0
+    in = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), smallBufferSize, iv, withChannel);
+    buf.clear();
+    byteBufferReadCheck(in, buf, 0);
+    in.close();
+
+    // Small buffer size, initial buffer position is not 0
+    in = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), smallBufferSize, iv, withChannel);
+    buf.clear();
+    byteBufferReadCheck(in, buf, 11);
+    in.close();
+
+    // Direct buffer, default buffer size, initial buffer position is 0
+    in = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), defaultBufferSize, 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 = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
+    buf.clear();
+    byteBufferReadCheck(in, buf, 11);
+    in.close();
+
+    // Direct buffer, small buffer size, initial buffer position is 0
+    in = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), smallBufferSize, iv, withChannel);
+    buf.clear();
+    byteBufferReadCheck(in, buf, 0);
+    in.close();
+
+    // Direct buffer, small buffer size, initial buffer position is not 0
+    in = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), smallBufferSize, iv, withChannel);
+    buf.clear();
+    byteBufferReadCheck(in, buf, 11);
+    in.close();
+  }
+
+  private void doByteBufferWrite(String cipherClass, ByteArrayOutputStream baos,
+                                 boolean withChannel)
+      throws Exception {
+    baos.reset();
+    CipherOutputStream out =
+        getCipherOutputStream(baos, getCipher(cipherClass), defaultBufferSize,
+            iv, withChannel);
+    ByteBuffer buf = ByteBuffer.allocateDirect(dataLen / 2);
+    buf.put(data, 0, dataLen / 2);
+    buf.flip();
+    int n1 = out.write(buf);
+
+    buf.clear();
+    buf.put(data, n1, dataLen / 3);
+    buf.flip();
+    int n2 = out.write(buf);
+
+    buf.clear();
+    buf.put(data, n1 + n2, dataLen - n1 - n2);
+    buf.flip();
+    int n3 = out.write(buf);
+
+    Assert.assertEquals(dataLen, n1 + n2 + n3);
+
+    out.flush();
+
+    InputStream in = getCipherInputStream(new ByteArrayInputStream(encData),
+        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
+    buf = ByteBuffer.allocate(dataLen + 100);
+    byteBufferReadCheck(in, buf, 0);
+    in.close();
+  }
+
+  private void byteBufferReadCheck(InputStream in, ByteBuffer buf,
+      int bufPos) throws Exception {
+    buf.position(bufPos);
+    int n = ((ReadableByteChannel) in).read(buf);
+    Assert.assertEquals(bufPos + n, buf.position());
+    byte[] readData = new byte[n];
+    buf.rewind();
+    buf.position(bufPos);
+    buf.get(readData);
+    byte[] expectedData = new byte[n];
+    System.arraycopy(data, 0, expectedData, 0, n);
+    Assert.assertArrayEquals(readData, expectedData);
+  }
+
+  private void prepareData() throws IOException {
+    Cipher cipher = null;
+    try {
+      cipher = (Cipher)ReflectionUtils.newInstance(
+          ReflectionUtils.getClassByName(jceCipherClass), props, transformation);
+    } catch (ClassNotFoundException cnfe) {
+      throw new IOException("Illegal crypto cipher!");
+    }
+
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    OutputStream out = new CipherOutputStream(baos, cipher, defaultBufferSize, key, iv);
+    out.write(data);
+    out.flush();
+    out.close();
+    encData = baos.toByteArray();
+  }
+
+  protected CipherInputStream getCipherInputStream(ByteArrayInputStream bais,
+                                                   Cipher cipher,
+                                                   int bufferSize, byte[] iv,
+                                                   boolean withChannel) throws
+      IOException {
+    if (withChannel) {
+      return new CipherInputStream(Channels.newChannel(bais), cipher,
+          bufferSize, key, iv);
+    } else {
+      return new CipherInputStream(bais, cipher, bufferSize, key, iv);
+    }
+  }
+
+  protected CipherOutputStream getCipherOutputStream(ByteArrayOutputStream baos,
+                                                     Cipher cipher,
+                                                     int bufferSize, byte[] iv,
+                                                     boolean withChannel) throws
+      IOException {
+    if (withChannel) {
+      return new CipherOutputStream(Channels.newChannel(baos), cipher,
+          bufferSize, key, iv);
+    } else {
+      return new CipherOutputStream(baos, cipher, bufferSize, key, iv);
+    }
+  }
+
+  private int readAll(InputStream in, byte[] b, int offset, int len)
+      throws IOException {
+    int n = 0;
+    int total = 0;
+    while (n != -1) {
+      total += n;
+      if (total >= len) {
+        break;
+      }
+      n = in.read(b, offset + total, len - total);
+    }
+
+    return total;
+  }
+
+  protected Cipher getCipher(String cipherClass) throws IOException {
+    try {
+      return (Cipher)ReflectionUtils.newInstance(
+          ReflectionUtils.getClassByName(cipherClass), props, transformation);
+    } catch (ClassNotFoundException cnfe) {
+      throw new IOException("Illegal crypto cipher!");
+    }
+  }
+
+  @Test
+  public void testReadWrite() throws Exception {
+    Assert.assertEquals(null, Openssl.getLoadingFailureReason());
+    doReadWriteTest(0, jceCipherClass, jceCipherClass, iv);
+    doReadWriteTest(0, opensslCipherClass, opensslCipherClass, iv);
+    doReadWriteTest(count, jceCipherClass, jceCipherClass, iv);
+    doReadWriteTest(count, opensslCipherClass, opensslCipherClass, iv);
+    doReadWriteTest(count, jceCipherClass, opensslCipherClass, iv);
+    doReadWriteTest(count, opensslCipherClass, jceCipherClass, iv);
+    // Overflow test, IV: xx xx xx xx xx xx xx xx ff ff ff ff ff ff ff ff
+    for(int i = 0; i < 8; i++) {
+      iv[8 + i] = (byte) 0xff;
+    }
+    doReadWriteTest(count, jceCipherClass, jceCipherClass, iv);
+    doReadWriteTest(count, opensslCipherClass, opensslCipherClass, iv);
+    doReadWriteTest(count, jceCipherClass, opensslCipherClass, iv);
+    doReadWriteTest(count, opensslCipherClass, jceCipherClass, iv);
+  }
+
+  private void doReadWriteTest(int count, String encCipherClass,
+                               String decCipherClass, byte[] iv) throws IOException {
+    doReadWriteTestForInputStream(count, encCipherClass, decCipherClass, iv);
+    doReadWriteTestForReadableByteChannel(count, encCipherClass, decCipherClass,
+        iv);
+  }
+
+  private void doReadWriteTestForInputStream(int count, String encCipherClass,
+                                             String decCipherClass, byte[] iv) throws IOException {
+    Cipher encCipher = getCipher(encCipherClass);
+    LOG.debug("Created a cipher object of type: " + encCipherClass);
+
+    // Generate data
+    SecureRandom random = new SecureRandom();
+    byte[] originalData = new byte[count];
+    byte[] decryptedData = new byte[count];
+    random.nextBytes(originalData);
+    LOG.debug("Generated " + count + " records");
+
+    // Encrypt data
+    ByteArrayOutputStream encryptedData = new ByteArrayOutputStream();
+    CipherOutputStream out =
+        getCipherOutputStream(encryptedData, encCipher, defaultBufferSize, iv,
+            false);
+    out.write(originalData, 0, originalData.length);
+    out.flush();
+    out.close();
+    LOG.debug("Finished encrypting data");
+
+    Cipher decCipher = getCipher(decCipherClass);
+    LOG.debug("Created a cipher object of type: " + decCipherClass);
+
+    // Decrypt data
+    CipherInputStream in = getCipherInputStream(
+        new ByteArrayInputStream(encryptedData.toByteArray()), decCipher,
+        defaultBufferSize, iv, false);
+
+    // Check
+    int remainingToRead = count;
+    int offset = 0;
+    while (remainingToRead > 0) {
+      int n = in.read(decryptedData, offset, decryptedData.length - offset);
+      if (n >=0) {
+        remainingToRead -= n;
+        offset += n;
+      }
+    }
+
+    Assert.assertArrayEquals("originalData and decryptedData not equal",
+        originalData, decryptedData);
+
+    // Decrypt data byte-at-a-time
+    in = getCipherInputStream(
+        new ByteArrayInputStream(encryptedData.toByteArray()), decCipher,
+        defaultBufferSize, iv, false);
+
+    // Check
+    DataInputStream originalIn = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(originalData)));
+    int expected;
+    do {
+      expected = originalIn.read();
+      Assert.assertEquals("Decrypted stream read by byte does not match",
+          expected, in.read());
+    } while (expected != -1);
+
+    LOG.debug("SUCCESS! Completed checking " + count + " records");
+  }
+
+  private void doReadWriteTestForReadableByteChannel(int count,
+                                                     String encCipherClass,
+                                                     String decCipherClass,
+                                                     byte[] iv) throws IOException {
+    Cipher encCipher = getCipher(encCipherClass);
+    LOG.debug("Created a cipher object of type: " + encCipherClass);
+
+    // Generate data
+    SecureRandom random = new SecureRandom();
+    byte[] originalData = new byte[count];
+    byte[] decryptedData = new byte[count];
+    random.nextBytes(originalData);
+    LOG.debug("Generated " + count + " records");
+
+    // Encrypt data
+    ByteArrayOutputStream encryptedData = new ByteArrayOutputStream();
+    CipherOutputStream out =
+        getCipherOutputStream(encryptedData, encCipher, defaultBufferSize, iv,
+            true);
+    out.write(originalData, 0, originalData.length);
+    out.flush();
+    out.close();
+    LOG.debug("Finished encrypting data");
+
+    Cipher decCipher = getCipher(decCipherClass);
+    LOG.debug("Created a cipher object of type: " + decCipherClass);
+
+    // Decrypt data
+    CipherInputStream in = getCipherInputStream(
+        new ByteArrayInputStream(encryptedData.toByteArray()), decCipher,
+        defaultBufferSize, iv, true);
+
+    // Check
+    int remainingToRead = count;
+    int offset = 0;
+    while (remainingToRead > 0) {
+      int n = in.read(decryptedData, offset, decryptedData.length - offset);
+      if (n >=0) {
+        remainingToRead -= n;
+        offset += n;
+      }
+    }
+
+    Assert.assertArrayEquals("originalData and decryptedData not equal",
+        originalData, decryptedData);
+
+    // Decrypt data byte-at-a-time
+    in = getCipherInputStream(new ByteArrayInputStream(
+        encryptedData.toByteArray()),decCipher,defaultBufferSize,iv,true);
+
+    // Check
+    DataInputStream originalIn = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(originalData)));
+    int expected;
+    do {
+      expected = originalIn.read();
+      Assert.assertEquals("Decrypted stream read by byte does not match",
+          expected, in.read());
+    } while (expected != -1);
+
+    LOG.debug("SUCCESS! Completed checking " + count + " records");
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/AbstractCryptoStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/AbstractCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/AbstractCryptoStreamTest.java
deleted file mode 100644
index fe73f00..0000000
--- a/src/test/java/org/apache/commons/crypto/stream/AbstractCryptoStreamTest.java
+++ /dev/null
@@ -1,456 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.crypto.stream;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
-import java.security.SecureRandom;
-import java.util.Properties;
-import java.util.Random;
-
-import org.apache.commons.crypto.cipher.Cipher;
-import org.apache.commons.crypto.cipher.CipherTransformation;
-import org.apache.commons.crypto.cipher.JceCipher;
-import org.apache.commons.crypto.cipher.Openssl;
-import org.apache.commons.crypto.cipher.OpensslCipher;
-import org.apache.commons.crypto.utils.ReflectionUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-public abstract class AbstractCryptoStreamTest {
-  private static final Log LOG= LogFactory.getLog(AbstractCryptoStreamTest.class);
-
-  private final int dataLen = 20000;
-  private byte[] data = new byte[dataLen];
-  private byte[] encData;
-  private Properties props = new Properties();
-  protected byte[] key = new byte[16];
-  private byte[] iv = new byte[16];
-  private int count = 10000;
-  protected static int defaultBufferSize = 8192;
-  protected static int smallBufferSize = 1024;
-
-  private final String jceCipherClass = JceCipher.class.getName();
-  private final String opensslCipherClass = OpensslCipher.class.getName();
-  protected CipherTransformation transformation;
-
-  public abstract void setUp() throws IOException;
-
-  @Before
-  public void before() throws IOException {
-    Random random = new SecureRandom();
-    random.nextBytes(data);
-    random.nextBytes(key);
-    random.nextBytes(iv);
-    setUp();
-    prepareData();
-  }
-
-  /** Test skip. */
-  @Test(timeout=120000)
-  public void testSkip() throws Exception {
-    doSkipTest(jceCipherClass, false);
-    doSkipTest(opensslCipherClass, false);
-
-    doSkipTest(jceCipherClass, true);
-    doSkipTest(opensslCipherClass, true);
-  }
-
-  /** Test byte buffer read with different buffer size. */
-  @Test(timeout=120000)
-  public void testByteBufferRead() throws Exception {
-    doByteBufferRead(jceCipherClass, false);
-    doByteBufferRead(opensslCipherClass, false);
-
-    doByteBufferRead(jceCipherClass, true);
-    doByteBufferRead(opensslCipherClass, true);
-  }
-
-  /** Test byte buffer write. */
-  @Test(timeout=120000)
-  public void testByteBufferWrite() throws Exception {
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    doByteBufferWrite(jceCipherClass, baos, false);
-    doByteBufferWrite(opensslCipherClass, baos, false);
-
-    doByteBufferWrite(jceCipherClass, baos, true);
-    doByteBufferWrite(opensslCipherClass, baos, true);
-  }
-
-  private void doSkipTest(String cipherClass, boolean withChannel) throws IOException {
-    InputStream in = getCryptoInputStream(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
-    byte[] result = new byte[dataLen];
-    int n1 = readAll(in, result, 0, dataLen / 3);
-
-    long skipped = in.skip(dataLen / 3);
-    int n2 = readAll(in, result, 0, dataLen);
-
-    Assert.assertEquals(dataLen, n1 + skipped + n2);
-    byte[] readData = new byte[n2];
-    System.arraycopy(result, 0, readData, 0, n2);
-    byte[] expectedData = new byte[n2];
-    System.arraycopy(data, dataLen - n2, expectedData, 0, n2);
-    Assert.assertArrayEquals(readData, expectedData);
-
-    try {
-      skipped = in.skip(-3);
-      Assert.fail("Skip Negative length should fail.");
-    } catch (IllegalArgumentException e) {
-      Assert.assertTrue(e.getMessage().contains("Negative skip length"));
-    }
-
-    // Skip after EOF
-    skipped = in.skip(3);
-    Assert.assertEquals(skipped, 0);
-
-    in.close();
-  }
-
-  private void doByteBufferRead(String cipherClass, boolean withChannel) throws Exception {
-    // Default buffer size, initial buffer position is 0
-    InputStream in = getCryptoInputStream(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
-    ByteBuffer buf = ByteBuffer.allocate(dataLen + 100);
-    byteBufferReadCheck(in, buf, 0);
-    in.close();
-
-    // Default buffer size, initial buffer position is not 0
-    in = getCryptoInputStream(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
-    buf.clear();
-    byteBufferReadCheck(in, buf, 11);
-    in.close();
-
-    // Small buffer size, initial buffer position is 0
-    in = getCryptoInputStream(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), smallBufferSize, iv, withChannel);
-    buf.clear();
-    byteBufferReadCheck(in, buf, 0);
-    in.close();
-
-    // Small buffer size, initial buffer position is not 0
-    in = getCryptoInputStream(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), smallBufferSize, iv, withChannel);
-    buf.clear();
-    byteBufferReadCheck(in, buf, 11);
-    in.close();
-
-    // Direct buffer, default buffer size, initial buffer position is 0
-    in = getCryptoInputStream(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), defaultBufferSize, 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(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
-    buf.clear();
-    byteBufferReadCheck(in, buf, 11);
-    in.close();
-
-    // Direct buffer, small buffer size, initial buffer position is 0
-    in = getCryptoInputStream(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), smallBufferSize, iv, withChannel);
-    buf.clear();
-    byteBufferReadCheck(in, buf, 0);
-    in.close();
-
-    // Direct buffer, small buffer size, initial buffer position is not 0
-    in = getCryptoInputStream(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), smallBufferSize, iv, withChannel);
-    buf.clear();
-    byteBufferReadCheck(in, buf, 11);
-    in.close();
-  }
-
-  private void doByteBufferWrite(String cipherClass, ByteArrayOutputStream baos,
-                                 boolean withChannel)
-      throws Exception {
-    baos.reset();
-    CryptoOutputStream out =
-        getCryptoOutputStream(baos, getCipher(cipherClass), defaultBufferSize,
-            iv, withChannel);
-    ByteBuffer buf = ByteBuffer.allocateDirect(dataLen / 2);
-    buf.put(data, 0, dataLen / 2);
-    buf.flip();
-    int n1 = out.write(buf);
-
-    buf.clear();
-    buf.put(data, n1, dataLen / 3);
-    buf.flip();
-    int n2 = out.write(buf);
-
-    buf.clear();
-    buf.put(data, n1 + n2, dataLen - n1 - n2);
-    buf.flip();
-    int n3 = out.write(buf);
-
-    Assert.assertEquals(dataLen, n1 + n2 + n3);
-
-    out.flush();
-
-    InputStream in = getCryptoInputStream(new ByteArrayInputStream(encData),
-        getCipher(cipherClass), defaultBufferSize, iv, withChannel);
-    buf = ByteBuffer.allocate(dataLen + 100);
-    byteBufferReadCheck(in, buf, 0);
-    in.close();
-  }
-
-  private void byteBufferReadCheck(InputStream in, ByteBuffer buf,
-      int bufPos) throws Exception {
-    buf.position(bufPos);
-    int n = ((ReadableByteChannel) in).read(buf);
-    Assert.assertEquals(bufPos + n, buf.position());
-    byte[] readData = new byte[n];
-    buf.rewind();
-    buf.position(bufPos);
-    buf.get(readData);
-    byte[] expectedData = new byte[n];
-    System.arraycopy(data, 0, expectedData, 0, n);
-    Assert.assertArrayEquals(readData, expectedData);
-  }
-
-  private void prepareData() throws IOException {
-    Cipher cipher = null;
-    try {
-      cipher = (Cipher)ReflectionUtils.newInstance(
-          ReflectionUtils.getClassByName(jceCipherClass), props, transformation);
-    } catch (ClassNotFoundException cnfe) {
-      throw new IOException("Illegal crypto cipher!");
-    }
-
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    OutputStream out = new CryptoOutputStream(baos, cipher, defaultBufferSize, key, iv);
-    out.write(data);
-    out.flush();
-    out.close();
-    encData = baos.toByteArray();
-  }
-
-  protected CryptoInputStream getCryptoInputStream(ByteArrayInputStream bais,
-                                                   Cipher cipher,
-                                                   int bufferSize, byte[] iv,
-                                                   boolean withChannel) throws
-      IOException {
-    if (withChannel) {
-      return new CryptoInputStream(Channels.newChannel(bais), cipher,
-          bufferSize, key, iv);
-    } else {
-      return new CryptoInputStream(bais, cipher, bufferSize, key, iv);
-    }
-  }
-
-  protected CryptoOutputStream getCryptoOutputStream(ByteArrayOutputStream baos,
-                                                   Cipher cipher,
-                                                   int bufferSize, byte[] iv,
-                                                   boolean withChannel) throws
-      IOException {
-    if (withChannel) {
-      return new CryptoOutputStream(Channels.newChannel(baos), cipher,
-          bufferSize, key, iv);
-    } else {
-      return new CryptoOutputStream(baos, cipher, bufferSize, key, iv);
-    }
-  }
-
-  private int readAll(InputStream in, byte[] b, int offset, int len)
-      throws IOException {
-    int n = 0;
-    int total = 0;
-    while (n != -1) {
-      total += n;
-      if (total >= len) {
-        break;
-      }
-      n = in.read(b, offset + total, len - total);
-    }
-
-    return total;
-  }
-
-  protected Cipher getCipher(String cipherClass) throws IOException {
-    try {
-      return (Cipher)ReflectionUtils.newInstance(
-          ReflectionUtils.getClassByName(cipherClass), props, transformation);
-    } catch (ClassNotFoundException cnfe) {
-      throw new IOException("Illegal crypto cipher!");
-    }
-  }
-
-  @Test
-  public void testReadWrite() throws Exception {
-    Assert.assertEquals(null, Openssl.getLoadingFailureReason());
-    doReadWriteTest(0, jceCipherClass, jceCipherClass, iv);
-    doReadWriteTest(0, opensslCipherClass, opensslCipherClass, iv);
-    doReadWriteTest(count, jceCipherClass, jceCipherClass, iv);
-    doReadWriteTest(count, opensslCipherClass, opensslCipherClass, iv);
-    doReadWriteTest(count, jceCipherClass, opensslCipherClass, iv);
-    doReadWriteTest(count, opensslCipherClass, jceCipherClass, iv);
-    // Overflow test, IV: xx xx xx xx xx xx xx xx ff ff ff ff ff ff ff ff
-    for(int i = 0; i < 8; i++) {
-      iv[8 + i] = (byte) 0xff;
-    }
-    doReadWriteTest(count, jceCipherClass, jceCipherClass, iv);
-    doReadWriteTest(count, opensslCipherClass, opensslCipherClass, iv);
-    doReadWriteTest(count, jceCipherClass, opensslCipherClass, iv);
-    doReadWriteTest(count, opensslCipherClass, jceCipherClass, iv);
-  }
-
-  private void doReadWriteTest(int count, String encCipherClass,
-                               String decCipherClass, byte[] iv) throws IOException {
-    doReadWriteTestForInputStream(count, encCipherClass, decCipherClass, iv);
-    doReadWriteTestForReadableByteChannel(count, encCipherClass, decCipherClass,
-        iv);
-  }
-
-  private void doReadWriteTestForInputStream(int count, String encCipherClass,
-                                             String decCipherClass, byte[] iv) throws IOException {
-    Cipher encCipher = getCipher(encCipherClass);
-    LOG.debug("Created a cipher object of type: " + encCipherClass);
-
-    // Generate data
-    SecureRandom random = new SecureRandom();
-    byte[] originalData = new byte[count];
-    byte[] decryptedData = new byte[count];
-    random.nextBytes(originalData);
-    LOG.debug("Generated " + count + " records");
-
-    // Encrypt data
-    ByteArrayOutputStream encryptedData = new ByteArrayOutputStream();
-    CryptoOutputStream out =
-        getCryptoOutputStream(encryptedData, encCipher, defaultBufferSize, iv,
-            false);
-    out.write(originalData, 0, originalData.length);
-    out.flush();
-    out.close();
-    LOG.debug("Finished encrypting data");
-
-    Cipher decCipher = getCipher(decCipherClass);
-    LOG.debug("Created a cipher object of type: " + decCipherClass);
-
-    // Decrypt data
-    CryptoInputStream in = getCryptoInputStream(
-        new ByteArrayInputStream(encryptedData.toByteArray()), decCipher,
-        defaultBufferSize, iv, false);
-
-    // Check
-    int remainingToRead = count;
-    int offset = 0;
-    while (remainingToRead > 0) {
-      int n = in.read(decryptedData, offset, decryptedData.length - offset);
-      if (n >=0) {
-        remainingToRead -= n;
-        offset += n;
-      }
-    }
-
-    Assert.assertArrayEquals("originalData and decryptedData not equal",
-        originalData, decryptedData);
-
-    // Decrypt data byte-at-a-time
-    in = getCryptoInputStream(
-        new ByteArrayInputStream(encryptedData.toByteArray()), decCipher,
-        defaultBufferSize, iv, false);
-
-    // Check
-    DataInputStream originalIn = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(originalData)));
-    int expected;
-    do {
-      expected = originalIn.read();
-      Assert.assertEquals("Decrypted stream read by byte does not match",
-          expected, in.read());
-    } while (expected != -1);
-
-    LOG.debug("SUCCESS! Completed checking " + count + " records");
-  }
-
-  private void doReadWriteTestForReadableByteChannel(int count,
-                                                     String encCipherClass,
-                                                     String decCipherClass,
-                                                     byte[] iv) throws IOException {
-    Cipher encCipher = getCipher(encCipherClass);
-    LOG.debug("Created a cipher object of type: " + encCipherClass);
-
-    // Generate data
-    SecureRandom random = new SecureRandom();
-    byte[] originalData = new byte[count];
-    byte[] decryptedData = new byte[count];
-    random.nextBytes(originalData);
-    LOG.debug("Generated " + count + " records");
-
-    // Encrypt data
-    ByteArrayOutputStream encryptedData = new ByteArrayOutputStream();
-    CryptoOutputStream out =
-        getCryptoOutputStream(encryptedData, encCipher, defaultBufferSize, iv,
-            true);
-    out.write(originalData, 0, originalData.length);
-    out.flush();
-    out.close();
-    LOG.debug("Finished encrypting data");
-
-    Cipher decCipher = getCipher(decCipherClass);
-    LOG.debug("Created a cipher object of type: " + decCipherClass);
-
-    // Decrypt data
-    CryptoInputStream in = getCryptoInputStream(
-        new ByteArrayInputStream(encryptedData.toByteArray()), decCipher,
-        defaultBufferSize, iv, true);
-
-    // Check
-    int remainingToRead = count;
-    int offset = 0;
-    while (remainingToRead > 0) {
-      int n = in.read(decryptedData, offset, decryptedData.length - offset);
-      if (n >=0) {
-        remainingToRead -= n;
-        offset += n;
-      }
-    }
-
-    Assert.assertArrayEquals("originalData and decryptedData not equal",
-        originalData, decryptedData);
-
-    // Decrypt data byte-at-a-time
-    in = getCryptoInputStream(new ByteArrayInputStream(
-        encryptedData.toByteArray()),decCipher,defaultBufferSize,iv,true);
-
-    // Check
-    DataInputStream originalIn = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(originalData)));
-    int expected;
-    do {
-      expected = originalIn.read();
-      Assert.assertEquals("Decrypted stream read by byte does not match",
-          expected, in.read());
-    } while (expected != -1);
-
-    LOG.debug("SUCCESS! Completed checking " + count + " records");
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCipherStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCipherStreamTest.java
new file mode 100644
index 0000000..c8717ff
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCipherStreamTest.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.crypto.stream;
+
+import java.io.IOException;
+
+import org.apache.commons.crypto.cipher.CipherTransformation;
+
+public class CBCNoPaddingCipherStreamTest extends AbstractCipherStreamTest {
+
+  public void setUp() throws IOException {
+    transformation = CipherTransformation
+        .AES_CBC_NOPADDING;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCryptoStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCryptoStreamTest.java
deleted file mode 100644
index 743a3ac..0000000
--- a/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCryptoStreamTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.crypto.stream;
-
-import java.io.IOException;
-
-import org.apache.commons.crypto.cipher.CipherTransformation;
-
-public class CBCNoPaddingCryptoStreamTest extends AbstractCryptoStreamTest {
-
-  public void setUp() throws IOException {
-    transformation = CipherTransformation
-        .AES_CBC_NOPADDING;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCipherStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCipherStreamTest.java
new file mode 100644
index 0000000..ff34bc9
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCipherStreamTest.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.crypto.stream;
+
+import java.io.IOException;
+
+import org.apache.commons.crypto.cipher.CipherTransformation;
+
+public class CBCPKCS5PaddingCipherStreamTest extends AbstractCipherStreamTest {
+
+  public void setUp() throws IOException {
+    transformation = CipherTransformation
+        .AES_CBC_PKCS5PADDING;
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCryptoStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCryptoStreamTest.java
deleted file mode 100644
index cb65dac..0000000
--- a/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCryptoStreamTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.crypto.stream;
-
-import java.io.IOException;
-
-import org.apache.commons.crypto.cipher.CipherTransformation;
-
-public class CBCPKCS5PaddingCryptoStreamTest extends AbstractCryptoStreamTest {
-
-  public void setUp() throws IOException {
-    transformation = CipherTransformation
-        .AES_CBC_PKCS5PADDING;
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/CTRCipherStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CTRCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CTRCipherStreamTest.java
new file mode 100644
index 0000000..f5e85ff
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/stream/CTRCipherStreamTest.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.crypto.stream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.channels.Channels;
+
+import org.apache.commons.crypto.cipher.Cipher;
+import org.apache.commons.crypto.cipher.CipherTransformation;
+
+public class CTRCipherStreamTest extends AbstractCipherStreamTest {
+
+  public void setUp() throws IOException {
+    transformation = CipherTransformation
+        .AES_CTR_NOPADDING;
+  }
+
+  @Override
+  protected CTRCipherInputStream getCipherInputStream
+      (ByteArrayInputStream bais, Cipher cipher, int
+      bufferSize,byte[] iv, boolean withChannel)
+      throws IOException {
+    if (withChannel) {
+      return new CTRCipherInputStream(Channels.newChannel(bais), cipher,
+          bufferSize, key, iv);
+    } else {
+      return new CTRCipherInputStream(bais, cipher, bufferSize, key, iv);
+    }
+  }
+
+  @Override
+  protected CTRCipherOutputStream getCipherOutputStream(ByteArrayOutputStream baos, Cipher cipher, int
+      bufferSize, byte[] iv, boolean withChannel)
+      throws IOException {
+    if (withChannel) {
+      return new CTRCipherOutputStream(Channels.newChannel(baos), cipher, bufferSize, key, iv);
+    } else {
+      return new CTRCipherOutputStream(baos, cipher, bufferSize, key, iv);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java
deleted file mode 100644
index 1a50382..0000000
--- a/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.crypto.stream;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.channels.Channels;
-
-import org.apache.commons.crypto.cipher.Cipher;
-import org.apache.commons.crypto.cipher.CipherTransformation;
-
-public class CTRCryptoStreamTest extends AbstractCryptoStreamTest {
-
-  public void setUp() throws IOException {
-    transformation = CipherTransformation
-        .AES_CTR_NOPADDING;
-  }
-
-  @Override
-  protected CTRCryptoInputStream getCryptoInputStream
-      (ByteArrayInputStream bais, Cipher cipher, int
-      bufferSize,byte[] iv, boolean withChannel)
-      throws IOException {
-    if (withChannel) {
-      return new CTRCryptoInputStream(Channels.newChannel(bais), cipher,
-          bufferSize, key, iv);
-    } else {
-      return new CTRCryptoInputStream(bais, cipher, bufferSize, key, iv);
-    }
-  }
-
-  @Override
-  protected CTRCryptoOutputStream getCryptoOutputStream(ByteArrayOutputStream baos,Cipher cipher, int
-      bufferSize,  byte[] iv, boolean withChannel)
-      throws IOException {
-    if (withChannel) {
-      return new CTRCryptoOutputStream(Channels.newChannel(baos), cipher, bufferSize, key, iv);
-    } else {
-      return new CTRCryptoOutputStream(baos, cipher, bufferSize, key, iv);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCipherStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCipherStreamTest.java
new file mode 100644
index 0000000..b59761d
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCipherStreamTest.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.crypto.stream;
+
+import java.io.IOException;
+
+import org.apache.commons.crypto.cipher.CipherTransformation;
+
+public class CTRNoPaddingCipherStreamTest extends AbstractCipherStreamTest {
+
+  public void setUp() throws IOException {
+    transformation = CipherTransformation
+        .AES_CTR_NOPADDING;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ad81d236/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCryptoStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCryptoStreamTest.java
deleted file mode 100644
index 1bbf600..0000000
--- a/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCryptoStreamTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.crypto.stream;
-
-import java.io.IOException;
-
-import org.apache.commons.crypto.cipher.CipherTransformation;
-
-public class CTRNoPaddingCryptoStreamTest extends AbstractCryptoStreamTest {
-
-  public void setUp() throws IOException {
-    transformation = CipherTransformation
-        .AES_CTR_NOPADDING;
-  }
-
-}