You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by sd...@apache.org on 2016/04/29 11:11:10 UTC

[3/5] commons-crypto git commit: CRYPTO-33: avoid shadowing JVM class renaming Cipher/Stream/Random classes

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/stream/CipherOutputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/CipherOutputStream.java b/src/main/java/org/apache/commons/crypto/stream/CipherOutputStream.java
deleted file mode 100644
index 57a0e1b..0000000
--- a/src/main/java/org/apache/commons/crypto/stream/CipherOutputStream.java
+++ /dev/null
@@ -1,438 +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.Channel;
-import java.nio.channels.WritableByteChannel;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Properties;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.ShortBufferException;
-import javax.crypto.spec.IvParameterSpec;
-
-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;
-
-/**
- * {@link CipherOutputStream} 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 CipherOutputStream extends OutputStream implements
-    WritableByteChannel {
-  private final byte[] oneByteBuf = new byte[1];
-
-  /** The output.*/
-  Output output;
-
-  /**the Cipher instance*/
-  final Cipher cipher;
-
-  /**The buffer size.*/
-  final int bufferSize;
-
-  /**Crypto key for the cipher.*/
-  final Key key;
-
-  /** the algorithm parameters */
-  final AlgorithmParameterSpec params;
-
-  /** Flag to mark whether the output stream is closed.*/
-  private boolean closed;
-
-  /**
-   * Input data buffer. The data starts at inBuffer.position() and ends at
-   * inBuffer.limit().
-   */
-  ByteBuffer inBuffer;
-
-  /**
-   * Encrypted data buffer. The data starts at outBuffer.position() and ends at
-   * outBuffer.limit().
-   */
-  ByteBuffer outBuffer;
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CipherOutputStream}.
-   *
-   * @param transformation the CipherTransformation instance.
-   * @param props The <code>Properties</code> class represents a set of
-   *              properties.
-   * @param out the output stream.
-   * @param key crypto key for the cipher.
-   * @param params the algorithm parameters.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CipherOutputStream(
-    CipherTransformation transformation,
-    Properties props,
-    OutputStream out,
-    Key key,
-    AlgorithmParameterSpec params) throws IOException {
-    this(out, Utils.getCipherInstance(transformation, props), Utils.getBufferSize(props), key,
-      params);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CipherOutputStream}.
-   *
-   * @param transformation the CipherTransformation instance.
-   * @param props The <code>Properties</code> class represents a set of
-   *              properties.
-   * @param out the WritableByteChannel instance.
-   * @param key crypto key for the cipher.
-   * @param params the algorithm parameters.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CipherOutputStream(
-    CipherTransformation transformation,
-    Properties props,
-    WritableByteChannel out,
-    Key key,
-    AlgorithmParameterSpec params) throws IOException {
-    this(out, Utils.getCipherInstance(transformation, props), Utils.getBufferSize(props), key,
-      params);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CipherOutputStream}.
-   *
-   * @param out the output stream.
-   * @param cipher the Cipher instance.
-   * @param bufferSize the bufferSize.
-   * @param key crypto key for the cipher.
-   * @param params the algorithm parameters.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CipherOutputStream(OutputStream out, Cipher cipher, int bufferSize,
-                            Key key, AlgorithmParameterSpec params) throws IOException {
-    this(new StreamOutput(out, bufferSize), cipher, bufferSize, key, params);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CipherOutputStream}.
-   *
-   * @param channel the WritableByteChannel instance.
-   * @param cipher the cipher instance.
-   * @param bufferSize the bufferSize.
-   * @param key crypto key for the cipher.
-   * @param params the algorithm parameters.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CipherOutputStream(WritableByteChannel channel, Cipher cipher,
-                            int bufferSize, Key key, AlgorithmParameterSpec params) throws IOException {
-    this(new ChannelOutput(channel), cipher, bufferSize, key, params);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CipherOutputStream}.
-   *
-   * @param output the output stream.
-   * @param cipher the Cipher instance.
-   * @param bufferSize the bufferSize.
-   * @param key crypto key for the cipher.
-   * @param params the algorithm parameters.
-   * @throws IOException if an I/O error occurs.
-   */
-  protected CipherOutputStream(Output output, Cipher cipher, int bufferSize,
-                               Key key, AlgorithmParameterSpec params)
-      throws IOException {
-
-    this.output = output;
-    this.bufferSize = Utils.checkBufferSize(cipher, bufferSize);
-    this.cipher = cipher;
-
-    this.key = key;
-    this.params = params;
-
-    if (!(params instanceof IvParameterSpec)) {
-      //other AlgorithmParameterSpec such as GCMParameterSpec is not supported now.
-      throw new IOException("Illegal parameters");
-    }
-
-    inBuffer = ByteBuffer.allocateDirect(this.bufferSize);
-    outBuffer = ByteBuffer.allocateDirect(this.bufferSize +
-        cipher.getTransformation().getAlgorithmBlockSize());
-
-    initCipher();
-  }
-
-  /**
-   * Overrides the {@link java.io.OutputStream#write(byte[])}.
-   * Writes the specified byte to this output stream.
-   *
-   * @param b the data.
-   * @throws IOException if an I/O error occurs.
-   */
-  @Override
-  public void write(int b) throws IOException {
-    oneByteBuf[0] = (byte) (b & 0xff);
-    write(oneByteBuf, 0, oneByteBuf.length);
-  }
-
-  /**
-   * Overrides the {@link java.io.OutputStream#write(byte[], int, int)}.
-   * 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 if an I/O error occurs.
-   */
-  @Override
-  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();
-      }
-    }
-  }
-
-  /**
-   * Overrides the {@link OutputStream#flush()}.
-   * To flush, we need to encrypt the data in the buffer and write to the
-   * underlying stream, then do the flush.
-   *
-   * @throws IOException if an I/O error occurs.
-   */
-  @Override
-  public void flush() throws IOException {
-    checkStream();
-    encrypt();
-    output.flush();
-    super.flush();
-  }
-
-  /**
-   * Overrides the {@link OutputStream#close()}.
-   * Closes this output stream and releases any system resources
-   * associated with this stream.
-   *
-   * @throws IOException if an I/O error occurs.
-   */
-  @Override
-  public void close() throws IOException {
-    if (closed) {
-      return;
-    }
-
-    try {
-      encryptFinal();
-      output.close();
-      freeBuffers();
-      cipher.close();
-      super.close();
-    } finally {
-      closed = true;
-    }
-  }
-
-  /**
-   * Overrides the {@link Channel#isOpen()}.
-   * Tells whether or not this channel is open.
-   *
-   * @return <tt>true</tt> if, and only if, this channel is open
-   */
-  @Override
-  public boolean isOpen() {
-    return !closed;
-  }
-
-  /**
-   * Overrides the {@link java.nio.channels.WritableByteChannel#write(ByteBuffer)}.
-   * Writes a sequence of bytes to this channel from the given buffer.
-   *
-   * @param src The buffer from which bytes are to be retrieved.
-   * @return The number of bytes written, possibly zero.
-   * @throws IOException if an I/O error occurs.
-   */
-  @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;
-  }
-
-  /**
-   * Initializes the cipher.
-   *
-   * @throws IOException if an I/O error occurs.
-   */
-  protected void initCipher()
-      throws IOException {
-    try {
-      cipher.init(Cipher.ENCRYPT_MODE, key, params);
-    } catch (InvalidKeyException e) {
-      throw new IOException(e);
-    } catch(InvalidAlgorithmParameterException e) {
-      throw new IOException(e);
-    }
-  }
-
-  /**
-   * Does the encryption, input is {@link #inBuffer} and output is
-   * {@link #outBuffer}.
-   *
-   *@throws IOException if an I/O error occurs.
-   */
-  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);
-  }
-
-  /**
-   * Does final encryption of the last data.
-   *
-   * @throws IOException if an I/O error occurs.
-   */
-  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);
-  }
-
-  /**
-   * Gets the outBuffer.
-   *
-   * @return the outBuffer.
-   */
-  protected ByteBuffer getOutBuffer() {
-    return outBuffer;
-  }
-
-  /**
-   * Gets the internal Cipher.
-   *
-   * @return the cipher instance.
-   */
-  protected Cipher getCipher() {
-    return cipher;
-  }
-
-  /**
-   * Gets the buffer size.
-   *
-   * @return the buffer size.
-   */
-  protected int getBufferSize() {
-    return bufferSize;
-  }
-
-  /**
-   * Gets the inBuffer.
-   *
-   * @return the inBuffer.
-   */
-  protected ByteBuffer getInBuffer() {
-    return inBuffer;
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java b/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java
new file mode 100644
index 0000000..2d62a76
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java
@@ -0,0 +1,559 @@
+/**
+ * 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.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channel;
+import java.nio.channels.ReadableByteChannel;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Properties;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+import org.apache.commons.crypto.cipher.CryptoCipher;
+import org.apache.commons.crypto.cipher.CipherTransformation;
+import org.apache.commons.crypto.stream.input.ChannelInput;
+import org.apache.commons.crypto.stream.input.Input;
+import org.apache.commons.crypto.stream.input.StreamInput;
+import org.apache.commons.crypto.utils.Utils;
+
+/**
+ * CryptoInputStream reads input data and decrypts data in stream manner. It supports
+ * any mode of operations such as AES CBC/CTR/GCM mode in concept.It is not thread-safe.
+ *
+ */
+
+public class CryptoInputStream extends InputStream implements
+    ReadableByteChannel {
+  private final byte[] oneByteBuf = new byte[1];
+
+  /**The CryptoCipher instance.*/
+  final CryptoCipher cipher;
+
+  /**The buffer size.*/
+  final int bufferSize;
+
+  /**Crypto key for the cipher.*/
+  final Key key;
+
+  /** the algorithm parameters */
+  final AlgorithmParameterSpec params;
+
+  /** Flag to mark whether the input stream is closed.*/
+  private boolean closed;
+
+  /** Flag to mark whether do final of the cipher to end the decrypting stream.*/
+  private boolean finalDone = false;
+
+  /**The input data.*/
+  Input input;
+
+  /**
+   * Input data buffer. The data starts at inBuffer.position() and ends at
+   * to inBuffer.limit().
+   */
+  protected ByteBuffer inBuffer;
+
+  /**
+   * The decrypted data buffer. The data starts at outBuffer.position() and
+   * ends at outBuffer.limit().
+   */
+  protected ByteBuffer outBuffer;
+
+  /**
+   * Constructs a {@link CryptoInputStream}.
+   *
+   * @param transformation the CipherTransformation instance.
+   * @param props The <code>Properties</code> class represents a set of
+   *              properties.
+   * @param in the input stream.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CryptoInputStream(CipherTransformation transformation,
+                           Properties props, InputStream in, Key key, AlgorithmParameterSpec params)
+      throws IOException {
+    this(in, Utils.getCipherInstance(transformation, props), Utils.getBufferSize(props), key,
+      params);
+  }
+
+  /**
+   * Constructs a {@link CryptoInputStream}.
+   *
+   * @param transformation the CipherTransformation instance.
+   * @param props The <code>Properties</code> class represents a set of
+   *              properties.
+   * @param in the ReadableByteChannel object.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CryptoInputStream(CipherTransformation transformation,
+                           Properties props, ReadableByteChannel in, Key key, AlgorithmParameterSpec params)
+      throws IOException {
+    this(in, Utils.getCipherInstance(transformation, props),
+        Utils.getBufferSize(props), key, params);
+  }
+
+  /**
+   * Constructs a {@link CryptoInputStream}.
+   *
+   * @param cipher the cipher instance.
+   * @param in the input stream.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CryptoInputStream(InputStream in, CryptoCipher cipher, int bufferSize,
+                           Key key, AlgorithmParameterSpec params) throws IOException {
+    this(new StreamInput(in, bufferSize), cipher, bufferSize, key, params);
+  }
+
+  /**
+   * Constructs a {@link CryptoInputStream}.
+   *
+   * @param in the ReadableByteChannel instance.
+   * @param cipher the cipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CryptoInputStream(ReadableByteChannel in, CryptoCipher cipher,
+                           int bufferSize, Key key, AlgorithmParameterSpec params) throws IOException {
+    this(new ChannelInput(in), cipher, bufferSize, key, params);
+  }
+
+  /**
+   * Constructs a {@link CryptoInputStream}.
+   *
+   * @param input the input data.
+   * @param cipher the cipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CryptoInputStream(Input input, CryptoCipher cipher, int bufferSize,
+                           Key key, AlgorithmParameterSpec params) throws IOException {
+    this.input = input;
+    this.cipher = cipher;
+    this.bufferSize = Utils.checkBufferSize(cipher, bufferSize);
+
+    this.key = key;
+    this.params = params;
+    if (!(params instanceof IvParameterSpec)) {
+      //other AlgorithmParameterSpec such as GCMParameterSpec is not supported now.
+      throw new IOException("Illegal parameters");
+    }
+
+    inBuffer = ByteBuffer.allocateDirect(this.bufferSize);
+    outBuffer = ByteBuffer.allocateDirect(this.bufferSize +
+        cipher.getTransformation().getAlgorithmBlockSize());
+    outBuffer.limit(0);
+
+    initCipher();
+  }
+
+  /**
+   * Overrides the {@link java.io.InputStream#read()}.
+   * Reads the next byte of data from the input stream.
+   *
+   * @return the next byte of data, or <code>-1</code> if the end of the
+   *         stream is reached.
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public int read() throws IOException {
+    int n;
+    while ((n = read(oneByteBuf, 0, 1)) == 0) ;
+    return (n == -1) ? -1 : oneByteBuf[0] & 0xff;
+  }
+
+  /**
+   * Overrides the {@link java.io.InputStream#read(byte[], int, int)}.
+   * Decryption is buffer based.
+   * If there is data in {@link #outBuffer}, then read it out of this buffer.
+   * If there is no data in {@link #outBuffer}, then read more from the
+   * underlying stream and do the decryption.
+   *
+   * @param b the buffer into which the decrypted data is read.
+   * @param off the buffer offset.
+   * @param len the maximum number of decrypted data bytes to read.
+   * @return int the total number of decrypted data bytes read into the buffer.
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public int read(byte[] b, int off, int len) throws IOException {
+    checkStream();
+    if (b == null) {
+      throw new NullPointerException();
+    } else if (off < 0 || len < 0 || len > b.length - off) {
+      throw new IndexOutOfBoundsException();
+    } else if (len == 0) {
+      return 0;
+    }
+
+    int remaining = outBuffer.remaining();
+    if (remaining > 0) {
+      // Satisfy the read with the existing data
+      int n = Math.min(len, remaining);
+      outBuffer.get(b, off, n);
+      return n;
+    } else {
+      // No data in the out buffer, try read new data and decrypt it
+      int nd = decryptMore();
+      if(nd <= 0)
+        return nd;
+
+      int n = Math.min(len, outBuffer.remaining());
+      outBuffer.get(b, off, n);
+      return n;
+    }
+  }
+
+  /**
+   * Overrides the {@link java.io.InputStream#skip(long)}.
+   * Skips over and discards <code>n</code> bytes of data from this input
+   * stream.
+   *
+   * @param n the number of bytes to be skipped.
+   * @return the actual number of bytes skipped.
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public long skip(long n) throws IOException {
+    Utils.checkArgument(n >= 0, "Negative skip length.");
+    checkStream();
+
+    if (n == 0) {
+      return 0;
+    }
+
+    long remaining = n;
+    int nd;
+
+    while (remaining > 0) {
+      if(remaining <= outBuffer.remaining()) {
+        // Skip in the remaining buffer
+        int pos = outBuffer.position() + (int) remaining;
+        outBuffer.position(pos);
+
+        remaining = 0;
+        break;
+      } else {
+        remaining -= outBuffer.remaining();
+        outBuffer.clear();
+      }
+
+      nd = decryptMore();
+      if (nd < 0) {
+        break;
+      }
+    }
+
+    return n - remaining;
+  }
+
+  /**
+   * Overrides the {@link InputStream#available()}.
+   * Returns an estimate of the number of bytes that can be read (or
+   * skipped over) from this input stream without blocking by the next
+   * invocation of a method for this input stream.
+   *
+   * @return an estimate of the number of bytes that can be read (or skipped
+   *         over) from this input stream without blocking or {@code 0} when
+   *          it reaches the end of the input stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public int available() throws IOException {
+    checkStream();
+
+    return input.available() + outBuffer.remaining();
+  }
+
+  /**
+   * Overrides the {@link InputStream#close()}.
+   * Closes this input stream and releases any system resources associated
+   * with the stream.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public void close() throws IOException {
+    if (closed) {
+      return;
+    }
+
+    input.close();
+    freeBuffers();
+    cipher.close();
+    super.close();
+    closed = true;
+  }
+
+  /**
+   * Overrides the {@link java.io.InputStream#mark(int)}.
+   * For {@link CryptoInputStream},we don't support the mark method.
+   *
+   * @param readlimit the maximum limit of bytes that can be read before
+   *                  the mark position becomes invalid.
+   */
+  @Override
+  public void mark(int readlimit) {
+  }
+
+  /**
+   * Overrides the {@link InputStream#reset()}.
+   * For {@link CryptoInputStream},we don't support the reset method.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public void reset() throws IOException {
+    throw new IOException("Mark/reset not supported");
+  }
+
+  /**
+   * Overrides the {@link InputStream#markSupported()}.
+   *
+   * @return false,the {@link CTRCipherInputStream} don't support the mark method.
+   */
+  @Override
+  public boolean markSupported() {
+    return false;
+  }
+
+  /**
+   * Overrides the {@link Channel#isOpen()}.
+   *
+   * @return <tt>true</tt> if, and only if, this channel is open.
+   */
+  @Override
+  public boolean isOpen() {
+    return !closed;
+  }
+
+  /**
+   * Overrides the {@link java.nio.channels.ReadableByteChannel#read(ByteBuffer)}.
+   * Reads a sequence of bytes from this channel into the given buffer.
+   *
+   * @param dst The buffer into which bytes are to be transferred.
+   * @return The number of bytes read, possibly zero, or <tt>-1</tt> if the
+   *         channel has reached end-of-stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public int read(ByteBuffer dst) throws IOException {
+    checkStream();
+    int remaining = outBuffer.remaining();
+    if (remaining <= 0) {
+      // Decrypt more data
+      int nd = decryptMore();
+      if(nd < 0) {
+        return -1;
+      }
+    }
+
+    // Copy decrypted data from outBuffer to dst
+    remaining = outBuffer.remaining();
+    final int toRead = dst.remaining();
+    if (toRead <= remaining) {
+      final int limit = outBuffer.limit();
+      outBuffer.limit(outBuffer.position() + toRead);
+      dst.put(outBuffer);
+      outBuffer.limit(limit);
+      return toRead;
+    } else {
+      dst.put(outBuffer);
+      return remaining;
+    }
+  }
+
+  /**
+   * Gets the buffer size.
+   *
+   * @return the bufferSize.
+   */
+  protected int getBufferSize() {
+    return bufferSize;
+  }
+
+  /**
+   * Gets the key.
+   *
+   * @return the key.
+   */
+  protected Key getKey() {
+    return key;
+  }
+
+
+  /**
+   * Gets the internal CryptoCipher.
+   *
+   * @return the cipher instance.
+   */
+  protected CryptoCipher getCipher() {
+    return cipher;
+  }
+
+  /**
+   * Gets the specification of cryptographic parameters.
+   *
+   * @return the params.
+   */
+  protected AlgorithmParameterSpec getParams() {
+    return params;
+  }
+
+  /**
+   * Gets the input.
+   *
+   * @return the input.
+   */
+  protected Input getInput() {
+    return input;
+  }
+
+  /**
+   * Initializes the cipher.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  protected void initCipher()
+      throws IOException {
+    try {
+      cipher.init(CryptoCipher.DECRYPT_MODE, key, params);
+    } catch (InvalidKeyException e) {
+      throw new IOException(e);
+    } catch(InvalidAlgorithmParameterException e) {
+      throw new IOException(e);
+    }
+  }
+
+  /**
+   * Decrypts more data by reading the under layer stream. The decrypted data will
+   * be put in the output buffer. If the end of the under stream reached, we will
+   * do final of the cipher to finish all the decrypting of data.
+   *
+   * @return The number of decrypted data. -1 if end of the decrypted stream.
+   */
+  protected int decryptMore() throws IOException {
+    if(finalDone) {
+      return -1;
+    }
+
+    int n = input.read(inBuffer);
+    if (n < 0) {
+      // The stream is end, finalize the cipher stream
+      decryptFinal();
+
+      // Satisfy the read with the remaining
+      int remaining = outBuffer.remaining();
+      if (remaining > 0) {
+        return remaining;
+      }
+
+      // End of the stream
+      return -1;
+    } else if(n == 0) {
+      // No data is read, but the stream is not end yet
+      return 0;
+    } else {
+      decrypt();
+      return outBuffer.remaining();
+    }
+  }
+
+  /**
+   * Does 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().
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  protected void decrypt() throws IOException {
+    // Prepare the input buffer and clear the out buffer
+    inBuffer.flip();
+    outBuffer.clear();
+
+    try {
+      cipher.update(inBuffer, outBuffer);
+    } catch (ShortBufferException e) {
+      throw new IOException(e);
+    }
+
+    // Clear the input buffer and prepare out buffer
+    inBuffer.clear();
+    outBuffer.flip();
+  }
+
+  /**
+   * Does final of the cipher to end the decrypting stream.
+   *
+   *@throws IOException if an I/O error occurs.
+   */
+  protected void decryptFinal() throws IOException {
+    // Prepare the input buffer and clear the out buffer
+    inBuffer.flip();
+    outBuffer.clear();
+
+    try {
+      cipher.doFinal(inBuffer, outBuffer);
+      finalDone = true;
+    } catch (ShortBufferException e) {
+      throw new IOException(e);
+    } catch (IllegalBlockSizeException e) {
+      throw new IOException(e);
+    } catch( BadPaddingException e) {
+      throw new IOException(e);
+    }
+
+    // Clear the input buffer and prepare out buffer
+    inBuffer.clear();
+    outBuffer.flip();
+  }
+
+  /**
+   * Checks whether the stream is closed.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  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/ea89d802/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
new file mode 100644
index 0000000..7735385
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java
@@ -0,0 +1,441 @@
+/**
+ * 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.Channel;
+import java.nio.channels.WritableByteChannel;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Properties;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+import org.apache.commons.crypto.cipher.CryptoCipher;
+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;
+
+/**
+ * {@link 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];
+
+  /** The output.*/
+  Output output;
+
+  /**the CryptoCipher instance*/
+  final CryptoCipher cipher;
+
+  /**The buffer size.*/
+  final int bufferSize;
+
+  /**Crypto key for the cipher.*/
+  final Key key;
+
+  /** the algorithm parameters */
+  final AlgorithmParameterSpec params;
+
+  /** Flag to mark whether the output stream is closed.*/
+  private boolean closed;
+
+  /**
+   * Input data buffer. The data starts at inBuffer.position() and ends at
+   * inBuffer.limit().
+   */
+  ByteBuffer inBuffer;
+
+  /**
+   * Encrypted data buffer. The data starts at outBuffer.position() and ends at
+   * outBuffer.limit().
+   */
+  ByteBuffer outBuffer;
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CryptoOutputStream}.
+   *
+   * @param transformation the CipherTransformation instance.
+   * @param props The <code>Properties</code> class represents a set of
+   *              properties.
+   * @param out the output stream.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+
+
+  public CryptoOutputStream(
+    CipherTransformation transformation,
+    Properties props,
+    OutputStream out,
+    Key key,
+    AlgorithmParameterSpec params) throws IOException {
+    this(out, Utils.getCipherInstance(transformation, props), Utils.getBufferSize(props), key, params);
+
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CryptoOutputStream}.
+   *
+   * @param transformation the CipherTransformation instance.
+   * @param props The <code>Properties</code> class represents a set of
+   *              properties.
+   * @param out the WritableByteChannel instance.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CryptoOutputStream(
+    CipherTransformation transformation,
+    Properties props,
+    WritableByteChannel out,
+    Key key,
+    AlgorithmParameterSpec params) throws IOException {
+    this(out, Utils.getCipherInstance(transformation, props),
+        Utils.getBufferSize(props), key, params);
+
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CryptoOutputStream}.
+   *
+   * @param out the output stream.
+   * @param cipher the CryptoCipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CryptoOutputStream(OutputStream out, CryptoCipher cipher, int bufferSize,
+                            Key key, AlgorithmParameterSpec params) throws IOException {
+    this(new StreamOutput(out, bufferSize), cipher, bufferSize, key, params);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CryptoOutputStream}.
+   *
+   * @param channel the WritableByteChannel instance.
+   * @param cipher the cipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CryptoOutputStream(WritableByteChannel channel, CryptoCipher cipher,
+                            int bufferSize, Key key, AlgorithmParameterSpec params) throws IOException {
+    this(new ChannelOutput(channel), cipher, bufferSize, key, params);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CryptoOutputStream}.
+   *
+   * @param output the output stream.
+   * @param cipher the CryptoCipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param params the algorithm parameters.
+   * @throws IOException if an I/O error occurs.
+   */
+  protected CryptoOutputStream(Output output, CryptoCipher cipher, int bufferSize,
+                               Key key, AlgorithmParameterSpec params)
+      throws IOException {
+
+    this.output = output;
+    this.bufferSize = Utils.checkBufferSize(cipher, bufferSize);
+    this.cipher = cipher;
+
+    this.key = key;
+    this.params = params;
+
+    if (!(params instanceof IvParameterSpec)) {
+      //other AlgorithmParameterSpec such as GCMParameterSpec is not supported now.
+      throw new IOException("Illegal parameters");
+    }
+
+    inBuffer = ByteBuffer.allocateDirect(this.bufferSize);
+    outBuffer = ByteBuffer.allocateDirect(this.bufferSize +
+        cipher.getTransformation().getAlgorithmBlockSize());
+
+    initCipher();
+  }
+
+  /**
+   * Overrides the {@link java.io.OutputStream#write(byte[])}.
+   * Writes the specified byte to this output stream.
+   *
+   * @param b the data.
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public void write(int b) throws IOException {
+    oneByteBuf[0] = (byte) (b & 0xff);
+    write(oneByteBuf, 0, oneByteBuf.length);
+  }
+
+  /**
+   * Overrides the {@link java.io.OutputStream#write(byte[], int, int)}.
+   * 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 if an I/O error occurs.
+   */
+  @Override
+  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();
+      }
+    }
+  }
+
+  /**
+   * Overrides the {@link OutputStream#flush()}.
+   * To flush, we need to encrypt the data in the buffer and write to the
+   * underlying stream, then do the flush.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public void flush() throws IOException {
+    checkStream();
+    encrypt();
+    output.flush();
+    super.flush();
+  }
+
+  /**
+   * Overrides the {@link OutputStream#close()}.
+   * Closes this output stream and releases any system resources
+   * associated with this stream.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  public void close() throws IOException {
+    if (closed) {
+      return;
+    }
+
+    try {
+      encryptFinal();
+      output.close();
+      freeBuffers();
+      cipher.close();
+      super.close();
+    } finally {
+      closed = true;
+    }
+  }
+
+  /**
+   * Overrides the {@link Channel#isOpen()}.
+   * Tells whether or not this channel is open.
+   *
+   * @return <tt>true</tt> if, and only if, this channel is open
+   */
+  @Override
+  public boolean isOpen() {
+    return !closed;
+  }
+
+  /**
+   * Overrides the {@link java.nio.channels.WritableByteChannel#write(ByteBuffer)}.
+   * Writes a sequence of bytes to this channel from the given buffer.
+   *
+   * @param src The buffer from which bytes are to be retrieved.
+   * @return The number of bytes written, possibly zero.
+   * @throws IOException if an I/O error occurs.
+   */
+  @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;
+  }
+
+  /**
+   * Initializes the cipher.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  protected void initCipher()
+      throws IOException {
+    try {
+      cipher.init(CryptoCipher.ENCRYPT_MODE, key, params);
+    } catch (InvalidKeyException e) {
+      throw new IOException(e);
+    } catch(InvalidAlgorithmParameterException e) {
+      throw new IOException(e);
+    }
+  }
+
+  /**
+   * Does the encryption, input is {@link #inBuffer} and output is
+   * {@link #outBuffer}.
+   *
+   *@throws IOException if an I/O error occurs.
+   */
+  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);
+  }
+
+  /**
+   * Does final encryption of the last data.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  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);
+  }
+
+  /**
+   * Gets the outBuffer.
+   *
+   * @return the outBuffer.
+   */
+  protected ByteBuffer getOutBuffer() {
+    return outBuffer;
+  }
+
+  /**
+   * Gets the internal Cipher.
+   *
+   * @return the cipher instance.
+   */
+  protected CryptoCipher getCipher() {
+    return cipher;
+  }
+
+  /**
+   * Gets the buffer size.
+   *
+   * @return the buffer size.
+   */
+  protected int getBufferSize() {
+    return bufferSize;
+  }
+
+  /**
+   * Gets the inBuffer.
+   *
+   * @return the inBuffer.
+   */
+  protected ByteBuffer getInBuffer() {
+    return inBuffer;
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/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
deleted file mode 100644
index 0a7c09b..0000000
--- a/src/main/java/org/apache/commons/crypto/stream/PositionedCipherInputStream.java
+++ /dev/null
@@ -1,362 +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 javax.crypto.spec.IvParameterSpec;
-
-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>();
-
-  /**
-   * Constructs a {@link PositionedCipherInputStream}.
-   *
-   * @param props The <code>Properties</code> class represents a set of
-   *              properties.
-   * @param in the input data.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @param streamOffset the start offset in the data.
-   * @throws IOException if an I/O error occurs.
-   */
-  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);
-  }
-
-  /**
-   * Constructs a {@link PositionedCipherInputStream}.
-   *
-   * @param input the input data.
-   * @param cipher the Cipher instance.
-   * @param bufferSize the bufferSize.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @param streamOffset the start offset in the data.
-   * @throws IOException if an I/O error occurs.
-   */
-  public PositionedCipherInputStream(Input input, Cipher cipher, int bufferSize,
-                                     byte[] key, byte[] iv, long streamOffset) throws IOException {
-    super(input, cipher, bufferSize, key, iv, streamOffset);
-  }
-
-  /**
-   * Reads up to 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.
-   *
-   * @param buffer the buffer into which the data is read.
-   * @param length the maximum number of bytes to read.
-   * @param offset the start offset in the data.
-   * @param position the offset from the start of the stream.
-   * @throws IOException if an I/O error occurs.
-   */
-  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;
-  }
-
-  /**
-   * Reads 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.
-   *
-   * @param buffer the buffer into which the data is read.
-   * @param length the maximum number of bytes to read.
-   * @param offset the start offset in the data.
-   * @param position the offset from the start of the stream.
-   * @throws IOException if an I/O error occurs.
-   */
-  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);
-    }
-  }
-
-  /**
-   * Reads 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.
-   *
-   * @param position the offset from the start of the stream.
-   * @param buffer the buffer into which the data is read.
-   * @throws IOException if an I/O error occurs.
-   */
-  public void readFully(long position, byte[] buffer) throws IOException {
-    readFully(position, buffer, 0, buffer.length);
-  }
-
-  /**
-   * Decrypts length bytes in buffer starting at offset. Output is also put
-   * into buffer starting at offset. It is thread-safe.
-   *
-   * @param buffer the buffer into which the data is read.
-   * @param offset the start offset in the data.
-   * @param position the offset from the start of the stream.
-   * @param length the maximum number of bytes to read.
-   * @throws IOException if an I/O error occurs.
-   */
-  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);
-    }
-  }
-
-  /**
-   * Does 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, key, new IvParameterSpec(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);
-    }
-  }
-
-  /**
-   * Overrides the {@link CipherInputStream#close()}.
-   * Closes this input stream and releases any system resources associated
-   * with the stream.
-   *
-   * @throws IOException if an I/O error occurs.
-   */
-  @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/ea89d802/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
new file mode 100644
index 0000000..7efbec6
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java
@@ -0,0 +1,362 @@
+/**
+ * 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 javax.crypto.spec.IvParameterSpec;
+
+import org.apache.commons.crypto.cipher.CryptoCipher;
+import org.apache.commons.crypto.cipher.CryptoCipherFactory;
+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>();
+
+  /**
+   * CryptoCipher pool
+   */
+  private final Queue<CipherState> cipherPool = new
+      ConcurrentLinkedQueue<CipherState>();
+
+  /**
+   * Constructs a {@link PositionedCryptoInputStream}.
+   *
+   * @param props The <code>Properties</code> class represents a set of
+   *              properties.
+   * @param in the input data.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @param streamOffset the start offset in the data.
+   * @throws IOException if an I/O error occurs.
+   */
+  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);
+  }
+
+  /**
+   * Constructs a {@link PositionedCryptoInputStream}.
+   *
+   * @param input the input data.
+   * @param cipher the CryptoCipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @param streamOffset the start offset in the data.
+   * @throws IOException if an I/O error occurs.
+   */
+  public PositionedCryptoInputStream(Input input, CryptoCipher cipher, int bufferSize,
+                                     byte[] key, byte[] iv, long streamOffset) throws IOException {
+    super(input, cipher, bufferSize, key, iv, streamOffset);
+  }
+
+  /**
+   * Reads up to 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.
+   *
+   * @param buffer the buffer into which the data is read.
+   * @param length the maximum number of bytes to read.
+   * @param offset the start offset in the data.
+   * @param position the offset from the start of the stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  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;
+  }
+
+  /**
+   * Reads 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.
+   *
+   * @param buffer the buffer into which the data is read.
+   * @param length the maximum number of bytes to read.
+   * @param offset the start offset in the data.
+   * @param position the offset from the start of the stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  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);
+    }
+  }
+
+  /**
+   * Reads 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.
+   *
+   * @param position the offset from the start of the stream.
+   * @param buffer the buffer into which the data is read.
+   * @throws IOException if an I/O error occurs.
+   */
+  public void readFully(long position, byte[] buffer) throws IOException {
+    readFully(position, buffer, 0, buffer.length);
+  }
+
+  /**
+   * Decrypts length bytes in buffer starting at offset. Output is also put
+   * into buffer starting at offset. It is thread-safe.
+   *
+   * @param buffer the buffer into which the data is read.
+   * @param offset the start offset in the data.
+   * @param position the offset from the start of the stream.
+   * @param length the maximum number of bytes to read.
+   * @throws IOException if an I/O error occurs.
+   */
+  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);
+    }
+  }
+
+  /**
+   * Does 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. CryptoCipher#update will consume all
+         * input data and put result in outBuffer.
+         * CryptoCipher#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(CryptoCipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
+    } catch (InvalidKeyException e) {
+      throw new IOException(e);
+    } catch (InvalidAlgorithmParameterException e) {
+      throw new IOException(e);
+    }
+    state.reset(false);
+  }
+
+  /** Get CryptoCipher from pool */
+  private CipherState getCipherState() throws IOException {
+    CipherState state = cipherPool.poll();
+    if (state == null) {
+      CryptoCipher cipher;
+      try {
+        cipher = CryptoCipherFactory.getInstance(getCipher().getTransformation(),
+            getCipher().getProperties());
+      } catch (GeneralSecurityException e) {
+        throw new IOException(e);
+      }
+      state = new CipherState(cipher);
+    }
+
+    return state;
+  }
+
+  /** Return CryptoCipher 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);
+    }
+  }
+
+  /**
+   * Overrides the {@link CryptoInputStream#close()}.
+   * Closes this input stream and releases any system resources associated
+   * with the stream.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  @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 CryptoCipher cipher;
+    private boolean reset;
+
+    public CipherState(CryptoCipher cipher) {
+      this.cipher = cipher;
+      this.reset = false;
+    }
+
+    public CryptoCipher 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/ea89d802/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 9aff624..ee24a0c 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>CipherInputStream</code>.
+ * wraps it as <code>Input</code> object acceptable by <code>CryptoInputStream</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/ea89d802/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 2971edb..a63c6ca 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>CipherInputStream</code> so that
+ * The Input interface abstract the input source of <code>CryptoInputStream</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/ea89d802/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 c7e6771..ac3739b 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>CipherInputStream</code>.
+ * wraps it as <code>Input</code> object acceptable by <code>CryptoInputStream</code>.
  */
 public class StreamInput implements Input {
   private byte[] buf;

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/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 0a60217..bae82a8 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>CipherOutputStream</code> as the output target.
+ * <code>Output</code> object acceptable by <code>CryptoOutputStream</code> as the output target.
  */
 public class ChannelOutput implements Output {
 

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/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 c57a89e..903fcea 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>CipherOutputStream</code> so that
+ * The Output interface abstract the output target of <code>CryptoOutputStream</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/ea89d802/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 73f0c74..e359c0d 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
@@ -22,8 +22,8 @@ import java.io.OutputStream;
 import java.nio.ByteBuffer;
 
 /**
- * The StreamOutput class takes a <code>OutputStream</code> object and wraps it as
- * <code>Output</code> object acceptable by <code>CipherOutputStream</code> as the output target.
+ * 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.
  */
 public class StreamOutput implements Output {
   private byte[] buf;

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/utils/ReflectionUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/utils/ReflectionUtils.java b/src/main/java/org/apache/commons/crypto/utils/ReflectionUtils.java
index 99e6d8c..4e1abd1 100644
--- a/src/main/java/org/apache/commons/crypto/utils/ReflectionUtils.java
+++ b/src/main/java/org/apache/commons/crypto/utils/ReflectionUtils.java
@@ -23,7 +23,7 @@ import java.util.Collections;
 import java.util.Map;
 import java.util.WeakHashMap;
 
-import org.apache.commons.crypto.cipher.Cipher;
+import org.apache.commons.crypto.cipher.CryptoCipher;
 
 /**
  * General utility methods for working with reflection.
@@ -37,7 +37,7 @@ public class ReflectionUtils {
   static {
     classLoader = Thread.currentThread().getContextClassLoader();
     if (classLoader == null) {
-      classLoader = Cipher.class.getClassLoader();
+      classLoader = CryptoCipher.class.getClassLoader();
     }
   }
 
@@ -51,7 +51,7 @@ public class ReflectionUtils {
 
   /**
    * A unique class which is used as a sentinel value in the caching
-   * for getClassByName. {@link Cipher#getClassByNameOrNull(String)}.
+   * for getClassByName. {@link CryptoCipher#getClassByNameOrNull(String)}.
    */
   private static abstract class NegativeCacheSentinel {}
 

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/utils/Utils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/utils/Utils.java b/src/main/java/org/apache/commons/crypto/utils/Utils.java
index c12fd9c..fe413a1 100644
--- a/src/main/java/org/apache/commons/crypto/utils/Utils.java
+++ b/src/main/java/org/apache/commons/crypto/utils/Utils.java
@@ -26,8 +26,8 @@ import java.util.Enumeration;
 import java.util.List;
 import java.util.Properties;
 
-import org.apache.commons.crypto.cipher.Cipher;
-import org.apache.commons.crypto.cipher.CipherFactory;
+import org.apache.commons.crypto.cipher.CryptoCipher;
+import org.apache.commons.crypto.cipher.CryptoCipherFactory;
 import org.apache.commons.crypto.cipher.CipherTransformation;
 import org.apache.commons.crypto.conf.ConfigurationKeys;
 
@@ -209,10 +209,10 @@ public class Utils {
   /**
    * Checks whether the cipher is supported streaming.
    *
-   * @param cipher the {@link org.apache.commons.crypto.cipher.Cipher} instance.
+   * @param cipher the {@link CryptoCipher} instance.
    * @throws IOException if an I/O error occurs.
    */
-  public static void checkStreamCipher(Cipher cipher) throws IOException {
+  public static void checkStreamCipher(CryptoCipher cipher) throws IOException {
     if (cipher.getTransformation() != CipherTransformation.AES_CTR_NOPADDING) {
       throw new IOException("AES/CTR/NoPadding is required");
     }
@@ -221,11 +221,11 @@ public class Utils {
   /**
    * Checks and floors buffer size.
    *
-   * @param cipher the {@link org.apache.commons.crypto.cipher.Cipher} instance.
+   * @param cipher the {@link CryptoCipher} instance.
    * @param bufferSize the buffer size.
    * @return the remaining buffer size.
    */
-  public static int checkBufferSize(Cipher cipher, int bufferSize) {
+  public static int checkBufferSize(CryptoCipher cipher, int bufferSize) {
     checkArgument(bufferSize >= MIN_BUFFER_SIZE,
         "Minimum value of buffer size is " + MIN_BUFFER_SIZE + ".");
     return bufferSize - bufferSize % cipher.getTransformation()
@@ -233,10 +233,10 @@ public class Utils {
   }
 
   /**
-   * This method is only for Counter (CTR) mode. Generally the Cipher calculates the
+   * This method is only for Counter (CTR) mode. Generally the CryptoCipher calculates the
    * IV and maintain encryption context internally.For example a
    * {@link javax.crypto.Cipher} will maintain its encryption context internally
-   * when we do encryption/decryption using the Cipher#update interface.
+   * when we do encryption/decryption using the CryptoCipher#update interface.
    * <p/>
    * Encryption/Decryption is not always on the entire file. For example,
    * in Hadoop, a node may only decrypt a portion of a file (i.e. a split).
@@ -269,18 +269,18 @@ public class Utils {
   }
 
   /**
-   * Helper method to create a Cipher instance and throws only IOException.
+   * Helper method to create a CryptoCipher instance and throws only IOException.
    *
    * @param props The <code>Properties</code> class represents a set of
    *              properties.
    * @param transformation the CipherTransformation instance.
-   * @return the Cipher instance.
+   * @return the CryptoCipher instance.
    * @throws IOException if an I/O error occurs.
    */
-  public static Cipher getCipherInstance(CipherTransformation transformation,
-      Properties props) throws IOException {
+  public static CryptoCipher getCipherInstance(CipherTransformation transformation,
+                                               Properties props) throws IOException {
     try {
-      return CipherFactory.getInstance(transformation, props);
+      return CryptoCipherFactory.getInstance(transformation, props);
     } catch (GeneralSecurityException e) {
       throw new IOException(e);
     }