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:08 UTC

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

Repository: commons-crypto
Updated Branches:
  refs/heads/master b53228834 -> ea89d8023


http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java
new file mode 100644
index 0000000..2591bd9
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java
@@ -0,0 +1,384 @@
+/**
+ * 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 org.apache.commons.crypto.cipher.CryptoCipher;
+import org.apache.commons.crypto.cipher.CipherTransformation;
+import org.apache.commons.crypto.cipher.JceCipher;
+import org.apache.commons.crypto.cipher.OpensslCipher;
+import org.apache.commons.crypto.stream.input.Input;
+import org.apache.commons.crypto.utils.ReflectionUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Properties;
+import java.util.Random;
+
+public class PositionedCryptoInputStreamTest {
+
+  private final int dataLen = 20000;
+  private byte[] testData = new byte[dataLen];
+  private byte[] encData;
+  private Properties props = new Properties();
+  private byte[] key = new byte[16];
+  private byte[] iv = new byte[16];
+  int bufferSize = 2048;
+  int bufferSizeLess = bufferSize - 1;
+  int bufferSizeMore = bufferSize + 1;
+  int length = 1024;
+  int lengthLess = length - 1;
+  int lengthMore = length + 1;
+
+  private final String jceCipherClass = JceCipher.class.getName();
+  private final String opensslCipherClass = OpensslCipher.class.getName();
+  private CipherTransformation transformation =
+                                CipherTransformation.AES_CTR_NOPADDING;
+
+  @Before
+  public void before() throws IOException {
+    Random random = new SecureRandom();
+    random.nextBytes(testData);
+    random.nextBytes(key);
+    random.nextBytes(iv);
+    prepareData();
+  }
+
+  private void prepareData() throws IOException {
+    CryptoCipher cipher = null;
+    try {
+      cipher = (CryptoCipher)ReflectionUtils.newInstance(
+              ReflectionUtils.getClassByName(jceCipherClass),
+              props, transformation);
+    } catch (ClassNotFoundException cnfe) {
+      throw new IOException("Illegal crypto cipher!");
+    }
+
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // encryption data
+    OutputStream out = new CryptoOutputStream(baos, cipher, bufferSize,
+            new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
+    out.write(testData);
+    out.flush();
+    out.close();
+    encData = baos.toByteArray();
+  }
+
+  public void setUp() throws IOException {}
+
+  private PositionedCryptoInputStream getCryptoInputStream(CryptoCipher cipher,
+                                                           int bufferSize) throws IOException {
+    return new PositionedCryptoInputStream(new PositionedInputForTest(
+      Arrays.copyOf(encData, encData.length)), cipher, bufferSize, key, iv, 0);
+  }
+
+  @Test
+  public void doTest() throws Exception {
+    testCipher(jceCipherClass);
+    testCipher(opensslCipherClass);
+  }
+
+  private void testCipher(String cipherClass) throws Exception {
+    doPositionedReadTests(cipherClass);
+    doReadFullyTests(cipherClass);
+    doSeekTests(cipherClass);
+    doMultipleReadTest(cipherClass);
+  }
+
+  // when there are multiple positioned read actions and one read action,
+  // they will not interfere each other.
+  private void doMultipleReadTest(String cipherClass) throws Exception {
+    PositionedCryptoInputStream in = getCryptoInputStream(
+            getCipher(cipherClass), bufferSize);
+    int position = 0;
+    while (in.available() > 0) {
+      ByteBuffer buf = ByteBuffer.allocate(length);
+      byte[] bytes1 = new byte[length];
+      byte[] bytes2 = new byte[lengthLess];
+      // do the read and position read
+      int pn1 = in.read(position, bytes1, 0, length);
+      int n = in.read(buf);
+      int pn2 = in.read(position, bytes2, 0, lengthLess);
+
+      // verify the result
+      if (pn1 > 0) {
+        compareByteArray(testData, position, bytes1, pn1);
+      }
+
+      if (pn2 > 0) {
+        compareByteArray(testData, position, bytes2, pn2);
+      }
+
+      if (n > 0) {
+        compareByteArray(testData, position, buf.array(), n);
+        position += n;
+      } else {
+        break;
+      }
+    }
+    in.close();
+  }
+
+  private void doPositionedReadTests(String cipherClass) throws Exception {
+    // test with different bufferSize when position = 0
+    testPositionedReadLoop(cipherClass, 0, length, bufferSize, dataLen);
+    testPositionedReadLoop(cipherClass, 0, length, bufferSizeLess, dataLen);
+    testPositionedReadLoop(cipherClass, 0, length, bufferSizeMore, dataLen);
+    // test with different position when bufferSize = 2048
+    testPositionedReadLoop(cipherClass, dataLen / 2, length, bufferSize, dataLen);
+    testPositionedReadLoop(cipherClass, dataLen / 2 - 1, length,
+            bufferSizeLess, dataLen);
+    testPositionedReadLoop(cipherClass, dataLen / 2 + 1, length,
+            bufferSizeMore, dataLen);
+    // position = -1 or position = max length, read nothing and return -1
+    testPositionedReadNone(cipherClass, -1, length, bufferSize);
+    testPositionedReadNone(cipherClass, dataLen, length, bufferSize);
+  }
+
+  private void doReadFullyTests(String cipherClass) throws Exception {
+    // test with different bufferSize when position = 0
+    testReadFullyLoop(cipherClass, 0, length, bufferSize, dataLen);
+    testReadFullyLoop(cipherClass, 0, length, bufferSizeLess, dataLen);
+    testReadFullyLoop(cipherClass, 0, length, bufferSizeMore, dataLen);
+    // test with different length when position = 0
+    testReadFullyLoop(cipherClass, 0, length, bufferSize, dataLen);
+    testReadFullyLoop(cipherClass, 0, lengthLess, bufferSize, dataLen);
+    testReadFullyLoop(cipherClass, 0, lengthMore, bufferSize, dataLen);
+    // test read fully failed
+    testReadFullyFailed(cipherClass, -1, length, bufferSize);
+    testReadFullyFailed(cipherClass, dataLen, length, bufferSize);
+    testReadFullyFailed(cipherClass, dataLen - length + 1, length, bufferSize);
+  }
+
+  private void doSeekTests(String cipherClass) throws Exception {
+    // test with different length when position = 0
+    testSeekLoop(cipherClass, 0, length, bufferSize);
+    testSeekLoop(cipherClass, 0, lengthLess, bufferSize);
+    testSeekLoop(cipherClass, 0, lengthMore, bufferSize);
+    // there should be none data read when position = dataLen
+    testSeekLoop(cipherClass, dataLen, length, bufferSize);
+    // test exception when position = -1
+    testSeekFailed(cipherClass, -1, bufferSize);
+  }
+
+  private void testSeekLoop(String cipherClass, int position, int length,
+      int bufferSize) throws Exception {
+    PositionedCryptoInputStream in = getCryptoInputStream(
+            getCipher(cipherClass), bufferSize);
+    while (in.available() > 0) {
+      in.seek(position);
+      ByteBuffer buf = ByteBuffer.allocate(length);
+      int n = in.read(buf);
+      if (n > 0) {
+        compareByteArray(testData, position, buf.array(), n);
+        position += n;
+      } else {
+        break;
+      }
+    }
+    in.close();
+  }
+
+  // test for the out of index position, eg, -1.
+  private void testSeekFailed(String cipherClass, int position,
+      int bufferSize) throws Exception {
+    PositionedCryptoInputStream in = getCryptoInputStream(
+            getCipher(cipherClass), bufferSize);
+    try {
+      in.seek(position);
+      Assert.fail("Excepted exception for cannot seek to negative offset.");
+    } catch (IllegalArgumentException iae) {
+    }
+    in.close();
+  }
+
+  private void testPositionedReadLoop(String cipherClass, int position,
+      int length, int bufferSize, int total) throws Exception {
+    PositionedCryptoInputStream in = getCryptoInputStream(
+            getCipher(cipherClass), bufferSize);
+    // do the position read until the end of data
+    while (position < total) {
+      byte[] bytes = new byte[length];
+      int n = in.read(position, bytes, 0, length);
+      if (n >= 0) {
+        compareByteArray(testData, position, bytes, n);
+        position += n;
+      } else {
+        break;
+      }
+    }
+    in.close();
+  }
+
+  // test for the out of index position, eg, -1.
+  private void testPositionedReadNone(String cipherClass, int position,
+      int length, int bufferSize) throws Exception {
+    PositionedCryptoInputStream in = getCryptoInputStream(
+            getCipher(cipherClass), bufferSize);
+    byte[] bytes = new byte[length];
+    int n = in.read(position, bytes, 0, length);
+    Assert.assertEquals(n, -1);
+    in.close();
+  }
+
+  private void testReadFullyLoop(String cipherClass,int position,
+      int length, int bufferSize, int total) throws Exception {
+    PositionedCryptoInputStream in = getCryptoInputStream(
+            getCipher(cipherClass), bufferSize);
+
+    // do the position read full until remain < length
+    while (position + length <= total) {
+      byte[] bytes = new byte[length];
+      in.readFully(position, bytes, 0, length);
+      compareByteArray(testData, position, bytes, length);
+      position += length;
+    }
+
+    in.close();
+  }
+
+  // test for the End of file reached before reading fully
+  private void testReadFullyFailed(String cipherClass, int position,
+      int length, int bufferSize) throws Exception {
+    PositionedCryptoInputStream in = getCryptoInputStream(
+            getCipher(cipherClass), bufferSize);
+    byte[] bytes = new byte[length];
+    try {
+      in.readFully(position, bytes, 0, length);
+      Assert.fail("Excepted EOFException.");
+    } catch (IOException ioe) {
+      // excepted exception
+    }
+    in.close();
+  }
+
+  // compare the data from pos with length and data2 from 0 with length
+  private void compareByteArray(byte[] data1, int pos, byte[] data2, int length) {
+    byte[] expectedData = new byte[length];
+    byte[] realData = new byte[length];
+    // get the expected data with the position and length
+    System.arraycopy(data1, pos, expectedData, 0, length);
+    // get the real data
+    System.arraycopy(data2, 0, realData, 0, length);
+    Assert.assertArrayEquals(expectedData, realData);
+  }
+
+  private CryptoCipher getCipher(String cipherClass) throws IOException {
+    try {
+      return (CryptoCipher)ReflectionUtils.newInstance(
+          ReflectionUtils.getClassByName(cipherClass), props, transformation);
+    } catch (ClassNotFoundException cnfe) {
+      throw new IOException("Illegal crypto cipher!");
+    }
+  }
+
+  class PositionedInputForTest implements Input {
+
+    byte[] data;
+    long pos;
+    long count;
+
+    public PositionedInputForTest(byte[] data) {
+      this.data = data;
+      this.pos = 0;
+      this.count = data.length;
+    }
+
+    @Override
+    public int read(ByteBuffer dst) throws IOException {
+      int remaining = (int)(count - pos);
+      if(remaining <= 0) {
+        return -1;
+      }
+
+      int length = Math.min(dst.remaining(), remaining);
+      dst.put(data, (int)pos, length);
+      pos += length;
+      return length;
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+      if (n <= 0) {
+        return 0;
+      }
+
+      long remaining = count - pos;
+      if(remaining < n) {
+        n = remaining;
+      }
+      pos += n;
+
+      return n;
+    }
+
+    @Override
+    public int read(long position, byte[] buffer, int offset, int length)
+            throws IOException {
+      if (buffer == null) {
+        throw new NullPointerException();
+      } else if (offset < 0 || length < 0 || length > buffer.length - offset) {
+        throw new IndexOutOfBoundsException();
+      }
+
+      if (position < 0 || position >= count) {
+        return -1;
+      }
+
+      long avail = count - position;
+      if (length > avail) {
+        length = (int)avail;
+      }
+      if (length <= 0) {
+        return 0;
+      }
+      System.arraycopy(data, (int)position, buffer, offset, length);
+      return length;
+    }
+
+    @Override
+    public void seek(long position) throws IOException {
+      if (pos < 0) {
+        throw new IOException("Negative seek offset");
+      } else if (position >= 0 && position < count) {
+        pos = position;
+      } else {
+        // to the end of file
+        pos = count;
+      }
+    }
+
+    @Override
+    public void close() throws IOException {
+    }
+
+    @Override
+    public int available() throws IOException {
+      return (int)(count - pos);
+    }
+  }
+}


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

Posted by sd...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/stream/CTRCipherInputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/CTRCipherInputStream.java b/src/main/java/org/apache/commons/crypto/stream/CTRCipherInputStream.java
deleted file mode 100644
index b0cea74..0000000
--- a/src/main/java/org/apache/commons/crypto/stream/CTRCipherInputStream.java
+++ /dev/null
@@ -1,625 +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.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.ReadableByteChannel;
-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 javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.apache.commons.crypto.cipher.Cipher;
-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;
-
-/**
- * CTRCipherInputStream decrypts data. AES CTR mode is required in order to
- * ensure that the plain text and cipher text have a 1:1 mapping. CTR crypto
- * stream has stream characteristic which is useful for implement features
- * like random seek. The decryption is buffer based. The key points of the
- * decryption are (1) calculating the counter and (2) padding through stream
- * position:
- * <p/>
- * counter = base + pos/(algorithm blocksize);
- * padding = pos%(algorithm blocksize);
- * <p/>
- * The underlying stream offset is maintained as state. It is not thread-safe.
- */
-public class CTRCipherInputStream extends CipherInputStream {
-  /**
-   * Underlying stream offset
-   */
-  long streamOffset = 0;
-
-  /**
-   * The initial IV.
-   */
-  protected final byte[] initIV;
-
-  /**
-   * Initialization vector for the cipher.
-   */
-  protected byte[] iv;
-
-  /**
-   * Padding = pos%(algorithm blocksize); Padding is put into {@link #inBuffer}
-   * before any other data goes in. The purpose of padding is to put the input
-   * data at proper position.
-   */
-  private byte padding;
-
-  /**
-   * Flag to mark whether the cipher has been reset
-   */
-  private boolean cipherReset = false;
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @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 iv Initialization vector for the cipher.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(Properties props, InputStream in,
-      byte[] key, byte[] iv)
-      throws IOException {
-    this(props, in, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @param props The <code>Properties</code> class represents a set of
-   *              properties.
-   * @param in the ReadableByteChannel instance.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(Properties props, ReadableByteChannel in,
-      byte[] key, byte[] iv)
-      throws IOException {
-    this(props, in, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @param in the input stream.
-   * @param cipher the Cipher instance.
-   * @param bufferSize the bufferSize.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(InputStream in, Cipher cipher, int bufferSize,
-      byte[] key, byte[] iv) throws IOException {
-    this(in, cipher, bufferSize, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @param in the ReadableByteChannel instance.
-   * @param cipher the cipher instance.
-   * @param bufferSize the bufferSize.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(ReadableByteChannel in, Cipher cipher,
-      int bufferSize, byte[] key, byte[] iv) throws IOException {
-    this(in, cipher, bufferSize, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @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.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(
-      Input input,
-      Cipher cipher,
-      int bufferSize,
-      byte[] key,
-      byte[] iv) throws IOException {
-    this(input, cipher, bufferSize, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @param props The <code>Properties</code> class represents a set of
-   *              properties.
-   * @param in the InputStream instance.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @param streamOffset the start offset in the stream.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(Properties props, InputStream in,
-      byte[] key, byte[] iv, long streamOffset)
-      throws IOException {
-    this(in, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props),
-        Utils.getBufferSize(props), key, iv, streamOffset);
-  }
-
-  /**
-   *Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @param props The <code>Properties</code> class represents a set of
-   *              properties.
-   * @param in the ReadableByteChannel instance.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @param streamOffset the start offset in the stream.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(Properties props, ReadableByteChannel in,
-      byte[] key, byte[] iv, long streamOffset)
-      throws IOException {
-    this(in, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props),
-        Utils.getBufferSize(props), key, iv, streamOffset);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @param in the InputStream instance.
-   * @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 stream.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(InputStream in, Cipher cipher, int bufferSize,
-      byte[] key, byte[] iv, long streamOffset) throws IOException {
-    this(new StreamInput(in, bufferSize), cipher, bufferSize, key, iv, streamOffset);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @param in the ReadableByteChannel instance.
-   * @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 stream.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(ReadableByteChannel in, Cipher cipher,
-      int bufferSize, byte[] key, byte[] iv, long streamOffset) throws IOException {
-    this(new ChannelInput(in), cipher, bufferSize, key, iv, streamOffset);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherInputStream}.
-   *
-   * @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 stream.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherInputStream(
-      Input input,
-      Cipher cipher,
-      int bufferSize,
-      byte[] key,
-      byte[] iv,
-      long streamOffset) throws IOException {
-    super(input, cipher, bufferSize, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
-
-    this.initIV = iv.clone();
-    this.iv = iv.clone();
-
-    Utils.checkStreamCipher(cipher);
-
-    resetStreamOffset(streamOffset);
-  }
-
-  /**
-   * Overrides the {@link org.apache.commons.crypto.stream.CipherInputStream#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;
-    } else if (n <= outBuffer.remaining()) {
-      int pos = outBuffer.position() + (int) n;
-      outBuffer.position(pos);
-      return n;
-    } else {
-      /*
-       * Subtract outBuffer.remaining() to see how many bytes we need to
-       * skip in the underlying stream. Add outBuffer.remaining() to the
-       * actual number of skipped bytes in the underlying stream to get the
-       * number of skipped bytes from the user's point of view.
-       */
-      n -= outBuffer.remaining();
-      long skipped = input.skip(n);
-      if (skipped < 0) {
-        skipped = 0;
-      }
-      long pos = streamOffset + skipped;
-      skipped += outBuffer.remaining();
-      resetStreamOffset(pos);
-      return skipped;
-    }
-  }
-
-  /**
-   * Overrides the {@link org.apache.commons.crypto.stream.CTRCipherInputStream#read(ByteBuffer)}.
-   * Reads a sequence of bytes from this channel into the given buffer.
-   *
-   * @param buf 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 buf) throws IOException {
-    checkStream();
-    int unread = outBuffer.remaining();
-    if (unread <= 0) { // Fill the unread decrypted data buffer firstly
-      final int n = input.read(inBuffer);
-      if (n <= 0) {
-        return n;
-      }
-
-      streamOffset += n; // Read n bytes
-      if (buf.isDirect() && buf.remaining() >= inBuffer.position() && padding == 0) {
-        // Use buf as the output buffer directly
-        decryptInPlace(buf);
-        padding = postDecryption(streamOffset);
-        return n;
-      } else {
-        // Use outBuffer as the output buffer
-        decrypt();
-        padding = postDecryption(streamOffset);
-      }
-    }
-
-    // Copy decrypted data from outBuffer to buf
-    unread = outBuffer.remaining();
-    final int toRead = buf.remaining();
-    if (toRead <= unread) {
-      final int limit = outBuffer.limit();
-      outBuffer.limit(outBuffer.position() + toRead);
-      buf.put(outBuffer);
-      outBuffer.limit(limit);
-      return toRead;
-    } else {
-      buf.put(outBuffer);
-      return unread;
-    }
-  }
-
-  /**
-   * Seeks the stream to a specific position relative to start of the under layer stream.
-   *
-   * @param position the given position in the data.
-   * @throws IOException if an I/O error occurs.
-   */
-  public void seek(long position) throws IOException {
-    Utils.checkArgument(position >= 0, "Cannot seek to negative offset.");
-    checkStream();
-    /*
-     * If data of target pos in the underlying stream has already been read
-     * and decrypted in outBuffer, we just need to re-position outBuffer.
-     */
-    if (position >= getStreamPosition() && position <= getStreamOffset()) {
-      int forward = (int) (position - getStreamPosition());
-      if (forward > 0) {
-        outBuffer.position(outBuffer.position() + forward);
-      }
-    } else {
-      input.seek(position);
-      resetStreamOffset(position);
-    }
-  }
-
-  /**
-   * Gets the offset of the stream.
-   *
-   * @return the stream offset.
-   */
-  protected long getStreamOffset() {
-    return streamOffset;
-  }
-
-  protected void setStreamOffset(long streamOffset) {
-    this.streamOffset = streamOffset;
-  }
-
-  /**
-   * Gets the position of the stream.
-   *
-   * @return the position of the stream.
-   */
-  protected long getStreamPosition() {
-    return streamOffset - outBuffer.remaining();
-  }
-
-  /**
-   * Decrypts more data by reading the under layer stream. The decrypted data will
-   * be put in the output buffer.
-   *
-   * @return The number of decrypted data. -1 if end of the decrypted stream.
-   * @throws IOException if an I/O error occurs.
-   */
-  @Override
-  protected int decryptMore() throws IOException {
-    int n = input.read(inBuffer);
-    if (n <= 0) {
-      return n;
-    }
-
-    streamOffset += n; // Read n bytes
-    decrypt();
-    padding = postDecryption(streamOffset);
-    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.
-   */
-  @Override
-  protected void decrypt() throws IOException {
-    Utils.checkState(inBuffer.position() >= padding);
-    if(inBuffer.position() == padding) {
-      // There is no real data in inBuffer.
-      return;
-    }
-
-    inBuffer.flip();
-    outBuffer.clear();
-    decryptBuffer(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);
-    }
-  }
-
-  /**
-   * Does the decryption using inBuffer as input and buf as output.
-   * Upon return, inBuffer is cleared; the buf's position will be equal to
-   * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i> where <i>p</i> is the position before
-   * decryption, <i>n</i> is the number of bytes decrypted.
-   * The buf's limit will not have changed.
-   *
-   * @param buf The buffer into which bytes are to be transferred.
-   * @throws IOException if an I/O error occurs.
-   */
-  protected void decryptInPlace(ByteBuffer buf) throws IOException {
-    Utils.checkState(inBuffer.position() >= padding);
-    Utils.checkState(buf.isDirect());
-    Utils.checkState(buf.remaining() >= inBuffer.position());
-    Utils.checkState(padding == 0);
-
-    if(inBuffer.position() == padding) {
-      // There is no real data in inBuffer.
-      return;
-    }
-    inBuffer.flip();
-    decryptBuffer(buf);
-    inBuffer.clear();
-  }
-
-  /**
-   * Decrypts all data in buf: total n bytes from given start position.
-   * Output is also buf and same start position.
-   * buf.position() and buf.limit() should be unchanged after decryption.
-   *
-   * @param buf The buffer into which bytes are to be transferred.
-   * @param offset the start offset in the data.
-   * @param len the the maximum number of decrypted data bytes to read.
-   * @throws IOException if an I/O error occurs.
-   */
-  protected void decrypt(ByteBuffer buf, int offset, int len)
-      throws IOException {
-    final int pos = buf.position();
-    final int limit = buf.limit();
-    int n = 0;
-    while (n < len) {
-      buf.position(offset + n);
-      buf.limit(offset + n + Math.min(len - n, inBuffer.remaining()));
-      inBuffer.put(buf);
-      // Do decryption
-      try {
-        decrypt();
-        buf.position(offset + n);
-        buf.limit(limit);
-        n += outBuffer.remaining();
-        buf.put(outBuffer);
-      } finally {
-        padding = postDecryption(streamOffset - (len - n));
-      }
-    }
-    buf.position(pos);
-  }
-
-  /**
-   * This method is executed immediately after decryption. Checks whether
-   * cipher should be updated and recalculate padding if needed.
-   *
-   * @param position the given position in the data..
-   * @return the byte.
-   */
-  protected byte postDecryption(long position) throws IOException {
-    byte padding = 0;
-    if (cipherReset) {
-      /*
-       * 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(position);
-      padding = getPadding(position);
-      inBuffer.position(padding);
-    }
-    return padding;
-  }
-
-  /**
-   * Gets the initialization vector.
-   *
-   * @return the initIV.
-   */
-  protected byte[] getInitIV() {
-    return initIV;
-  }
-
-  /**
-   * Gets the counter for input stream position.
-   *
-   * @param position the given position in the data.
-   * @return the counter for input stream position.
-   */
-  protected long getCounter(long position) {
-    return position / cipher.getTransformation().getAlgorithmBlockSize();
-  }
-
-  /**
-   * Gets the padding for input stream position.
-   *
-   * @param position the given position in the data.
-   * @return the padding for input stream position.
-   */
-  protected byte getPadding(long position) {
-    return (byte)(position % cipher.getTransformation().getAlgorithmBlockSize());
-  }
-
-  /**
-   * Overrides the {@link CTRCipherInputStream#initCipher()}.
-   * Initializes the cipher.
-   */
-  @Override
-  protected void initCipher() {
-    // Do nothing for initCipher
-    // Will reset the cipher when reset the stream offset
-  }
-
-  /**
-   * Calculates the counter and iv, resets the cipher.
-   *
-   * @param position the given position in the data.
-   * @throws IOException if an I/O error occurs.
-   */
-  protected void resetCipher(long position)
-      throws IOException {
-    final long counter = getCounter(position);
-    Utils.calculateIV(initIV, counter, iv);
-    try {
-      cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
-    } catch (InvalidKeyException e) {
-      throw new IOException(e);
-    } catch (InvalidAlgorithmParameterException e) {
-      throw new IOException(e);
-    }
-    cipherReset = false;
-  }
-
-  /**
-   * Resets the underlying stream offset; clear {@link #inBuffer} and
-   * {@link #outBuffer}. This Typically happens during {@link #skip(long)}.
-   *
-   * @param offset the offset of the stream.
-   * @throws IOException if an I/O error occurs.
-   */
-  protected void resetStreamOffset(long offset) throws IOException {
-    streamOffset = offset;
-    inBuffer.clear();
-    outBuffer.clear();
-    outBuffer.limit(0);
-    resetCipher(offset);
-    padding = getPadding(offset);
-    inBuffer.position(padding); // Set proper position for input data.
-  }
-
-  /**
-   * Does the decryption using out as output.
-   *
-   * @param out the output ByteBuffer.
-   * @throws IOException if an I/O error occurs.
-   */
-  protected void decryptBuffer(ByteBuffer out)
-      throws IOException {
-    int inputSize = inBuffer.remaining();
-    try {
-      int n = cipher.update(inBuffer, out);
-      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.
-         */
-        cipher.doFinal(inBuffer, out);
-        cipherReset = true;
-      }
-    } catch (ShortBufferException e) {
-      throw new IOException(e);
-    } catch (IllegalBlockSizeException e) {
-      throw new IOException(e);
-    } catch (BadPaddingException e) {
-      throw new IOException(e);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/stream/CTRCipherOutputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/CTRCipherOutputStream.java b/src/main/java/org/apache/commons/crypto/stream/CTRCipherOutputStream.java
deleted file mode 100644
index 7889123..0000000
--- a/src/main/java/org/apache/commons/crypto/stream/CTRCipherOutputStream.java
+++ /dev/null
@@ -1,385 +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 javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-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;
-
-/**
- * CTRCipherOutputStream encrypts data. It is not thread-safe. AES CTR mode is
- * required in order to ensure that the plain text and cipher text have a 1:1
- * mapping. The encryption is buffer based. The key points of the encryption are
- * (1) calculating counter and (2) padding through stream position.
- * <p/>
- * counter = base + pos/(algorithm blocksize);
- * padding = pos%(algorithm blocksize);
- * <p/>
- * The underlying stream offset is maintained as state.
- */
-public class CTRCipherOutputStream extends CipherOutputStream {
-  /**
-   * Underlying stream offset.
-   */
-  long streamOffset = 0;
-
-  /**
-   * The initial IV.
-   */
-  protected final byte[] initIV;
-
-  /**
-   * Initialization vector for the cipher.
-   */
-  protected byte[] iv;
-
-  /**
-   * Padding = pos%(algorithm blocksize); Padding is put into {@link #inBuffer}
-   * before any other data goes in. The purpose of padding is to put input data
-   * at proper position.
-   */
-  private byte padding;
-
-  /**
-   * Flag to mark whether the cipher has been reset
-   */
-  private boolean cipherReset = false;
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @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 iv Initialization vector for the cipher.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherOutputStream(Properties props, OutputStream out, byte[] key,
-                               byte[] iv)
-      throws IOException {
-    this(props, out, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @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 iv Initialization vector for the cipher.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherOutputStream(Properties props, WritableByteChannel out,
-                               byte[] key, byte[] iv)
-      throws IOException {
-    this(props, out, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @param out the output stream.
-   * @param cipher the Cipher instance.
-   * @param bufferSize the bufferSize.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherOutputStream(OutputStream out, Cipher cipher, int bufferSize,
-                               byte[] key, byte[] iv) throws IOException {
-    this(out, cipher, bufferSize, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @param channel the WritableByteChannel instance.
-   * @param cipher the Cipher instance.
-   * @param bufferSize the bufferSize.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherOutputStream(WritableByteChannel channel, Cipher cipher,
-                               int bufferSize, byte[] key, byte[] iv) throws IOException {
-    this(channel, cipher, bufferSize, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @param output the Output instance.
-   * @param cipher the Cipher instance.
-   * @param bufferSize the bufferSize.
-   * @param key crypto key for the cipher.
-   * @param iv Initialization vector for the cipher.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherOutputStream(Output output, Cipher cipher, int bufferSize,
-                               byte[] key, byte[] iv)
-      throws IOException {
-    this(output, cipher, bufferSize, key, iv, 0);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @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 iv Initialization vector for the cipher.
-   * @param streamOffset the start offset in the data.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherOutputStream(Properties props, OutputStream out, byte[] key,
-                               byte[] iv, long streamOffset)
-      throws IOException {
-    this(out, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props),
-        Utils.getBufferSize(props), key, iv, streamOffset);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @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 iv Initialization vector for the cipher.
-   * @param streamOffset the start offset in the data.
-   * @throws IOException if an I/O error occurs.
-   */
-  public CTRCipherOutputStream(Properties props, WritableByteChannel out,
-                               byte[] key, byte[] iv, long streamOffset)
-      throws IOException {
-    this(out, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props),
-        Utils.getBufferSize(props), key, iv, streamOffset);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @param out the output stream.
-   * @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 CTRCipherOutputStream(OutputStream out, Cipher cipher, int bufferSize,
-                               byte[] key, byte[] iv, long streamOffset) throws IOException {
-    this(new StreamOutput(out, bufferSize), cipher,
-        bufferSize, key, iv, streamOffset);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @param channel the WritableByteChannel instance.
-   * @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 CTRCipherOutputStream(WritableByteChannel channel, Cipher cipher,
-                               int bufferSize, byte[] key, byte[] iv,
-                               long streamOffset) throws IOException {
-    this(new ChannelOutput(channel), cipher,
-        bufferSize, key, iv, streamOffset);
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.stream.CTRCipherOutputStream}.
-   *
-   * @param output the output stream.
-   * @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 CTRCipherOutputStream(Output output, Cipher cipher, int bufferSize,
-                               byte[] key, byte[] iv, long streamOffset)
-      throws IOException {
-    super(output, cipher, bufferSize, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
-
-    Utils.checkStreamCipher(cipher);
-    this.streamOffset = streamOffset;
-    this.initIV = iv.clone();
-    this.iv = iv.clone();
-
-    resetCipher();
-  }
-
-  /**
-   * Does the encryption, input is {@link #inBuffer} and output is
-   * {@link #outBuffer}.
-   *
-   * @throws IOException if an I/O error occurs.
-   */
-  @Override
-  protected void encrypt() throws IOException {
-    Utils.checkState(inBuffer.position() >= padding);
-    if (inBuffer.position() == padding) {
-      // There is no real data in the inBuffer.
-      return;
-    }
-
-    inBuffer.flip();
-    outBuffer.clear();
-    encryptBuffer(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);
-      padding = 0;
-    }
-
-    final int len = output.write(outBuffer);
-    streamOffset += len;
-    if (cipherReset) {
-      /*
-       * This code is generally not executed since the encryptor usually
-       * maintains encryption context (e.g. the counter) internally. However,
-       * some implementations can't maintain context so a re-init is necessary
-       * after each encryption call.
-       */
-      resetCipher();
-    }
-  }
-
-  /**
-   * Does final encryption of the last data.
-   *
-   * @throws IOException if an I/O error occurs.
-   */
-  @Override
-  protected void encryptFinal() throws IOException {
-    // The same as the normal encryption for Counter mode
-    encrypt();
-  }
-
-  /**
-   * Overrides the {@link CipherOutputStream#initCipher()}.
-   * Initializes the cipher.
-   */
-  @Override
-  protected void initCipher() {
-    // Do nothing for initCipher
-    // Will reset the cipher considering the stream offset
-  }
-
-  /**
-   * Resets the {@link #cipher}: calculate counter and {@link #padding}.
-   *
-   * @throws IOException if an I/O error occurs.
-   */
-  private void resetCipher() throws IOException {
-    final long counter =
-        streamOffset / cipher.getTransformation().getAlgorithmBlockSize();
-    padding =
-        (byte)(streamOffset % cipher.getTransformation().getAlgorithmBlockSize());
-    inBuffer.position(padding); // Set proper position for input data.
-
-    Utils.calculateIV(initIV, counter, iv);
-    try {
-      cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
-    } catch (InvalidKeyException e) {
-      throw new IOException(e);
-    }catch (InvalidAlgorithmParameterException e) {
-      throw new IOException(e);
-    }
-    cipherReset = false;
-  }
-
-  /**
-   * Does the encryption if the ByteBuffer data.
-   *
-   * @param out the output ByteBuffer.
-   * @throws IOException if an I/O error occurs.
-   */
-  private void encryptBuffer(ByteBuffer out)
-      throws IOException {
-    int inputSize = inBuffer.remaining();
-    try {
-      int n = cipher.update(inBuffer, out);
-      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.
-         */
-        cipher.doFinal(inBuffer, out);
-        cipherReset = true;
-      }
-    } catch (ShortBufferException e) {
-      throw new IOException(e);
-    } catch (BadPaddingException e) {
-      throw new IOException(e);
-    } catch (IllegalBlockSizeException e) {
-      throw new IOException(e);
-    }
-  }
-
-  /**
-   * Get the underlying stream offset
-   *
-   * @return the underlying stream offset
-   */
-  protected long getStreamOffset() {
-    return streamOffset;
-  }
-
-  /**
-   * Set the underlying stream offset
-   *
-   * @param streamOffset the underlying stream offset
-   */
-  protected void setStreamOffset(long streamOffset) {
-    this.streamOffset = streamOffset;
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java b/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java
new file mode 100644
index 0000000..dd9202d
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java
@@ -0,0 +1,625 @@
+/**
+ * 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.ReadableByteChannel;
+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 javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+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;
+
+/**
+ * CTRCryptoInputStream decrypts data. AES CTR mode is required in order to
+ * ensure that the plain text and cipher text have a 1:1 mapping. CTR crypto
+ * stream has stream characteristic which is useful for implement features
+ * like random seek. The decryption is buffer based. The key points of the
+ * decryption are (1) calculating the counter and (2) padding through stream
+ * position:
+ * <p/>
+ * counter = base + pos/(algorithm blocksize);
+ * padding = pos%(algorithm blocksize);
+ * <p/>
+ * The underlying stream offset is maintained as state. It is not thread-safe.
+ */
+public class CTRCryptoInputStream extends CryptoInputStream {
+  /**
+   * Underlying stream offset
+   */
+  long streamOffset = 0;
+
+  /**
+   * The initial IV.
+   */
+  protected final byte[] initIV;
+
+  /**
+   * Initialization vector for the cipher.
+   */
+  protected byte[] iv;
+
+  /**
+   * Padding = pos%(algorithm blocksize); Padding is put into {@link #inBuffer}
+   * before any other data goes in. The purpose of padding is to put the input
+   * data at proper position.
+   */
+  private byte padding;
+
+  /**
+   * Flag to mark whether the cipher has been reset
+   */
+  private boolean cipherReset = false;
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @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 iv Initialization vector for the cipher.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(Properties props, InputStream in,
+                              byte[] key, byte[] iv)
+      throws IOException {
+    this(props, in, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @param props The <code>Properties</code> class represents a set of
+   *              properties.
+   * @param in the ReadableByteChannel instance.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(Properties props, ReadableByteChannel in,
+                              byte[] key, byte[] iv)
+      throws IOException {
+    this(props, in, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @param in the input stream.
+   * @param cipher the CryptoCipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(InputStream in, CryptoCipher cipher, int bufferSize,
+                              byte[] key, byte[] iv) throws IOException {
+    this(in, cipher, bufferSize, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @param in the ReadableByteChannel instance.
+   * @param cipher the cipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(ReadableByteChannel in, CryptoCipher cipher,
+                              int bufferSize, byte[] key, byte[] iv) throws IOException {
+    this(in, cipher, bufferSize, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @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.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(
+      Input input,
+      CryptoCipher cipher,
+      int bufferSize,
+      byte[] key,
+      byte[] iv) throws IOException {
+    this(input, cipher, bufferSize, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @param props The <code>Properties</code> class represents a set of
+   *              properties.
+   * @param in the InputStream instance.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @param streamOffset the start offset in the stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(Properties props, InputStream in,
+                              byte[] key, byte[] iv, long streamOffset)
+      throws IOException {
+    this(in, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props),
+        Utils.getBufferSize(props), key, iv, streamOffset);
+  }
+
+  /**
+   *Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @param props The <code>Properties</code> class represents a set of
+   *              properties.
+   * @param in the ReadableByteChannel instance.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @param streamOffset the start offset in the stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(Properties props, ReadableByteChannel in,
+                              byte[] key, byte[] iv, long streamOffset)
+      throws IOException {
+    this(in, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props),
+        Utils.getBufferSize(props), key, iv, streamOffset);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @param in the InputStream instance.
+   * @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 stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(InputStream in, CryptoCipher cipher, int bufferSize,
+                              byte[] key, byte[] iv, long streamOffset) throws IOException {
+    this(new StreamInput(in, bufferSize), cipher, bufferSize, key, iv, streamOffset);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @param in the ReadableByteChannel instance.
+   * @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 stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(ReadableByteChannel in, CryptoCipher cipher,
+                              int bufferSize, byte[] key, byte[] iv, long streamOffset) throws IOException {
+    this(new ChannelInput(in), cipher, bufferSize, key, iv, streamOffset);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoInputStream}.
+   *
+   * @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 stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoInputStream(
+      Input input,
+      CryptoCipher cipher,
+      int bufferSize,
+      byte[] key,
+      byte[] iv,
+      long streamOffset) throws IOException {
+    super(input, cipher, bufferSize, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
+
+    this.initIV = iv.clone();
+    this.iv = iv.clone();
+
+    Utils.checkStreamCipher(cipher);
+
+    resetStreamOffset(streamOffset);
+  }
+
+  /**
+   * Overrides the {@link org.apache.commons.crypto.stream.CryptoInputStream#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;
+    } else if (n <= outBuffer.remaining()) {
+      int pos = outBuffer.position() + (int) n;
+      outBuffer.position(pos);
+      return n;
+    } else {
+      /*
+       * Subtract outBuffer.remaining() to see how many bytes we need to
+       * skip in the underlying stream. Add outBuffer.remaining() to the
+       * actual number of skipped bytes in the underlying stream to get the
+       * number of skipped bytes from the user's point of view.
+       */
+      n -= outBuffer.remaining();
+      long skipped = input.skip(n);
+      if (skipped < 0) {
+        skipped = 0;
+      }
+      long pos = streamOffset + skipped;
+      skipped += outBuffer.remaining();
+      resetStreamOffset(pos);
+      return skipped;
+    }
+  }
+
+  /**
+   * Overrides the {@link org.apache.commons.crypto.stream.CTRCryptoInputStream#read(ByteBuffer)}.
+   * Reads a sequence of bytes from this channel into the given buffer.
+   *
+   * @param buf 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 buf) throws IOException {
+    checkStream();
+    int unread = outBuffer.remaining();
+    if (unread <= 0) { // Fill the unread decrypted data buffer firstly
+      final int n = input.read(inBuffer);
+      if (n <= 0) {
+        return n;
+      }
+
+      streamOffset += n; // Read n bytes
+      if (buf.isDirect() && buf.remaining() >= inBuffer.position() && padding == 0) {
+        // Use buf as the output buffer directly
+        decryptInPlace(buf);
+        padding = postDecryption(streamOffset);
+        return n;
+      } else {
+        // Use outBuffer as the output buffer
+        decrypt();
+        padding = postDecryption(streamOffset);
+      }
+    }
+
+    // Copy decrypted data from outBuffer to buf
+    unread = outBuffer.remaining();
+    final int toRead = buf.remaining();
+    if (toRead <= unread) {
+      final int limit = outBuffer.limit();
+      outBuffer.limit(outBuffer.position() + toRead);
+      buf.put(outBuffer);
+      outBuffer.limit(limit);
+      return toRead;
+    } else {
+      buf.put(outBuffer);
+      return unread;
+    }
+  }
+
+  /**
+   * Seeks the stream to a specific position relative to start of the under layer stream.
+   *
+   * @param position the given position in the data.
+   * @throws IOException if an I/O error occurs.
+   */
+  public void seek(long position) throws IOException {
+    Utils.checkArgument(position >= 0, "Cannot seek to negative offset.");
+    checkStream();
+    /*
+     * If data of target pos in the underlying stream has already been read
+     * and decrypted in outBuffer, we just need to re-position outBuffer.
+     */
+    if (position >= getStreamPosition() && position <= getStreamOffset()) {
+      int forward = (int) (position - getStreamPosition());
+      if (forward > 0) {
+        outBuffer.position(outBuffer.position() + forward);
+      }
+    } else {
+      input.seek(position);
+      resetStreamOffset(position);
+    }
+  }
+
+  /**
+   * Gets the offset of the stream.
+   *
+   * @return the stream offset.
+   */
+  protected long getStreamOffset() {
+    return streamOffset;
+  }
+
+  protected void setStreamOffset(long streamOffset) {
+    this.streamOffset = streamOffset;
+  }
+
+  /**
+   * Gets the position of the stream.
+   *
+   * @return the position of the stream.
+   */
+  protected long getStreamPosition() {
+    return streamOffset - outBuffer.remaining();
+  }
+
+  /**
+   * Decrypts more data by reading the under layer stream. The decrypted data will
+   * be put in the output buffer.
+   *
+   * @return The number of decrypted data. -1 if end of the decrypted stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  protected int decryptMore() throws IOException {
+    int n = input.read(inBuffer);
+    if (n <= 0) {
+      return n;
+    }
+
+    streamOffset += n; // Read n bytes
+    decrypt();
+    padding = postDecryption(streamOffset);
+    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.
+   */
+  @Override
+  protected void decrypt() throws IOException {
+    Utils.checkState(inBuffer.position() >= padding);
+    if(inBuffer.position() == padding) {
+      // There is no real data in inBuffer.
+      return;
+    }
+
+    inBuffer.flip();
+    outBuffer.clear();
+    decryptBuffer(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);
+    }
+  }
+
+  /**
+   * Does the decryption using inBuffer as input and buf as output.
+   * Upon return, inBuffer is cleared; the buf's position will be equal to
+   * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i> where <i>p</i> is the position before
+   * decryption, <i>n</i> is the number of bytes decrypted.
+   * The buf's limit will not have changed.
+   *
+   * @param buf The buffer into which bytes are to be transferred.
+   * @throws IOException if an I/O error occurs.
+   */
+  protected void decryptInPlace(ByteBuffer buf) throws IOException {
+    Utils.checkState(inBuffer.position() >= padding);
+    Utils.checkState(buf.isDirect());
+    Utils.checkState(buf.remaining() >= inBuffer.position());
+    Utils.checkState(padding == 0);
+
+    if(inBuffer.position() == padding) {
+      // There is no real data in inBuffer.
+      return;
+    }
+    inBuffer.flip();
+    decryptBuffer(buf);
+    inBuffer.clear();
+  }
+
+  /**
+   * Decrypts all data in buf: total n bytes from given start position.
+   * Output is also buf and same start position.
+   * buf.position() and buf.limit() should be unchanged after decryption.
+   *
+   * @param buf The buffer into which bytes are to be transferred.
+   * @param offset the start offset in the data.
+   * @param len the the maximum number of decrypted data bytes to read.
+   * @throws IOException if an I/O error occurs.
+   */
+  protected void decrypt(ByteBuffer buf, int offset, int len)
+      throws IOException {
+    final int pos = buf.position();
+    final int limit = buf.limit();
+    int n = 0;
+    while (n < len) {
+      buf.position(offset + n);
+      buf.limit(offset + n + Math.min(len - n, inBuffer.remaining()));
+      inBuffer.put(buf);
+      // Do decryption
+      try {
+        decrypt();
+        buf.position(offset + n);
+        buf.limit(limit);
+        n += outBuffer.remaining();
+        buf.put(outBuffer);
+      } finally {
+        padding = postDecryption(streamOffset - (len - n));
+      }
+    }
+    buf.position(pos);
+  }
+
+  /**
+   * This method is executed immediately after decryption. Checks whether
+   * cipher should be updated and recalculate padding if needed.
+   *
+   * @param position the given position in the data..
+   * @return the byte.
+   */
+  protected byte postDecryption(long position) throws IOException {
+    byte padding = 0;
+    if (cipherReset) {
+      /*
+       * 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(position);
+      padding = getPadding(position);
+      inBuffer.position(padding);
+    }
+    return padding;
+  }
+
+  /**
+   * Gets the initialization vector.
+   *
+   * @return the initIV.
+   */
+  protected byte[] getInitIV() {
+    return initIV;
+  }
+
+  /**
+   * Gets the counter for input stream position.
+   *
+   * @param position the given position in the data.
+   * @return the counter for input stream position.
+   */
+  protected long getCounter(long position) {
+    return position / cipher.getTransformation().getAlgorithmBlockSize();
+  }
+
+  /**
+   * Gets the padding for input stream position.
+   *
+   * @param position the given position in the data.
+   * @return the padding for input stream position.
+   */
+  protected byte getPadding(long position) {
+    return (byte)(position % cipher.getTransformation().getAlgorithmBlockSize());
+  }
+
+  /**
+   * Overrides the {@link CTRCryptoInputStream#initCipher()}.
+   * Initializes the cipher.
+   */
+  @Override
+  protected void initCipher() {
+    // Do nothing for initCipher
+    // Will reset the cipher when reset the stream offset
+  }
+
+  /**
+   * Calculates the counter and iv, resets the cipher.
+   *
+   * @param position the given position in the data.
+   * @throws IOException if an I/O error occurs.
+   */
+  protected void resetCipher(long position)
+      throws IOException {
+    final long counter = getCounter(position);
+    Utils.calculateIV(initIV, counter, iv);
+    try {
+      cipher.init(CryptoCipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
+    } catch (InvalidKeyException e) {
+      throw new IOException(e);
+    } catch (InvalidAlgorithmParameterException e) {
+      throw new IOException(e);
+    }
+    cipherReset = false;
+  }
+
+  /**
+   * Resets the underlying stream offset; clear {@link #inBuffer} and
+   * {@link #outBuffer}. This Typically happens during {@link #skip(long)}.
+   *
+   * @param offset the offset of the stream.
+   * @throws IOException if an I/O error occurs.
+   */
+  protected void resetStreamOffset(long offset) throws IOException {
+    streamOffset = offset;
+    inBuffer.clear();
+    outBuffer.clear();
+    outBuffer.limit(0);
+    resetCipher(offset);
+    padding = getPadding(offset);
+    inBuffer.position(padding); // Set proper position for input data.
+  }
+
+  /**
+   * Does the decryption using out as output.
+   *
+   * @param out the output ByteBuffer.
+   * @throws IOException if an I/O error occurs.
+   */
+  protected void decryptBuffer(ByteBuffer out)
+      throws IOException {
+    int inputSize = inBuffer.remaining();
+    try {
+      int n = cipher.update(inBuffer, out);
+      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.
+         */
+        cipher.doFinal(inBuffer, out);
+        cipherReset = true;
+      }
+    } catch (ShortBufferException e) {
+      throw new IOException(e);
+    } catch (IllegalBlockSizeException e) {
+      throw new IOException(e);
+    } catch (BadPaddingException e) {
+      throw new IOException(e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/stream/CTRCryptoOutputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/CTRCryptoOutputStream.java b/src/main/java/org/apache/commons/crypto/stream/CTRCryptoOutputStream.java
new file mode 100644
index 0000000..483f03c
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/stream/CTRCryptoOutputStream.java
@@ -0,0 +1,385 @@
+/**
+ * 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 javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+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;
+
+/**
+ * CTRCryptoOutputStream encrypts data. It is not thread-safe. AES CTR mode is
+ * required in order to ensure that the plain text and cipher text have a 1:1
+ * mapping. The encryption is buffer based. The key points of the encryption are
+ * (1) calculating counter and (2) padding through stream position.
+ * <p/>
+ * counter = base + pos/(algorithm blocksize);
+ * padding = pos%(algorithm blocksize);
+ * <p/>
+ * The underlying stream offset is maintained as state.
+ */
+public class CTRCryptoOutputStream extends CryptoOutputStream {
+  /**
+   * Underlying stream offset.
+   */
+  long streamOffset = 0;
+
+  /**
+   * The initial IV.
+   */
+  protected final byte[] initIV;
+
+  /**
+   * Initialization vector for the cipher.
+   */
+  protected byte[] iv;
+
+  /**
+   * Padding = pos%(algorithm blocksize); Padding is put into {@link #inBuffer}
+   * before any other data goes in. The purpose of padding is to put input data
+   * at proper position.
+   */
+  private byte padding;
+
+  /**
+   * Flag to mark whether the cipher has been reset
+   */
+  private boolean cipherReset = false;
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @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 iv Initialization vector for the cipher.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoOutputStream(Properties props, OutputStream out, byte[] key,
+                               byte[] iv)
+      throws IOException {
+    this(props, out, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @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 iv Initialization vector for the cipher.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoOutputStream(Properties props, WritableByteChannel out,
+                               byte[] key, byte[] iv)
+      throws IOException {
+    this(props, out, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @param out the output stream.
+   * @param cipher the CryptoCipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoOutputStream(OutputStream out, CryptoCipher cipher, int bufferSize,
+                               byte[] key, byte[] iv) throws IOException {
+    this(out, cipher, bufferSize, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @param channel the WritableByteChannel instance.
+   * @param cipher the CryptoCipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoOutputStream(WritableByteChannel channel, CryptoCipher cipher,
+                               int bufferSize, byte[] key, byte[] iv) throws IOException {
+    this(channel, cipher, bufferSize, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @param output the Output instance.
+   * @param cipher the CryptoCipher instance.
+   * @param bufferSize the bufferSize.
+   * @param key crypto key for the cipher.
+   * @param iv Initialization vector for the cipher.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoOutputStream(Output output, CryptoCipher cipher, int bufferSize,
+                               byte[] key, byte[] iv)
+      throws IOException {
+    this(output, cipher, bufferSize, key, iv, 0);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @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 iv Initialization vector for the cipher.
+   * @param streamOffset the start offset in the data.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoOutputStream(Properties props, OutputStream out, byte[] key,
+                               byte[] iv, long streamOffset)
+      throws IOException {
+    this(out, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props),
+        Utils.getBufferSize(props), key, iv, streamOffset);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @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 iv Initialization vector for the cipher.
+   * @param streamOffset the start offset in the data.
+   * @throws IOException if an I/O error occurs.
+   */
+  public CTRCryptoOutputStream(Properties props, WritableByteChannel out,
+                               byte[] key, byte[] iv, long streamOffset)
+      throws IOException {
+    this(out, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props),
+        Utils.getBufferSize(props), key, iv, streamOffset);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @param out the output stream.
+   * @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 CTRCryptoOutputStream(OutputStream out, CryptoCipher cipher, int bufferSize,
+                               byte[] key, byte[] iv, long streamOffset) throws IOException {
+    this(new StreamOutput(out, bufferSize), cipher,
+        bufferSize, key, iv, streamOffset);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @param channel the WritableByteChannel instance.
+   * @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 CTRCryptoOutputStream(WritableByteChannel channel, CryptoCipher cipher,
+                               int bufferSize, byte[] key, byte[] iv,
+                               long streamOffset) throws IOException {
+    this(new ChannelOutput(channel), cipher,
+        bufferSize, key, iv, streamOffset);
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.stream.CTRCryptoOutputStream}.
+   *
+   * @param output the output stream.
+   * @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 CTRCryptoOutputStream(Output output, CryptoCipher cipher, int bufferSize,
+                               byte[] key, byte[] iv, long streamOffset)
+      throws IOException {
+    super(output, cipher, bufferSize, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
+
+    Utils.checkStreamCipher(cipher);
+    this.streamOffset = streamOffset;
+    this.initIV = iv.clone();
+    this.iv = iv.clone();
+
+    resetCipher();
+  }
+
+  /**
+   * Does the encryption, input is {@link #inBuffer} and output is
+   * {@link #outBuffer}.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  protected void encrypt() throws IOException {
+    Utils.checkState(inBuffer.position() >= padding);
+    if (inBuffer.position() == padding) {
+      // There is no real data in the inBuffer.
+      return;
+    }
+
+    inBuffer.flip();
+    outBuffer.clear();
+    encryptBuffer(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);
+      padding = 0;
+    }
+
+    final int len = output.write(outBuffer);
+    streamOffset += len;
+    if (cipherReset) {
+      /*
+       * This code is generally not executed since the encryptor usually
+       * maintains encryption context (e.g. the counter) internally. However,
+       * some implementations can't maintain context so a re-init is necessary
+       * after each encryption call.
+       */
+      resetCipher();
+    }
+  }
+
+  /**
+   * Does final encryption of the last data.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  @Override
+  protected void encryptFinal() throws IOException {
+    // The same as the normal encryption for Counter mode
+    encrypt();
+  }
+
+  /**
+   * Overrides the {@link CryptoOutputStream#initCipher()}.
+   * Initializes the cipher.
+   */
+  @Override
+  protected void initCipher() {
+    // Do nothing for initCipher
+    // Will reset the cipher considering the stream offset
+  }
+
+  /**
+   * Resets the {@link #cipher}: calculate counter and {@link #padding}.
+   *
+   * @throws IOException if an I/O error occurs.
+   */
+  private void resetCipher() throws IOException {
+    final long counter =
+        streamOffset / cipher.getTransformation().getAlgorithmBlockSize();
+    padding =
+        (byte)(streamOffset % cipher.getTransformation().getAlgorithmBlockSize());
+    inBuffer.position(padding); // Set proper position for input data.
+
+    Utils.calculateIV(initIV, counter, iv);
+    try {
+      cipher.init(CryptoCipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
+    } catch (InvalidKeyException e) {
+      throw new IOException(e);
+    }catch (InvalidAlgorithmParameterException e) {
+      throw new IOException(e);
+    }
+    cipherReset = false;
+  }
+
+  /**
+   * Does the encryption if the ByteBuffer data.
+   *
+   * @param out the output ByteBuffer.
+   * @throws IOException if an I/O error occurs.
+   */
+  private void encryptBuffer(ByteBuffer out)
+      throws IOException {
+    int inputSize = inBuffer.remaining();
+    try {
+      int n = cipher.update(inBuffer, out);
+      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.
+         */
+        cipher.doFinal(inBuffer, out);
+        cipherReset = true;
+      }
+    } catch (ShortBufferException e) {
+      throw new IOException(e);
+    } catch (BadPaddingException e) {
+      throw new IOException(e);
+    } catch (IllegalBlockSizeException e) {
+      throw new IOException(e);
+    }
+  }
+
+  /**
+   * Get the underlying stream offset
+   *
+   * @return the underlying stream offset
+   */
+  protected long getStreamOffset() {
+    return streamOffset;
+  }
+
+  /**
+   * Set the underlying stream offset
+   *
+   * @param streamOffset the underlying stream offset
+   */
+  protected void setStreamOffset(long streamOffset) {
+    this.streamOffset = streamOffset;
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/stream/CipherInputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/stream/CipherInputStream.java b/src/main/java/org/apache/commons/crypto/stream/CipherInputStream.java
deleted file mode 100644
index 83df143..0000000
--- a/src/main/java/org/apache/commons/crypto/stream/CipherInputStream.java
+++ /dev/null
@@ -1,559 +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.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.Cipher;
-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 CipherInputStream extends InputStream implements
-    ReadableByteChannel {
-  private final byte[] oneByteBuf = new byte[1];
-
-  /**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 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 CipherInputStream}.
-   *
-   * @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 CipherInputStream(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 CipherInputStream}.
-   *
-   * @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 CipherInputStream(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 CipherInputStream}.
-   *
-   * @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 CipherInputStream(InputStream in, Cipher cipher, int bufferSize,
-                           Key key, AlgorithmParameterSpec params) throws IOException {
-    this(new StreamInput(in, bufferSize), cipher, bufferSize, key, params);
-  }
-
-  /**
-   * Constructs a {@link CipherInputStream}.
-   *
-   * @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 CipherInputStream(ReadableByteChannel in, Cipher cipher,
-                           int bufferSize, Key key, AlgorithmParameterSpec params) throws IOException {
-    this(new ChannelInput(in), cipher, bufferSize, key, params);
-  }
-
-  /**
-   * Constructs a {@link CipherInputStream}.
-   *
-   * @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 CipherInputStream(Input input, Cipher 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 CipherInputStream},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 CipherInputStream},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 Cipher.
-   *
-   * @return the cipher instance.
-   */
-  protected Cipher 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(Cipher.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);
-  }
-}


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

Posted by sd...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/native/org/apache/commons/crypto/random/OpensslCryptoRandomNative.c
----------------------------------------------------------------------
diff --git a/src/main/native/org/apache/commons/crypto/random/OpensslCryptoRandomNative.c b/src/main/native/org/apache/commons/crypto/random/OpensslCryptoRandomNative.c
new file mode 100644
index 0000000..58e64fb
--- /dev/null
+++ b/src/main/native/org/apache/commons/crypto/random/OpensslCryptoRandomNative.c
@@ -0,0 +1,335 @@
+/**
+ * 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.
+ */
+
+#include "org_apache_commons_crypto_random.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef UNIX
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#endif
+
+#ifdef WINDOWS
+#include <windows.h>
+#endif
+
+#include "OpensslCryptoRandomNative.h"
+
+#ifdef UNIX
+static void * (*dlsym_CRYPTO_malloc) (int, const char *, int);
+static void (*dlsym_CRYPTO_free) (void *);
+static int (*dlsym_CRYPTO_num_locks) (void);
+static void (*dlsym_CRYPTO_set_locking_callback) (void (*)());
+static void (*dlsym_CRYPTO_set_id_callback) (unsigned long (*)());
+static void (*dlsym_ENGINE_load_rdrand) (void);
+static ENGINE * (*dlsym_ENGINE_by_id) (const char *);
+static int (*dlsym_ENGINE_init) (ENGINE *);
+static int (*dlsym_ENGINE_set_default) (ENGINE *, unsigned int);
+static int (*dlsym_ENGINE_finish) (ENGINE *);
+static int (*dlsym_ENGINE_free) (ENGINE *);
+static void (*dlsym_ENGINE_cleanup) (void);
+static int (*dlsym_RAND_bytes) (unsigned char *, int);
+static unsigned long (*dlsym_ERR_get_error) (void);
+#endif
+
+#ifdef WINDOWS
+typedef void * (__cdecl *__dlsym_CRYPTO_malloc) (int, const char *, int);
+typedef void (__cdecl *__dlsym_CRYPTO_free) (void *);
+typedef int (__cdecl *__dlsym_CRYPTO_num_locks) (void);
+typedef void (__cdecl *__dlsym_CRYPTO_set_locking_callback)  \
+              (void (*)(int, int, char *, int);
+typedef void (__cdecl *__dlsym_ENGINE_load_rdrand) (void);
+typedef ENGINE * (__cdecl *__dlsym_ENGINE_by_id) (const char *);
+typedef int (__cdecl *__dlsym_ENGINE_init) (ENGINE *);
+typedef int (__cdecl *__dlsym_ENGINE_set_default) (ENGINE *, unsigned int);
+typedef int (__cdecl *__dlsym_ENGINE_finish) (ENGINE *);
+typedef int (__cdecl *__dlsym_ENGINE_free) (ENGINE *);
+typedef void (__cdecl *__dlsym_ENGINE_cleanup) (void);
+typedef int (__cdecl *__dlsym_RAND_bytes) (unsigned char *, int);
+typedef unsigned long (__cdecl *__dlsym_ERR_get_error) (void);
+static __dlsym_CRYPTO_malloc dlsym_CRYPTO_malloc;
+static __dlsym_CRYPTO_free dlsym_CRYPTO_free;
+static __dlsym_CRYPTO_num_locks dlsym_CRYPTO_num_locks;
+static __dlsym_CRYPTO_set_locking_callback dlsym_CRYPTO_set_locking_callback;
+static __dlsym_ENGINE_load_rdrand dlsym_ENGINE_load_rdrand;
+static __dlsym_ENGINE_by_id dlsym_ENGINE_by_id;
+static __dlsym_ENGINE_init dlsym_ENGINE_init;
+static __dlsym_ENGINE_set_default dlsym_ENGINE_set_default;
+static __dlsym_ENGINE_finish dlsym_ENGINE_finish;
+static __dlsym_ENGINE_free dlsym_ENGINE_free;
+static __dlsym_ENGINE_cleanup dlsym_ENGINE_cleanup;
+static __dlsym_RAND_bytes dlsym_RAND_bytes;
+static __dlsym_ERR_get_error dlsym_ERR_get_error;
+#endif
+
+static ENGINE * openssl_rand_init(void);
+static void openssl_rand_clean(ENGINE *eng, int clean_locks);
+static int openssl_rand_bytes(unsigned char *buf, int num);
+
+JNIEXPORT void JNICALL Java_org_apache_commons_crypto_random_OpensslCryptoRandomNative_initSR
+    (JNIEnv *env, jclass clazz)
+{
+  char msg[1000];
+#ifdef UNIX
+  void *openssl = dlopen(COMMONS_CRYPTO_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL);
+#endif
+
+#ifdef WINDOWS
+  HMODULE openssl = LoadLibrary(COMMONS_CRYPTO_OPENSSL_LIBRARY);
+#endif
+
+  if (!openssl) {
+    snprintf(msg, sizeof(msg), "Cannot load %s (%s)!", COMMONS_CRYPTO_OPENSSL_LIBRARY,  \
+        dlerror());
+    THROW(env, "java/lang/UnsatisfiedLinkError", msg);
+    return;
+  }
+
+#ifdef UNIX
+  dlerror();  // Clear any existing error
+  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_malloc, env, openssl, "CRYPTO_malloc");
+  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_free, env, openssl, "CRYPTO_free");
+  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_num_locks, env, openssl, "CRYPTO_num_locks");
+  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_set_locking_callback,  \
+                      env, openssl, "CRYPTO_set_locking_callback");
+  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_set_id_callback, env,  \
+                      openssl, "CRYPTO_set_id_callback");
+  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_load_rdrand, env,  \
+                      openssl, "ENGINE_load_rdrand");
+  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_by_id, env, openssl, "ENGINE_by_id");
+  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_init, env, openssl, "ENGINE_init");
+  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_set_default, env,  \
+                      openssl, "ENGINE_set_default");
+  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_finish, env, openssl, "ENGINE_finish");
+  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_free, env, openssl, "ENGINE_free");
+  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_cleanup, env, openssl, "ENGINE_cleanup");
+  LOAD_DYNAMIC_SYMBOL(dlsym_RAND_bytes, env, openssl, "RAND_bytes");
+  LOAD_DYNAMIC_SYMBOL(dlsym_ERR_get_error, env, openssl, "ERR_get_error");
+#endif
+
+#ifdef WINDOWS
+  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_malloc, dlsym_CRYPTO_malloc,  \
+                      env, openssl, "CRYPTO_malloc");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_free, dlsym_CRYPTO_free,  \
+                      env, openssl, "CRYPTO_free");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_num_locks, dlsym_CRYPTO_num_locks,  \
+                      env, openssl, "CRYPTO_num_locks");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_set_locking_callback,  \
+                      dlsym_CRYPTO_set_locking_callback,  \
+                      env, openssl, "CRYPTO_set_locking_callback");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_load_rdrand, dlsym_ENGINE_load_rdrand,  \
+                      env, openssl, "ENGINE_load_rdrand");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_by_id, dlsym_ENGINE_by_id,  \
+                      env, openssl, "ENGINE_by_id");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_init, dlsym_ENGINE_init,  \
+                      env, openssl, "ENGINE_init");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_set_default, dlsym_ENGINE_set_default,  \
+                      env, openssl, "ENGINE_set_default");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_finish, dlsym_ENGINE_finish,  \
+                      env, openssl, "ENGINE_finish");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_free, dlsym_ENGINE_free,  \
+                      env, openssl, "ENGINE_free");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_cleanup, dlsym_ENGINE_cleanup,  \
+                      env, openssl, "ENGINE_cleanup");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_RAND_bytes, dlsym_RAND_bytes,  \
+                      env, openssl, "RAND_bytes");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_ERR_get_error, dlsym_ERR_get_error,  \
+                      env, openssl, "ERR_get_error");
+#endif
+
+  openssl_rand_init();
+}
+
+JNIEXPORT jboolean JNICALL Java_org_apache_commons_crypto_random_OpensslCryptoRandomNative_nextRandBytes___3B
+    (JNIEnv *env, jobject object, jbyteArray bytes)
+{
+  if (NULL == bytes) {
+    THROW(env, "java/lang/NullPointerException", "Buffer cannot be null.");
+    return JNI_FALSE;
+  }
+  jbyte *b = (*env)->GetByteArrayElements(env, bytes, NULL);
+  if (NULL == b) {
+    THROW(env, "java/lang/InternalError", "Cannot get bytes array.");
+    return JNI_FALSE;
+  }
+  int b_len = (*env)->GetArrayLength(env, bytes);
+  int ret = openssl_rand_bytes((unsigned char *)b, b_len);
+  (*env)->ReleaseByteArrayElements(env, bytes, b, 0);
+
+  if (1 != ret) {
+    return JNI_FALSE;
+  }
+  return JNI_TRUE;
+}
+
+/**
+ * To ensure thread safety for random number generators, we need to call
+ * CRYPTO_set_locking_callback.
+ * http://wiki.openssl.org/index.php/Random_Numbers
+ * Example: crypto/threads/mttest.c
+ */
+
+#ifdef WINDOWS
+static void windows_locking_callback(int mode, int type, char *file, int line);
+static HANDLE *lock_cs;
+
+static void locks_setup(void)
+{
+  int i;
+  lock_cs = dlsym_CRYPTO_malloc(dlsym_CRYPTO_num_locks() * sizeof(HANDLE),  \
+      __FILE__, __LINE__);
+
+  for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) {
+    lock_cs[i] = CreateMutex(NULL, FALSE, NULL);
+  }
+  dlsym_CRYPTO_set_locking_callback((void (*)(int, int, char *, int))  \
+      windows_locking_callback);
+  /* id callback defined */
+}
+
+static void locks_cleanup(void)
+{
+  int i;
+  dlsym_CRYPTO_set_locking_callback(NULL);
+
+  for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) {
+    CloseHandle(lock_cs[i]);
+  }
+  dlsym_CRYPTO_free(lock_cs);
+}
+
+static void windows_locking_callback(int mode, int type, char *file, int line)
+{
+  UNUSED(file), UNUSED(line);
+
+  if (mode & CRYPTO_LOCK) {
+    WaitForSingleObject(lock_cs[type], INFINITE);
+  } else {
+    ReleaseMutex(lock_cs[type]);
+  }
+}
+#endif /* WINDOWS */
+
+#ifdef UNIX
+static void pthreads_locking_callback(int mode, int type, char *file, int line);
+static unsigned long pthreads_thread_id(void);
+static pthread_mutex_t *lock_cs;
+
+static void locks_setup(void)
+{
+  int i;
+  lock_cs = dlsym_CRYPTO_malloc(dlsym_CRYPTO_num_locks() *  \
+      sizeof(pthread_mutex_t), __FILE__, __LINE__);
+
+  for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) {
+    pthread_mutex_init(&(lock_cs[i]), NULL);
+  }
+
+  dlsym_CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
+  dlsym_CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
+}
+
+static void locks_cleanup(void)
+{
+  int i;
+  dlsym_CRYPTO_set_locking_callback(NULL);
+
+  for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) {
+    pthread_mutex_destroy(&(lock_cs[i]));
+  }
+
+  dlsym_CRYPTO_free(lock_cs);
+}
+
+static void pthreads_locking_callback(int mode, int type, char *file, int line)
+{
+  UNUSED(file), UNUSED(line);
+
+  if (mode & CRYPTO_LOCK) {
+    pthread_mutex_lock(&(lock_cs[type]));
+  } else {
+    pthread_mutex_unlock(&(lock_cs[type]));
+  }
+}
+
+static unsigned long pthreads_thread_id(void)
+{
+  return (unsigned long)syscall(SYS_gettid);
+}
+
+#endif /* UNIX */
+
+/**
+ * If using an Intel chipset with RDRAND, the high-performance hardware
+ * random number generator will be used.
+ */
+static ENGINE * openssl_rand_init(void)
+{
+  locks_setup();
+
+  dlsym_ENGINE_load_rdrand();
+  ENGINE *eng = dlsym_ENGINE_by_id("rdrand");
+
+  int ret = -1;
+  do {
+    if (NULL == eng) {
+      break;
+    }
+
+    int rc = dlsym_ENGINE_init(eng);
+    if (0 == rc) {
+      break;
+    }
+
+    rc = dlsym_ENGINE_set_default(eng, ENGINE_METHOD_RAND);
+    if (0 == rc) {
+      break;
+    }
+
+    ret = 0;
+  } while(0);
+
+  if (ret == -1) {
+    openssl_rand_clean(eng, 0);
+  }
+
+  return eng;
+}
+
+static void openssl_rand_clean(ENGINE *eng, int clean_locks)
+{
+  if (NULL != eng) {
+    dlsym_ENGINE_finish(eng);
+    dlsym_ENGINE_free(eng);
+  }
+
+  dlsym_ENGINE_cleanup();
+  if (clean_locks) {
+    locks_cleanup();
+  }
+}
+
+static int openssl_rand_bytes(unsigned char *buf, int num)
+{
+  return dlsym_RAND_bytes(buf, num);
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/native/org/apache/commons/crypto/random/OpensslSecureRandomNative.c
----------------------------------------------------------------------
diff --git a/src/main/native/org/apache/commons/crypto/random/OpensslSecureRandomNative.c b/src/main/native/org/apache/commons/crypto/random/OpensslSecureRandomNative.c
deleted file mode 100644
index 5dcfd1f..0000000
--- a/src/main/native/org/apache/commons/crypto/random/OpensslSecureRandomNative.c
+++ /dev/null
@@ -1,335 +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.
- */
-
-#include "org_apache_commons_crypto_random.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef UNIX
-#include <pthread.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#endif
-
-#ifdef WINDOWS
-#include <windows.h>
-#endif
-
-#include "OpensslSecureRandomNative.h"
-
-#ifdef UNIX
-static void * (*dlsym_CRYPTO_malloc) (int, const char *, int);
-static void (*dlsym_CRYPTO_free) (void *);
-static int (*dlsym_CRYPTO_num_locks) (void);
-static void (*dlsym_CRYPTO_set_locking_callback) (void (*)());
-static void (*dlsym_CRYPTO_set_id_callback) (unsigned long (*)());
-static void (*dlsym_ENGINE_load_rdrand) (void);
-static ENGINE * (*dlsym_ENGINE_by_id) (const char *);
-static int (*dlsym_ENGINE_init) (ENGINE *);
-static int (*dlsym_ENGINE_set_default) (ENGINE *, unsigned int);
-static int (*dlsym_ENGINE_finish) (ENGINE *);
-static int (*dlsym_ENGINE_free) (ENGINE *);
-static void (*dlsym_ENGINE_cleanup) (void);
-static int (*dlsym_RAND_bytes) (unsigned char *, int);
-static unsigned long (*dlsym_ERR_get_error) (void);
-#endif
-
-#ifdef WINDOWS
-typedef void * (__cdecl *__dlsym_CRYPTO_malloc) (int, const char *, int);
-typedef void (__cdecl *__dlsym_CRYPTO_free) (void *);
-typedef int (__cdecl *__dlsym_CRYPTO_num_locks) (void);
-typedef void (__cdecl *__dlsym_CRYPTO_set_locking_callback)  \
-              (void (*)(int, int, char *, int);
-typedef void (__cdecl *__dlsym_ENGINE_load_rdrand) (void);
-typedef ENGINE * (__cdecl *__dlsym_ENGINE_by_id) (const char *);
-typedef int (__cdecl *__dlsym_ENGINE_init) (ENGINE *);
-typedef int (__cdecl *__dlsym_ENGINE_set_default) (ENGINE *, unsigned int);
-typedef int (__cdecl *__dlsym_ENGINE_finish) (ENGINE *);
-typedef int (__cdecl *__dlsym_ENGINE_free) (ENGINE *);
-typedef void (__cdecl *__dlsym_ENGINE_cleanup) (void);
-typedef int (__cdecl *__dlsym_RAND_bytes) (unsigned char *, int);
-typedef unsigned long (__cdecl *__dlsym_ERR_get_error) (void);
-static __dlsym_CRYPTO_malloc dlsym_CRYPTO_malloc;
-static __dlsym_CRYPTO_free dlsym_CRYPTO_free;
-static __dlsym_CRYPTO_num_locks dlsym_CRYPTO_num_locks;
-static __dlsym_CRYPTO_set_locking_callback dlsym_CRYPTO_set_locking_callback;
-static __dlsym_ENGINE_load_rdrand dlsym_ENGINE_load_rdrand;
-static __dlsym_ENGINE_by_id dlsym_ENGINE_by_id;
-static __dlsym_ENGINE_init dlsym_ENGINE_init;
-static __dlsym_ENGINE_set_default dlsym_ENGINE_set_default;
-static __dlsym_ENGINE_finish dlsym_ENGINE_finish;
-static __dlsym_ENGINE_free dlsym_ENGINE_free;
-static __dlsym_ENGINE_cleanup dlsym_ENGINE_cleanup;
-static __dlsym_RAND_bytes dlsym_RAND_bytes;
-static __dlsym_ERR_get_error dlsym_ERR_get_error;
-#endif
-
-static ENGINE * openssl_rand_init(void);
-static void openssl_rand_clean(ENGINE *eng, int clean_locks);
-static int openssl_rand_bytes(unsigned char *buf, int num);
-
-JNIEXPORT void JNICALL Java_org_apache_commons_crypto_random_OpensslSecureRandomNative_initSR
-    (JNIEnv *env, jclass clazz)
-{
-  char msg[1000];
-#ifdef UNIX
-  void *openssl = dlopen(COMMONS_CRYPTO_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL);
-#endif
-
-#ifdef WINDOWS
-  HMODULE openssl = LoadLibrary(COMMONS_CRYPTO_OPENSSL_LIBRARY);
-#endif
-
-  if (!openssl) {
-    snprintf(msg, sizeof(msg), "Cannot load %s (%s)!", COMMONS_CRYPTO_OPENSSL_LIBRARY,  \
-        dlerror());
-    THROW(env, "java/lang/UnsatisfiedLinkError", msg);
-    return;
-  }
-
-#ifdef UNIX
-  dlerror();  // Clear any existing error
-  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_malloc, env, openssl, "CRYPTO_malloc");
-  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_free, env, openssl, "CRYPTO_free");
-  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_num_locks, env, openssl, "CRYPTO_num_locks");
-  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_set_locking_callback,  \
-                      env, openssl, "CRYPTO_set_locking_callback");
-  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_set_id_callback, env,  \
-                      openssl, "CRYPTO_set_id_callback");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_load_rdrand, env,  \
-                      openssl, "ENGINE_load_rdrand");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_by_id, env, openssl, "ENGINE_by_id");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_init, env, openssl, "ENGINE_init");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_set_default, env,  \
-                      openssl, "ENGINE_set_default");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_finish, env, openssl, "ENGINE_finish");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_free, env, openssl, "ENGINE_free");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_cleanup, env, openssl, "ENGINE_cleanup");
-  LOAD_DYNAMIC_SYMBOL(dlsym_RAND_bytes, env, openssl, "RAND_bytes");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ERR_get_error, env, openssl, "ERR_get_error");
-#endif
-
-#ifdef WINDOWS
-  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_malloc, dlsym_CRYPTO_malloc,  \
-                      env, openssl, "CRYPTO_malloc");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_free, dlsym_CRYPTO_free,  \
-                      env, openssl, "CRYPTO_free");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_num_locks, dlsym_CRYPTO_num_locks,  \
-                      env, openssl, "CRYPTO_num_locks");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_set_locking_callback,  \
-                      dlsym_CRYPTO_set_locking_callback,  \
-                      env, openssl, "CRYPTO_set_locking_callback");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_load_rdrand, dlsym_ENGINE_load_rdrand,  \
-                      env, openssl, "ENGINE_load_rdrand");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_by_id, dlsym_ENGINE_by_id,  \
-                      env, openssl, "ENGINE_by_id");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_init, dlsym_ENGINE_init,  \
-                      env, openssl, "ENGINE_init");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_set_default, dlsym_ENGINE_set_default,  \
-                      env, openssl, "ENGINE_set_default");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_finish, dlsym_ENGINE_finish,  \
-                      env, openssl, "ENGINE_finish");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_free, dlsym_ENGINE_free,  \
-                      env, openssl, "ENGINE_free");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_cleanup, dlsym_ENGINE_cleanup,  \
-                      env, openssl, "ENGINE_cleanup");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_RAND_bytes, dlsym_RAND_bytes,  \
-                      env, openssl, "RAND_bytes");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ERR_get_error, dlsym_ERR_get_error,  \
-                      env, openssl, "ERR_get_error");
-#endif
-
-  openssl_rand_init();
-}
-
-JNIEXPORT jboolean JNICALL Java_org_apache_commons_crypto_random_OpensslSecureRandomNative_nextRandBytes___3B
-    (JNIEnv *env, jobject object, jbyteArray bytes)
-{
-  if (NULL == bytes) {
-    THROW(env, "java/lang/NullPointerException", "Buffer cannot be null.");
-    return JNI_FALSE;
-  }
-  jbyte *b = (*env)->GetByteArrayElements(env, bytes, NULL);
-  if (NULL == b) {
-    THROW(env, "java/lang/InternalError", "Cannot get bytes array.");
-    return JNI_FALSE;
-  }
-  int b_len = (*env)->GetArrayLength(env, bytes);
-  int ret = openssl_rand_bytes((unsigned char *)b, b_len);
-  (*env)->ReleaseByteArrayElements(env, bytes, b, 0);
-
-  if (1 != ret) {
-    return JNI_FALSE;
-  }
-  return JNI_TRUE;
-}
-
-/**
- * To ensure thread safety for random number generators, we need to call
- * CRYPTO_set_locking_callback.
- * http://wiki.openssl.org/index.php/Random_Numbers
- * Example: crypto/threads/mttest.c
- */
-
-#ifdef WINDOWS
-static void windows_locking_callback(int mode, int type, char *file, int line);
-static HANDLE *lock_cs;
-
-static void locks_setup(void)
-{
-  int i;
-  lock_cs = dlsym_CRYPTO_malloc(dlsym_CRYPTO_num_locks() * sizeof(HANDLE),  \
-      __FILE__, __LINE__);
-
-  for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) {
-    lock_cs[i] = CreateMutex(NULL, FALSE, NULL);
-  }
-  dlsym_CRYPTO_set_locking_callback((void (*)(int, int, char *, int))  \
-      windows_locking_callback);
-  /* id callback defined */
-}
-
-static void locks_cleanup(void)
-{
-  int i;
-  dlsym_CRYPTO_set_locking_callback(NULL);
-
-  for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) {
-    CloseHandle(lock_cs[i]);
-  }
-  dlsym_CRYPTO_free(lock_cs);
-}
-
-static void windows_locking_callback(int mode, int type, char *file, int line)
-{
-  UNUSED(file), UNUSED(line);
-
-  if (mode & CRYPTO_LOCK) {
-    WaitForSingleObject(lock_cs[type], INFINITE);
-  } else {
-    ReleaseMutex(lock_cs[type]);
-  }
-}
-#endif /* WINDOWS */
-
-#ifdef UNIX
-static void pthreads_locking_callback(int mode, int type, char *file, int line);
-static unsigned long pthreads_thread_id(void);
-static pthread_mutex_t *lock_cs;
-
-static void locks_setup(void)
-{
-  int i;
-  lock_cs = dlsym_CRYPTO_malloc(dlsym_CRYPTO_num_locks() *  \
-      sizeof(pthread_mutex_t), __FILE__, __LINE__);
-
-  for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) {
-    pthread_mutex_init(&(lock_cs[i]), NULL);
-  }
-
-  dlsym_CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
-  dlsym_CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
-}
-
-static void locks_cleanup(void)
-{
-  int i;
-  dlsym_CRYPTO_set_locking_callback(NULL);
-
-  for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) {
-    pthread_mutex_destroy(&(lock_cs[i]));
-  }
-
-  dlsym_CRYPTO_free(lock_cs);
-}
-
-static void pthreads_locking_callback(int mode, int type, char *file, int line)
-{
-  UNUSED(file), UNUSED(line);
-
-  if (mode & CRYPTO_LOCK) {
-    pthread_mutex_lock(&(lock_cs[type]));
-  } else {
-    pthread_mutex_unlock(&(lock_cs[type]));
-  }
-}
-
-static unsigned long pthreads_thread_id(void)
-{
-  return (unsigned long)syscall(SYS_gettid);
-}
-
-#endif /* UNIX */
-
-/**
- * If using an Intel chipset with RDRAND, the high-performance hardware
- * random number generator will be used.
- */
-static ENGINE * openssl_rand_init(void)
-{
-  locks_setup();
-
-  dlsym_ENGINE_load_rdrand();
-  ENGINE *eng = dlsym_ENGINE_by_id("rdrand");
-
-  int ret = -1;
-  do {
-    if (NULL == eng) {
-      break;
-    }
-
-    int rc = dlsym_ENGINE_init(eng);
-    if (0 == rc) {
-      break;
-    }
-
-    rc = dlsym_ENGINE_set_default(eng, ENGINE_METHOD_RAND);
-    if (0 == rc) {
-      break;
-    }
-
-    ret = 0;
-  } while(0);
-
-  if (ret == -1) {
-    openssl_rand_clean(eng, 0);
-  }
-
-  return eng;
-}
-
-static void openssl_rand_clean(ENGINE *eng, int clean_locks)
-{
-  if (NULL != eng) {
-    dlsym_ENGINE_finish(eng);
-    dlsym_ENGINE_free(eng);
-  }
-
-  dlsym_ENGINE_cleanup();
-  if (clean_locks) {
-    locks_cleanup();
-  }
-}
-
-static int openssl_rand_bytes(unsigned char *buf, int num)
-{
-  return dlsym_RAND_bytes(buf, num);
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/site/xdoc/userguide.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/userguide.xml b/src/site/xdoc/userguide.xml
index 0af471d..5accf0e 100644
--- a/src/site/xdoc/userguide.xml
+++ b/src/site/xdoc/userguide.xml
@@ -32,7 +32,7 @@
               </a>
             </td>
             <td>
-              The interface for SecureRandom.
+              The interface for CryptoRandom.
             </td>
           </tr>
           <tr>
@@ -62,7 +62,7 @@
         <ol style="list-style-type: decimal">
         <h4>Usage of Random API</h4>
         <p>
-          SecureRandom provides a cryptographically strong random number generators.
+          CryptoRandom provides a cryptographically strong random number generators.
           The default implementation will use Intel\ufffd Digital Random Number Generator (DRNG)
           for accelerating the random generation.
         </p>
@@ -73,13 +73,13 @@
               byte[] key = new byte[16];<br/>
               byte[] iv = new byte[16];<br/>
               Properties properties = new Properties();<br/>
-              //Gets the 'SecureRandom' instance.<br/>
-              SecureRandom secureRandom = SecureRandomFactory.getSecureRandom(properties);<br/>
+              //Gets the 'CryptoRandom' instance.<br/>
+              CryptoRandom CryptoRandom = CryptoRandomFactory.getCryptoRandom(properties);<br/>
               //Generates random bytes and places them into the byte array.<br/>
-              secureRandom.nextBytes(key);<br/>
-              secureRandom.nextBytes(iv);<br/>
-              //Closes the SecureRandom.<br/>
-              secureRandom.close();<br/>
+              CryptoRandom.nextBytes(key);<br/>
+              CryptoRandom.nextBytes(iv);<br/>
+              //Closes the CryptoRandom.<br/>
+              CryptoRandom.close();<br/>
             </td>
           </tr>
         </table>
@@ -96,8 +96,8 @@
           <tr>
             <td>
               Properties properties = new Properties();<br/>
-              //Creates a Cipher instance with the transformation and properties.<br/>
-              Cipher cipher = Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, properties);<br/><br/>
+              //Creates a CryptoCipher instance with the transformation and properties.<br/>
+              CryptoCipher cipher = Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, properties);<br/><br/>
               String input = "hello world!";<br/>
               int inputOffset = 0;<br/>
               int inputLen = input.length();<br/>
@@ -121,7 +121,7 @@
             <td>
               Properties properties = new Properties();<br/>
               //Creates a Cipher instance with the transformation and properties.<br/>
-              Cipher cipher = Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, properties);<br/><br/>
+              CryptoCipher cipher = Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, properties);<br/><br/>
               int bufferSize = 4096;<br/>
               ByteBuffer inBuffer = ByteBuffer.allocateDirect(bufferSize);<br/>
               ByteBuffer outBuffer = ByteBuffer.allocateDirect(bufferSize);<br/>
@@ -140,9 +140,9 @@
 
         <h4>Usage of Stream API</h4>
         <p>
-          Stream provides the data encryption and decryption in stream manner. We provide CipherInputStream,
-          CTRCipherInputStream, PositionedCipherInputstream implementations for InputStream and CipherOutputStream,
-          CTRCipherOutputStream implementations for OutputStream.
+          Stream provides the data encryption and decryption in stream manner. We provide CryptoInputStream,
+          CTRCryptoInputStream, PositionedCryptoInputStream implementations for InputStream and CryptoOutputStream,
+          CTRCryptoOutputStream implementations for OutputStream.
         </p>
         <h5>Usage of stream encryption</h5>
         <table>
@@ -151,13 +151,13 @@
               int bufferSize = 4096;<br/>
               String input = "hello world!";<br/>
               byte[] decryptedData = new byte[1024];<br/>
-              //Encryption with CipherOutputStream.<br/>
+              //Encryption with CryptoOutputStream.<br/>
               //Initializes the cipher with ENCRYPT_MODE,key and iv.<br/>
               cipher.init(Cipher.ENCRYPT_MODE, key, iv);<br/>
               // Constructs the original OutputStream.<br/>
               OutputStream outputStream = new ByteArrayOutputStream();<br/>
-              //Constructs the instance of CipherOutputStream.<br/>
-              CipherOutputStream cos = new CipherOutputStream(outputStream, cipher, bufferSize, key, iv);<br/>
+              //Constructs the instance of CryptoOutputStream.<br/>
+              CryptoOutputStream cos = new CryptoOutputStream(outputStream, cipher, bufferSize, key, iv);<br/>
               cos.write(input.getBytes("UTF-8"));<br/>
               cos.flush();<br/>
               cos.close();<br/>
@@ -168,13 +168,13 @@
         <table>
           <tr>
             <td>
-              // Decryption with CipherInputStream.<br/>
+              // Decryption with CryptoInputStream.<br/>
               //Initializes the cipher with DECRYPT_MODE,key and iv.<br/>
               cipher.init(Cipher.DECRYPT_MODE, key, iv);<br/>
               //Constructs the original InputStream.<br/>
               InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());<br/>
-              //Constructs the instance of CipherInputStream.<br/>
-              CipherInputStream cis = new CipherInputStream(inputStream, cipher, bufferSize, key, iv);<br/>
+              //Constructs the instance of CryptoInputStream.<br/>
+              CryptoInputStream cis = new CryptoInputStream(inputStream, cipher, bufferSize, key, iv);<br/>
               int decryptedLen = cis.read(decryptedData, 0, 1024);<br/>
               cis.close();<br/>
             </td>

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java b/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java
index 67ab5c0..f60f29c 100644
--- a/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java
+++ b/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java
@@ -48,7 +48,7 @@ public abstract class AbstractCipherTest {
       0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
   static final byte[] IV = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
       0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
-  Cipher enc, dec;
+  CryptoCipher enc, dec;
 
   @Before
   public void setup() {
@@ -96,19 +96,19 @@ public abstract class AbstractCipherTest {
       GeneralSecurityException, IOException {
     ByteBuffer decResult = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE);
     ByteBuffer encResult = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE);
-    Cipher enc, dec;
+    CryptoCipher enc, dec;
 
     enc = getCipher(transformation);
     dec = getCipher(transformation);
 
     try {
-      enc.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
+      enc.init(CryptoCipher.ENCRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
     } catch (Exception e) {
       Assert.fail("AES failed initialisation - " + e.toString());
     }
 
     try {
-      dec.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
+      dec.init(CryptoCipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
     } catch (Exception e) {
       Assert.fail("AES failed initialisation - " + e.toString());
     }
@@ -219,21 +219,21 @@ public abstract class AbstractCipherTest {
     dec = getCipher(transformation);
 
     try {
-      enc.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
+      enc.init(CryptoCipher.ENCRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
     } catch (Exception e) {
       Assert.fail("AES failed initialisation - " + e.toString());
     }
 
     try {
-      dec.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
+      dec.init(CryptoCipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
     } catch (Exception e) {
       Assert.fail("AES failed initialisation - " + e.toString());
     }
   }
 
-  private Cipher getCipher(CipherTransformation transformation) {
+  private CryptoCipher getCipher(CipherTransformation transformation) {
     try {
-      return (Cipher) ReflectionUtils
+      return (CryptoCipher) ReflectionUtils
           .newInstance(ReflectionUtils.getClassByName(cipherClass), props,
               transformation);
     } catch (ClassNotFoundException e) {

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/cipher/CipherFactoryTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/cipher/CipherFactoryTest.java b/src/test/java/org/apache/commons/crypto/cipher/CipherFactoryTest.java
deleted file mode 100644
index cd995df..0000000
--- a/src/test/java/org/apache/commons/crypto/cipher/CipherFactoryTest.java
+++ /dev/null
@@ -1,57 +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.cipher;
-
-import java.security.GeneralSecurityException;
-import java.util.Properties;
-
-import org.apache.commons.crypto.conf.ConfigurationKeys;
-
-import junit.framework.Assert;
-import org.junit.Test;
-
-public class CipherFactoryTest {
-  @Test
-  public void testDefaultCipher() throws GeneralSecurityException {
-    Cipher defaultCipher = CipherFactory.getInstance(
-        CipherTransformation.AES_CBC_NOPADDING);
-    Assert.assertEquals(OpensslCipher.class.getName(),
-        defaultCipher.getClass().getName());
-  }
-
-  @Test
-  public void testEmptyCipher() throws GeneralSecurityException {
-    Properties properties = new Properties();
-    properties.put(ConfigurationKeys.COMMONS_CRYPTO_CIPHER_CLASSES_KEY, "");
-    Cipher defaultCipher = CipherFactory.getInstance(
-        CipherTransformation.AES_CBC_NOPADDING, properties);
-    Assert.assertEquals(OpensslCipher.class.getName(),
-        defaultCipher.getClass().getName());
-  }
-
-  @Test
-  public void testInvalidCipher() throws GeneralSecurityException {
-    Properties properties = new Properties();
-    properties.put(ConfigurationKeys.COMMONS_CRYPTO_CIPHER_CLASSES_KEY,
-        "InvalidCipherName");
-    Cipher defaultCipher = CipherFactory.getInstance(
-        CipherTransformation.AES_CBC_NOPADDING, properties);
-    Assert.assertEquals(JceCipher.class.getName(),
-        defaultCipher.getClass().getName());
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/cipher/CryptoCipherFactoryTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/cipher/CryptoCipherFactoryTest.java b/src/test/java/org/apache/commons/crypto/cipher/CryptoCipherFactoryTest.java
new file mode 100644
index 0000000..3653cf9
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/cipher/CryptoCipherFactoryTest.java
@@ -0,0 +1,57 @@
+/**
+ * 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.cipher;
+
+import java.security.GeneralSecurityException;
+import java.util.Properties;
+
+import org.apache.commons.crypto.conf.ConfigurationKeys;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+public class CryptoCipherFactoryTest {
+  @Test
+  public void testDefaultCipher() throws GeneralSecurityException {
+    CryptoCipher defaultCipher = CryptoCipherFactory.getInstance(
+        CipherTransformation.AES_CBC_NOPADDING);
+    Assert.assertEquals(OpensslCipher.class.getName(),
+        defaultCipher.getClass().getName());
+  }
+
+  @Test
+  public void testEmptyCipher() throws GeneralSecurityException {
+    Properties properties = new Properties();
+    properties.put(ConfigurationKeys.COMMONS_CRYPTO_CIPHER_CLASSES_KEY, "");
+    CryptoCipher defaultCipher = CryptoCipherFactory.getInstance(
+        CipherTransformation.AES_CBC_NOPADDING, properties);
+    Assert.assertEquals(OpensslCipher.class.getName(),
+        defaultCipher.getClass().getName());
+  }
+
+  @Test
+  public void testInvalidCipher() throws GeneralSecurityException {
+    Properties properties = new Properties();
+    properties.put(ConfigurationKeys.COMMONS_CRYPTO_CIPHER_CLASSES_KEY,
+        "InvalidCipherName");
+    CryptoCipher defaultCipher = CryptoCipherFactory.getInstance(
+        CipherTransformation.AES_CBC_NOPADDING, properties);
+    Assert.assertEquals(JceCipher.class.getName(),
+        defaultCipher.getClass().getName());
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/random/AbstractRandomTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/random/AbstractRandomTest.java b/src/test/java/org/apache/commons/crypto/random/AbstractRandomTest.java
index d2919ea..1d1db88 100644
--- a/src/test/java/org/apache/commons/crypto/random/AbstractRandomTest.java
+++ b/src/test/java/org/apache/commons/crypto/random/AbstractRandomTest.java
@@ -24,11 +24,11 @@ import org.junit.Test;
 
 public abstract class AbstractRandomTest {
 
-  public abstract SecureRandom getSecureRandom() throws GeneralSecurityException;
+  public abstract CryptoRandom getCryptoRandom() throws GeneralSecurityException;
 
   @Test(timeout=120000)
   public void testRandomBytes() throws Exception {
-    SecureRandom random = getSecureRandom();
+    CryptoRandom random = getCryptoRandom();
     // len = 16
     checkRandomBytes(random, 16);
     // len = 32
@@ -44,7 +44,7 @@ public abstract class AbstractRandomTest {
    * Test will timeout if secure random implementation always returns a
    * constant value.
    */
-  private void checkRandomBytes(SecureRandom random, int len) {
+  private void checkRandomBytes(CryptoRandom random, int len) {
     byte[] bytes = new byte[len];
     byte[] bytes1 = new byte[len];
     random.nextBytes(bytes);

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/random/TestJavaCryptoRandom.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/random/TestJavaCryptoRandom.java b/src/test/java/org/apache/commons/crypto/random/TestJavaCryptoRandom.java
new file mode 100644
index 0000000..bb84bc7
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/random/TestJavaCryptoRandom.java
@@ -0,0 +1,40 @@
+/**
+ * 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.random;
+
+import java.security.GeneralSecurityException;
+import java.util.Properties;
+
+import org.apache.commons.crypto.conf.ConfigurationKeys;
+import static junit.framework.Assert.fail;
+
+public class TestJavaCryptoRandom extends AbstractRandomTest {
+
+  @Override
+  public CryptoRandom getCryptoRandom() throws GeneralSecurityException {
+    Properties props = new Properties();
+    props.setProperty(ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY,
+        JavaCryptoRandom.class.getName());
+    CryptoRandom random = CryptoRandomFactory.getCryptoRandom(props);
+    if ( !(random instanceof JavaCryptoRandom)) {
+      fail("The CryptoRandom should be: " + JavaCryptoRandom.class.getName());
+    }
+    return random;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/random/TestJavaSecureRandom.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/random/TestJavaSecureRandom.java b/src/test/java/org/apache/commons/crypto/random/TestJavaSecureRandom.java
deleted file mode 100644
index 2bbed66..0000000
--- a/src/test/java/org/apache/commons/crypto/random/TestJavaSecureRandom.java
+++ /dev/null
@@ -1,40 +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.random;
-
-import java.security.GeneralSecurityException;
-import java.util.Properties;
-
-import org.apache.commons.crypto.conf.ConfigurationKeys;
-import static junit.framework.Assert.fail;
-
-public class TestJavaSecureRandom extends AbstractRandomTest {
-
-  @Override
-  public SecureRandom getSecureRandom() throws GeneralSecurityException {
-    Properties props = new Properties();
-    props.setProperty(ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY,
-        JavaSecureRandom.class.getName());
-    SecureRandom random = SecureRandomFactory.getSecureRandom(props);
-    if ( !(random instanceof JavaSecureRandom)) {
-      fail("The SecureRandom should be: " + JavaSecureRandom.class.getName());
-    }
-    return random;
-  }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/random/TestOpensslCryptoRandom.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/random/TestOpensslCryptoRandom.java b/src/test/java/org/apache/commons/crypto/random/TestOpensslCryptoRandom.java
new file mode 100644
index 0000000..fede249
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/random/TestOpensslCryptoRandom.java
@@ -0,0 +1,40 @@
+/**
+ * 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.random;
+
+import java.security.GeneralSecurityException;
+import java.util.Properties;
+
+import org.apache.commons.crypto.conf.ConfigurationKeys;
+import static junit.framework.Assert.fail;
+
+public class TestOpensslCryptoRandom extends AbstractRandomTest {
+
+  @Override
+  public CryptoRandom getCryptoRandom() throws GeneralSecurityException {
+    Properties props = new Properties();
+    props.setProperty(ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY,
+        OpensslCryptoRandom.class.getName());
+    CryptoRandom random = CryptoRandomFactory.getCryptoRandom(props);
+    if ( !(random instanceof OpensslCryptoRandom)) {
+      fail("The CryptoRandom should be: " + OpensslCryptoRandom.class.getName());
+    }
+    return random;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/random/TestOpensslSecureRandom.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/random/TestOpensslSecureRandom.java b/src/test/java/org/apache/commons/crypto/random/TestOpensslSecureRandom.java
deleted file mode 100644
index 13224dd..0000000
--- a/src/test/java/org/apache/commons/crypto/random/TestOpensslSecureRandom.java
+++ /dev/null
@@ -1,40 +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.random;
-
-import java.security.GeneralSecurityException;
-import java.util.Properties;
-
-import org.apache.commons.crypto.conf.ConfigurationKeys;
-import static junit.framework.Assert.fail;
-
-public class TestOpensslSecureRandom extends AbstractRandomTest {
-
-  @Override
-  public SecureRandom getSecureRandom() throws GeneralSecurityException {
-    Properties props = new Properties();
-    props.setProperty(ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY,
-        OpensslSecureRandom.class.getName());
-    SecureRandom random = SecureRandomFactory.getSecureRandom(props);
-    if ( !(random instanceof OpensslSecureRandom)) {
-      fail("The SecureRandom should be: " + OpensslSecureRandom.class.getName());
-    }
-    return random;
-  }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/random/TestOsCryptoRandom.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/random/TestOsCryptoRandom.java b/src/test/java/org/apache/commons/crypto/random/TestOsCryptoRandom.java
new file mode 100644
index 0000000..9968c34
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/random/TestOsCryptoRandom.java
@@ -0,0 +1,28 @@
+/**
+ * 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.random;
+
+import java.util.Properties;
+
+public class TestOsCryptoRandom extends AbstractRandomTest{
+
+  @Override
+  public CryptoRandom getCryptoRandom() {
+    return new OsCryptoRandom(new Properties());
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/test/java/org/apache/commons/crypto/random/TestOsSecureRandom.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/random/TestOsSecureRandom.java b/src/test/java/org/apache/commons/crypto/random/TestOsSecureRandom.java
deleted file mode 100644
index de88511..0000000
--- a/src/test/java/org/apache/commons/crypto/random/TestOsSecureRandom.java
+++ /dev/null
@@ -1,28 +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.random;
-
-import java.util.Properties;
-
-public class TestOsSecureRandom extends AbstractRandomTest{
-
-  @Override
-  public SecureRandom getSecureRandom() {
-    return new OsSecureRandom(new Properties());
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/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
index 40b1487..a89e4d1 100644
--- a/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java
+++ b/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java
@@ -31,11 +31,8 @@ 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.cipher.*;
+import org.apache.commons.crypto.cipher.CryptoCipher;
 import org.apache.commons.crypto.utils.ReflectionUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -107,7 +104,7 @@ public abstract class AbstractCipherStreamTest {
   }
 
   private void doSkipTest(String cipherClass, boolean withChannel) throws IOException {
-    InputStream in = getCipherInputStream(new ByteArrayInputStream(encData),
+    InputStream in = getCryptoInputStream(new ByteArrayInputStream(encData),
         getCipher(cipherClass), defaultBufferSize, iv, withChannel);
     byte[] result = new byte[dataLen];
     int n1 = readAll(in, result, 0, dataLen / 3);
@@ -138,56 +135,56 @@ public abstract class AbstractCipherStreamTest {
 
   private void doByteBufferRead(String cipherClass, boolean withChannel) throws Exception {
     // Default buffer size, initial buffer position is 0
-    InputStream in = getCipherInputStream(new ByteArrayInputStream(encData),
+    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 = getCipherInputStream(new ByteArrayInputStream(encData),
+    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 = getCipherInputStream(new ByteArrayInputStream(encData),
+    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 = getCipherInputStream(new ByteArrayInputStream(encData),
+    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 = getCipherInputStream(new ByteArrayInputStream(encData),
+    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 = getCipherInputStream(new ByteArrayInputStream(encData),
+    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 = getCipherInputStream(new ByteArrayInputStream(encData),
+    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 = getCipherInputStream(new ByteArrayInputStream(encData),
+    in = getCryptoInputStream(new ByteArrayInputStream(encData),
         getCipher(cipherClass), smallBufferSize, iv, withChannel);
     buf.clear();
     byteBufferReadCheck(in, buf, 11);
@@ -198,8 +195,8 @@ public abstract class AbstractCipherStreamTest {
                                  boolean withChannel)
       throws Exception {
     baos.reset();
-    CipherOutputStream out =
-        getCipherOutputStream(baos, getCipher(cipherClass), defaultBufferSize,
+    CryptoOutputStream out =
+        getCryptoOutputStream(baos, getCipher(cipherClass), defaultBufferSize,
             iv, withChannel);
     ByteBuffer buf = ByteBuffer.allocateDirect(dataLen / 2);
     buf.put(data, 0, dataLen / 2);
@@ -220,7 +217,7 @@ public abstract class AbstractCipherStreamTest {
 
     out.flush();
 
-    InputStream in = getCipherInputStream(new ByteArrayInputStream(encData),
+    InputStream in = getCryptoInputStream(new ByteArrayInputStream(encData),
         getCipher(cipherClass), defaultBufferSize, iv, withChannel);
     buf = ByteBuffer.allocate(dataLen + 100);
     byteBufferReadCheck(in, buf, 0);
@@ -242,16 +239,16 @@ public abstract class AbstractCipherStreamTest {
   }
 
   private void prepareData() throws IOException {
-    Cipher cipher = null;
+    CryptoCipher cipher = null;
     try {
-      cipher = (Cipher)ReflectionUtils.newInstance(
+      cipher = (CryptoCipher)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,
+    OutputStream out = new CryptoOutputStream(baos, cipher, defaultBufferSize,
             new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
     out.write(data);
     out.flush();
@@ -259,30 +256,30 @@ public abstract class AbstractCipherStreamTest {
     encData = baos.toByteArray();
   }
 
-  protected CipherInputStream getCipherInputStream(ByteArrayInputStream bais,
-                                                   Cipher cipher,
+  protected CryptoInputStream getCryptoInputStream(ByteArrayInputStream bais,
+                                                   CryptoCipher cipher,
                                                    int bufferSize, byte[] iv,
                                                    boolean withChannel) throws
       IOException {
     if (withChannel) {
-      return new CipherInputStream(Channels.newChannel(bais), cipher,
+      return new CryptoInputStream(Channels.newChannel(bais), cipher,
           bufferSize, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
     } else {
-      return new CipherInputStream(bais, cipher, bufferSize,
+      return new CryptoInputStream(bais, cipher, bufferSize,
               new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
     }
   }
 
-  protected CipherOutputStream getCipherOutputStream(ByteArrayOutputStream baos,
-                                                     Cipher cipher,
+  protected CryptoOutputStream getCryptoOutputStream(ByteArrayOutputStream baos,
+                                                     CryptoCipher cipher,
                                                      int bufferSize, byte[] iv,
                                                      boolean withChannel) throws
       IOException {
     if (withChannel) {
-      return new CipherOutputStream(Channels.newChannel(baos), cipher,
+      return new CryptoOutputStream(Channels.newChannel(baos), cipher,
           bufferSize, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
     } else {
-      return new CipherOutputStream(baos, cipher, bufferSize,
+      return new CryptoOutputStream(baos, cipher, bufferSize,
               new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
     }
   }
@@ -302,9 +299,9 @@ public abstract class AbstractCipherStreamTest {
     return total;
   }
 
-  protected Cipher getCipher(String cipherClass) throws IOException {
+  protected CryptoCipher getCipher(String cipherClass) throws IOException {
     try {
-      return (Cipher)ReflectionUtils.newInstance(
+      return (CryptoCipher)ReflectionUtils.newInstance(
           ReflectionUtils.getClassByName(cipherClass), props, transformation);
     } catch (ClassNotFoundException cnfe) {
       throw new IOException("Illegal crypto cipher!");
@@ -339,7 +336,7 @@ public abstract class AbstractCipherStreamTest {
 
   private void doReadWriteTestForInputStream(int count, String encCipherClass,
                                              String decCipherClass, byte[] iv) throws IOException {
-    Cipher encCipher = getCipher(encCipherClass);
+    CryptoCipher encCipher = getCipher(encCipherClass);
     LOG.debug("Created a cipher object of type: " + encCipherClass);
 
     // Generate data
@@ -351,19 +348,19 @@ public abstract class AbstractCipherStreamTest {
 
     // Encrypt data
     ByteArrayOutputStream encryptedData = new ByteArrayOutputStream();
-    CipherOutputStream out =
-        getCipherOutputStream(encryptedData, encCipher, defaultBufferSize, iv,
+    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);
+    CryptoCipher decCipher = getCipher(decCipherClass);
     LOG.debug("Created a cipher object of type: " + decCipherClass);
 
     // Decrypt data
-    CipherInputStream in = getCipherInputStream(
+    CryptoInputStream in = getCryptoInputStream(
         new ByteArrayInputStream(encryptedData.toByteArray()), decCipher,
         defaultBufferSize, iv, false);
 
@@ -382,7 +379,7 @@ public abstract class AbstractCipherStreamTest {
         originalData, decryptedData);
 
     // Decrypt data byte-at-a-time
-    in = getCipherInputStream(
+    in = getCryptoInputStream(
         new ByteArrayInputStream(encryptedData.toByteArray()), decCipher,
         defaultBufferSize, iv, false);
 
@@ -402,7 +399,7 @@ public abstract class AbstractCipherStreamTest {
                                                      String encCipherClass,
                                                      String decCipherClass,
                                                      byte[] iv) throws IOException {
-    Cipher encCipher = getCipher(encCipherClass);
+    CryptoCipher encCipher = getCipher(encCipherClass);
     LOG.debug("Created a cipher object of type: " + encCipherClass);
 
     // Generate data
@@ -414,19 +411,19 @@ public abstract class AbstractCipherStreamTest {
 
     // Encrypt data
     ByteArrayOutputStream encryptedData = new ByteArrayOutputStream();
-    CipherOutputStream out =
-        getCipherOutputStream(encryptedData, encCipher, defaultBufferSize, iv,
+    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);
+    CryptoCipher decCipher = getCipher(decCipherClass);
     LOG.debug("Created a cipher object of type: " + decCipherClass);
 
     // Decrypt data
-    CipherInputStream in = getCipherInputStream(
+    CryptoInputStream in = getCryptoInputStream(
         new ByteArrayInputStream(encryptedData.toByteArray()), decCipher,
         defaultBufferSize, iv, true);
 
@@ -445,7 +442,7 @@ public abstract class AbstractCipherStreamTest {
         originalData, decryptedData);
 
     // Decrypt data byte-at-a-time
-    in = getCipherInputStream(new ByteArrayInputStream(
+    in = getCryptoInputStream(new ByteArrayInputStream(
         encryptedData.toByteArray()),decCipher,defaultBufferSize,iv,true);
 
     // Check

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/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
deleted file mode 100644
index 6f9b5f1..0000000
--- a/src/test/java/org/apache/commons/crypto/stream/CTRCipherStreamTest.java
+++ /dev/null
@@ -1,59 +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 CTRCipherStreamTest extends AbstractCipherStreamTest {
-
-  @Override
-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/ea89d802/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
new file mode 100644
index 0000000..0953196
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java
@@ -0,0 +1,59 @@
+/**
+ * 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.CryptoCipher;
+import org.apache.commons.crypto.cipher.CipherTransformation;
+
+public class CTRCryptoStreamTest extends AbstractCipherStreamTest {
+
+  @Override
+public void setUp() throws IOException {
+    transformation = CipherTransformation
+        .AES_CTR_NOPADDING;
+  }
+
+  @Override
+  protected CTRCryptoInputStream getCryptoInputStream
+      (ByteArrayInputStream bais, CryptoCipher 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, CryptoCipher 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/ea89d802/src/test/java/org/apache/commons/crypto/stream/PositionedCipherInputStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/PositionedCipherInputStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/PositionedCipherInputStreamTest.java
deleted file mode 100644
index 35bbf7a..0000000
--- a/src/test/java/org/apache/commons/crypto/stream/PositionedCipherInputStreamTest.java
+++ /dev/null
@@ -1,384 +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 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.OpensslCipher;
-import org.apache.commons.crypto.stream.input.Input;
-import org.apache.commons.crypto.utils.ReflectionUtils;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.security.SecureRandom;
-import java.util.Arrays;
-import java.util.Properties;
-import java.util.Random;
-
-public class PositionedCipherInputStreamTest {
-
-  private final int dataLen = 20000;
-  private byte[] testData = new byte[dataLen];
-  private byte[] encData;
-  private Properties props = new Properties();
-  private byte[] key = new byte[16];
-  private byte[] iv = new byte[16];
-  int bufferSize = 2048;
-  int bufferSizeLess = bufferSize - 1;
-  int bufferSizeMore = bufferSize + 1;
-  int length = 1024;
-  int lengthLess = length - 1;
-  int lengthMore = length + 1;
-
-  private final String jceCipherClass = JceCipher.class.getName();
-  private final String opensslCipherClass = OpensslCipher.class.getName();
-  private CipherTransformation transformation =
-                                CipherTransformation.AES_CTR_NOPADDING;
-
-  @Before
-  public void before() throws IOException {
-    Random random = new SecureRandom();
-    random.nextBytes(testData);
-    random.nextBytes(key);
-    random.nextBytes(iv);
-    prepareData();
-  }
-
-  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();
-    // encryption data
-    OutputStream out = new CipherOutputStream(baos, cipher, bufferSize,
-            new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
-    out.write(testData);
-    out.flush();
-    out.close();
-    encData = baos.toByteArray();
-  }
-
-  public void setUp() throws IOException {}
-
-  private PositionedCipherInputStream getCipherInputStream(Cipher cipher,
-                                                           int bufferSize) throws IOException {
-    return new PositionedCipherInputStream(new PositionedInputForTest(
-      Arrays.copyOf(encData, encData.length)), cipher, bufferSize, key, iv, 0);
-  }
-
-  @Test
-  public void doTest() throws Exception {
-    testCipher(jceCipherClass);
-    testCipher(opensslCipherClass);
-  }
-
-  private void testCipher(String cipherClass) throws Exception {
-    doPositionedReadTests(cipherClass);
-    doReadFullyTests(cipherClass);
-    doSeekTests(cipherClass);
-    doMultipleReadTest(cipherClass);
-  }
-
-  // when there are multiple positioned read actions and one read action,
-  // they will not interfere each other.
-  private void doMultipleReadTest(String cipherClass) throws Exception {
-    PositionedCipherInputStream in = getCipherInputStream(
-            getCipher(cipherClass), bufferSize);
-    int position = 0;
-    while (in.available() > 0) {
-      ByteBuffer buf = ByteBuffer.allocate(length);
-      byte[] bytes1 = new byte[length];
-      byte[] bytes2 = new byte[lengthLess];
-      // do the read and position read
-      int pn1 = in.read(position, bytes1, 0, length);
-      int n = in.read(buf);
-      int pn2 = in.read(position, bytes2, 0, lengthLess);
-
-      // verify the result
-      if (pn1 > 0) {
-        compareByteArray(testData, position, bytes1, pn1);
-      }
-
-      if (pn2 > 0) {
-        compareByteArray(testData, position, bytes2, pn2);
-      }
-
-      if (n > 0) {
-        compareByteArray(testData, position, buf.array(), n);
-        position += n;
-      } else {
-        break;
-      }
-    }
-    in.close();
-  }
-
-  private void doPositionedReadTests(String cipherClass) throws Exception {
-    // test with different bufferSize when position = 0
-    testPositionedReadLoop(cipherClass, 0, length, bufferSize, dataLen);
-    testPositionedReadLoop(cipherClass, 0, length, bufferSizeLess, dataLen);
-    testPositionedReadLoop(cipherClass, 0, length, bufferSizeMore, dataLen);
-    // test with different position when bufferSize = 2048
-    testPositionedReadLoop(cipherClass, dataLen / 2, length, bufferSize, dataLen);
-    testPositionedReadLoop(cipherClass, dataLen / 2 - 1, length,
-            bufferSizeLess, dataLen);
-    testPositionedReadLoop(cipherClass, dataLen / 2 + 1, length,
-            bufferSizeMore, dataLen);
-    // position = -1 or position = max length, read nothing and return -1
-    testPositionedReadNone(cipherClass, -1, length, bufferSize);
-    testPositionedReadNone(cipherClass, dataLen, length, bufferSize);
-  }
-
-  private void doReadFullyTests(String cipherClass) throws Exception {
-    // test with different bufferSize when position = 0
-    testReadFullyLoop(cipherClass, 0, length, bufferSize, dataLen);
-    testReadFullyLoop(cipherClass, 0, length, bufferSizeLess, dataLen);
-    testReadFullyLoop(cipherClass, 0, length, bufferSizeMore, dataLen);
-    // test with different length when position = 0
-    testReadFullyLoop(cipherClass, 0, length, bufferSize, dataLen);
-    testReadFullyLoop(cipherClass, 0, lengthLess, bufferSize, dataLen);
-    testReadFullyLoop(cipherClass, 0, lengthMore, bufferSize, dataLen);
-    // test read fully failed
-    testReadFullyFailed(cipherClass, -1, length, bufferSize);
-    testReadFullyFailed(cipherClass, dataLen, length, bufferSize);
-    testReadFullyFailed(cipherClass, dataLen - length + 1, length, bufferSize);
-  }
-
-  private void doSeekTests(String cipherClass) throws Exception {
-    // test with different length when position = 0
-    testSeekLoop(cipherClass, 0, length, bufferSize);
-    testSeekLoop(cipherClass, 0, lengthLess, bufferSize);
-    testSeekLoop(cipherClass, 0, lengthMore, bufferSize);
-    // there should be none data read when position = dataLen
-    testSeekLoop(cipherClass, dataLen, length, bufferSize);
-    // test exception when position = -1
-    testSeekFailed(cipherClass, -1, bufferSize);
-  }
-
-  private void testSeekLoop(String cipherClass, int position, int length,
-      int bufferSize) throws Exception {
-    PositionedCipherInputStream in = getCipherInputStream(
-            getCipher(cipherClass), bufferSize);
-    while (in.available() > 0) {
-      in.seek(position);
-      ByteBuffer buf = ByteBuffer.allocate(length);
-      int n = in.read(buf);
-      if (n > 0) {
-        compareByteArray(testData, position, buf.array(), n);
-        position += n;
-      } else {
-        break;
-      }
-    }
-    in.close();
-  }
-
-  // test for the out of index position, eg, -1.
-  private void testSeekFailed(String cipherClass, int position,
-      int bufferSize) throws Exception {
-    PositionedCipherInputStream in = getCipherInputStream(
-            getCipher(cipherClass), bufferSize);
-    try {
-      in.seek(position);
-      Assert.fail("Excepted exception for cannot seek to negative offset.");
-    } catch (IllegalArgumentException iae) {
-    }
-    in.close();
-  }
-
-  private void testPositionedReadLoop(String cipherClass, int position,
-      int length, int bufferSize, int total) throws Exception {
-    PositionedCipherInputStream in = getCipherInputStream(
-            getCipher(cipherClass), bufferSize);
-    // do the position read until the end of data
-    while (position < total) {
-      byte[] bytes = new byte[length];
-      int n = in.read(position, bytes, 0, length);
-      if (n >= 0) {
-        compareByteArray(testData, position, bytes, n);
-        position += n;
-      } else {
-        break;
-      }
-    }
-    in.close();
-  }
-
-  // test for the out of index position, eg, -1.
-  private void testPositionedReadNone(String cipherClass, int position,
-      int length, int bufferSize) throws Exception {
-    PositionedCipherInputStream in = getCipherInputStream(
-            getCipher(cipherClass), bufferSize);
-    byte[] bytes = new byte[length];
-    int n = in.read(position, bytes, 0, length);
-    Assert.assertEquals(n, -1);
-    in.close();
-  }
-
-  private void testReadFullyLoop(String cipherClass,int position,
-      int length, int bufferSize, int total) throws Exception {
-    PositionedCipherInputStream in = getCipherInputStream(
-            getCipher(cipherClass), bufferSize);
-
-    // do the position read full until remain < length
-    while (position + length <= total) {
-      byte[] bytes = new byte[length];
-      in.readFully(position, bytes, 0, length);
-      compareByteArray(testData, position, bytes, length);
-      position += length;
-    }
-
-    in.close();
-  }
-
-  // test for the End of file reached before reading fully
-  private void testReadFullyFailed(String cipherClass, int position,
-      int length, int bufferSize) throws Exception {
-    PositionedCipherInputStream in = getCipherInputStream(
-            getCipher(cipherClass), bufferSize);
-    byte[] bytes = new byte[length];
-    try {
-      in.readFully(position, bytes, 0, length);
-      Assert.fail("Excepted EOFException.");
-    } catch (IOException ioe) {
-      // excepted exception
-    }
-    in.close();
-  }
-
-  // compare the data from pos with length and data2 from 0 with length
-  private void compareByteArray(byte[] data1, int pos, byte[] data2, int length) {
-    byte[] expectedData = new byte[length];
-    byte[] realData = new byte[length];
-    // get the expected data with the position and length
-    System.arraycopy(data1, pos, expectedData, 0, length);
-    // get the real data
-    System.arraycopy(data2, 0, realData, 0, length);
-    Assert.assertArrayEquals(expectedData, realData);
-  }
-
-  private 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!");
-    }
-  }
-
-  class PositionedInputForTest implements Input {
-
-    byte[] data;
-    long pos;
-    long count;
-
-    public PositionedInputForTest(byte[] data) {
-      this.data = data;
-      this.pos = 0;
-      this.count = data.length;
-    }
-
-    @Override
-    public int read(ByteBuffer dst) throws IOException {
-      int remaining = (int)(count - pos);
-      if(remaining <= 0) {
-        return -1;
-      }
-
-      int length = Math.min(dst.remaining(), remaining);
-      dst.put(data, (int)pos, length);
-      pos += length;
-      return length;
-    }
-
-    @Override
-    public long skip(long n) throws IOException {
-      if (n <= 0) {
-        return 0;
-      }
-
-      long remaining = count - pos;
-      if(remaining < n) {
-        n = remaining;
-      }
-      pos += n;
-
-      return n;
-    }
-
-    @Override
-    public int read(long position, byte[] buffer, int offset, int length)
-            throws IOException {
-      if (buffer == null) {
-        throw new NullPointerException();
-      } else if (offset < 0 || length < 0 || length > buffer.length - offset) {
-        throw new IndexOutOfBoundsException();
-      }
-
-      if (position < 0 || position >= count) {
-        return -1;
-      }
-
-      long avail = count - position;
-      if (length > avail) {
-        length = (int)avail;
-      }
-      if (length <= 0) {
-        return 0;
-      }
-      System.arraycopy(data, (int)position, buffer, offset, length);
-      return length;
-    }
-
-    @Override
-    public void seek(long position) throws IOException {
-      if (pos < 0) {
-        throw new IOException("Negative seek offset");
-      } else if (position >= 0 && position < count) {
-        pos = position;
-      } else {
-        // to the end of file
-        pos = count;
-      }
-    }
-
-    @Override
-    public void close() throws IOException {
-    }
-
-    @Override
-    public int available() throws IOException {
-      return (int)(count - pos);
-    }
-  }
-}


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

Posted by sd...@apache.org.
CRYPTO-33: avoid shadowing JVM class
renaming Cipher/Stream/Random classes


Project: http://git-wip-us.apache.org/repos/asf/commons-crypto/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-crypto/commit/ea89d802
Tree: http://git-wip-us.apache.org/repos/asf/commons-crypto/tree/ea89d802
Diff: http://git-wip-us.apache.org/repos/asf/commons-crypto/diff/ea89d802

Branch: refs/heads/master
Commit: ea89d8023ed7c2a88c468df15994bdd9db922242
Parents: b532288
Author: Xianda Ke <xi...@intel.com>
Authored: Thu Apr 28 11:33:43 2016 +0800
Committer: Sun Dapeng <sd...@apache.org>
Committed: Fri Apr 29 17:07:42 2016 +0800

----------------------------------------------------------------------
 Makefile                                        |  10 +-
 README.md                                       |  85 +--
 .../apache/commons/crypto/cipher/Cipher.java    | 157 -----
 .../commons/crypto/cipher/CipherFactory.java    | 105 ----
 .../commons/crypto/cipher/CryptoCipher.java     | 157 +++++
 .../crypto/cipher/CryptoCipherFactory.java      | 105 ++++
 .../apache/commons/crypto/cipher/JceCipher.java |   6 +-
 .../apache/commons/crypto/cipher/Openssl.java   |   2 +-
 .../commons/crypto/cipher/OpensslCipher.java    |   6 +-
 .../commons/crypto/cipher/package-info.java     |   2 +-
 .../commons/crypto/conf/ConfigurationKeys.java  |  12 +-
 .../commons/crypto/random/CryptoRandom.java     |  36 ++
 .../crypto/random/CryptoRandomFactory.java      |  76 +++
 .../commons/crypto/random/JavaCryptoRandom.java |  76 +++
 .../commons/crypto/random/JavaSecureRandom.java |  76 ---
 .../crypto/random/OpensslCryptoRandom.java      | 143 +++++
 .../random/OpensslCryptoRandomNative.java       |  43 ++
 .../crypto/random/OpensslSecureRandom.java      | 143 -----
 .../random/OpensslSecureRandomNative.java       |  43 --
 .../commons/crypto/random/OsCryptoRandom.java   | 133 ++++
 .../commons/crypto/random/OsSecureRandom.java   | 133 ----
 .../commons/crypto/random/SecureRandom.java     |  36 --
 .../crypto/random/SecureRandomFactory.java      |  76 ---
 .../crypto/stream/CTRCipherInputStream.java     | 625 -------------------
 .../crypto/stream/CTRCipherOutputStream.java    | 385 ------------
 .../crypto/stream/CTRCryptoInputStream.java     | 625 +++++++++++++++++++
 .../crypto/stream/CTRCryptoOutputStream.java    | 385 ++++++++++++
 .../crypto/stream/CipherInputStream.java        | 559 -----------------
 .../crypto/stream/CipherOutputStream.java       | 438 -------------
 .../crypto/stream/CryptoInputStream.java        | 559 +++++++++++++++++
 .../crypto/stream/CryptoOutputStream.java       | 441 +++++++++++++
 .../stream/PositionedCipherInputStream.java     | 362 -----------
 .../stream/PositionedCryptoInputStream.java     | 362 +++++++++++
 .../crypto/stream/input/ChannelInput.java       |   2 +-
 .../commons/crypto/stream/input/Input.java      |   2 +-
 .../crypto/stream/input/StreamInput.java        |   2 +-
 .../crypto/stream/output/ChannelOutput.java     |   2 +-
 .../commons/crypto/stream/output/Output.java    |   2 +-
 .../crypto/stream/output/StreamOutput.java      |   4 +-
 .../commons/crypto/utils/ReflectionUtils.java   |   6 +-
 .../org/apache/commons/crypto/utils/Utils.java  |  26 +-
 .../crypto/random/OpensslCryptoRandomNative.c   | 335 ++++++++++
 .../crypto/random/OpensslSecureRandomNative.c   | 335 ----------
 src/site/xdoc/userguide.xml                     |  40 +-
 .../crypto/cipher/AbstractCipherTest.java       |  16 +-
 .../crypto/cipher/CipherFactoryTest.java        |  57 --
 .../crypto/cipher/CryptoCipherFactoryTest.java  |  57 ++
 .../crypto/random/AbstractRandomTest.java       |   6 +-
 .../crypto/random/TestJavaCryptoRandom.java     |  40 ++
 .../crypto/random/TestJavaSecureRandom.java     |  40 --
 .../crypto/random/TestOpensslCryptoRandom.java  |  40 ++
 .../crypto/random/TestOpensslSecureRandom.java  |  40 --
 .../crypto/random/TestOsCryptoRandom.java       |  28 +
 .../crypto/random/TestOsSecureRandom.java       |  28 -
 .../crypto/stream/AbstractCipherStreamTest.java |  81 ++-
 .../crypto/stream/CTRCipherStreamTest.java      |  59 --
 .../crypto/stream/CTRCryptoStreamTest.java      |  59 ++
 .../stream/PositionedCipherInputStreamTest.java | 384 ------------
 .../stream/PositionedCryptoInputStreamTest.java | 384 ++++++++++++
 59 files changed, 4201 insertions(+), 4276 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/Makefile
----------------------------------------------------------------------
diff --git a/Makefile b/Makefile
index 0b356fc..9190e25 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ include Makefile.common
 MVN:=mvn
 
 COMMONS_CRYPTO_OUT:=$(TARGET)/$(commons-crypto)-$(os_arch)
-COMMONS_CRYPTO_OBJ:=$(addprefix $(COMMONS_CRYPTO_OUT)/,OpensslSecureRandom.o OpensslNative.o)
+COMMONS_CRYPTO_OBJ:=$(addprefix $(COMMONS_CRYPTO_OUT)/,OpensslCryptoRandom.o OpensslNative.o)
 
 ifeq ($(OS_NAME),SunOS)
   TAR:= gtar
@@ -20,21 +20,21 @@ $(TARGET)/jni-classes/org/apache/commons/crypto/cipher/OpensslNative.class : $(S
 	@mkdir -p $(TARGET)/jni-classes
 	$(JAVAC) -source 1.6 -target 1.6 -d $(TARGET)/jni-classes -sourcepath $(SRC) $<
 
-$(TARGET)/jni-classes/org/apache/commons/crypto/random/OpensslSecureRandomNative.class : $(SRC)/org/apache/commons/crypto/random/OpensslSecureRandomNative.java
+$(TARGET)/jni-classes/org/apache/commons/crypto/random/OpensslCryptoRandomNative.class : $(SRC)/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java
 	@mkdir -p $(TARGET)/jni-classes
 	$(JAVAC) -source 1.6 -target 1.6 -d $(TARGET)/jni-classes -sourcepath $(SRC) $<
 
 $(TARGET)/jni-classes/org/apache/commons/crypto/cipher/OpensslNative.h: $(TARGET)/jni-classes/org/apache/commons/crypto/cipher/OpensslNative.class
 	$(JAVAH) -force -classpath $(TARGET)/jni-classes -o $@ org.apache.commons.crypto.cipher.OpensslNative
 
-$(TARGET)/jni-classes/org/apache/commons/crypto/random/OpensslSecureRandomNative.h: $(TARGET)/jni-classes/org/apache/commons/crypto/random/OpensslSecureRandomNative.class
-	$(JAVAH) -force -classpath $(TARGET)/jni-classes -o $@ org.apache.commons.crypto.random.OpensslSecureRandomNative
+$(TARGET)/jni-classes/org/apache/commons/crypto/random/OpensslCryptoRandomNative.h: $(TARGET)/jni-classes/org/apache/commons/crypto/random/OpensslCryptoRandomNative.class
+	$(JAVAH) -force -classpath $(TARGET)/jni-classes -o $@ org.apache.commons.crypto.random.OpensslCryptoRandomNative
 
 $(COMMONS_CRYPTO_OUT)/OpensslNative.o : $(SRC_NATIVE)/org/apache/commons/crypto/cipher/OpensslNative.c $(TARGET)/jni-classes/org/apache/commons/crypto/cipher/OpensslNative.h
 	@mkdir -p $(@D)
 	$(CC) $(CFLAGS) -c $< -o $@
 
-$(COMMONS_CRYPTO_OUT)/OpensslSecureRandom.o : $(SRC_NATIVE)/org/apache/commons/crypto/random/OpensslSecureRandomNative.c $(TARGET)/jni-classes/org/apache/commons/crypto/random/OpensslSecureRandomNative.h
+$(COMMONS_CRYPTO_OUT)/OpensslCryptoRandom.o : $(SRC_NATIVE)/org/apache/commons/crypto/random/OpensslCryptoRandomNative.c $(TARGET)/jni-classes/org/apache/commons/crypto/random/OpensslCryptoRandomNative.h
 	@mkdir -p $(@D)
 	$(CC) $(CFLAGS) -c $< -o $@
 

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index fdde241..d6f01e3 100644
--- a/README.md
+++ b/README.md
@@ -1,87 +1,10 @@
-Chimera [![Build Status](https://travis-ci.org/intel-hadoop/chimera.svg?branch=master)](https://travis-ci.org/intel-hadoop/chimera) is a cryptographic library optimized with AES-NI (Advanced Encryption Standard New Instructions). It provides Java API for both cipher level and Java stream level. Developers can use it to implement high performance AES encryption/decryption with the minimum code and effort. Please note that Chimera doesn't implement the cryptographic algorithm such as AES directly. It wraps to Openssl or JCE which implement the algorithms.
+Apache Commons Crypto is a cryptographic library optimized with AES-NI (Advanced Encryption Standard New Instructions). It provides Java API for both cipher level and Java stream level. Developers can use it to implement high performance AES encryption/decryption with the minimum code and effort. Please note that Apache Commons Crypto doesn't implement the cryptographic algorithm such as AES directly. It wraps to Openssl or JCE which implement the algorithms.
 
 ## Features
   * Cipher API for low level cryptographic operations.
-  * Java stream API (CipherInputStream/CipherOutputStream) for high level stream encyrption/decryption.
+  * Java stream API (CryptoInputStream/CryptoOutputStream) for high level stream encyrption/decryption.
   * Both optimized with high performance AES encryption/decryption. (1400 MB/s - 1700 MB/s throughput in modern Xeon processors).
   * JNI-based implementation to achieve comparable performance to the native C++ version based on Openssl.
-  * Portable across various operating systems (currently only Linux); Chimera loads the library according to your machine environment (It looks system properties, `os.name` and `os.arch`). 
-  * Simple usage. Add the chimera-(version).jar file to your classpath.
+  * Portable across various operating systems (currently only Linux); Apache Commons Crypto loads the library according to your machine environment (It looks system properties, `os.name` and `os.arch`).
+  * Simple usage. Add the commons-crypto-(version).jar file to your classpath.
   * [Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). Free for both commercial and non-commercial use.
-
-## Download
-  * Release version: http://central.maven.org/maven2/org/apache/commons/crypto/chimera/
-  * Snapshot version (the latest beta version): https://oss.sonatype.org/content/repositories/snapshots/org/apache/commons/crypto/chimera/
-
-### Using with Maven
-  * Chimera is available from Maven's central repository:  <http://central.maven.org/maven2/org/apache/commons/crypto/chimera>
-
-Add the following dependency to your pom.xml:
-
-    <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-crypto</artifactId>
-      <version>0.9.0</version>
-      <type>jar</type>
-      <scope>compile</scope>
-    </dependency>
-
-### Using with sbt
-
-```
-libraryDependencies += "org.apache.commons" % "commons-crypto" % "0.9.0"
-```
-
-## Usage 
-
-```java
-
-Properties properties = new Properties();
-properties.setProperty("chimera.crypto.cipher.classes", "org.apache.commons.crypto.cipher.OpensslCipher");
-
-Cipher cipher = Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, properties);
-byte[] key = new byte[16];
-byte[] iv = new byte[16];
-int bufferSize = 4096;
-String input = "hello world!";
-byte[] decryptedData = new byte[1024];
-// Encrypt
-ByteArrayOutputStream os = new ByteArrayOutputStream();
-CipherOutputStream cos = new CipherOutputStream(os, cipher, bufferSize,
-                                                new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
-cos.write(input.getBytes("UTF-8"));
-cos.flush();
-cos.close();
-
-// Decrypt
-CipherInputStream cis = new CipherInputStream(new ByteArrayInputStream(os.toByteArray()), cipher, bufferSize,
-                                              new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
-int decryptedLen = cis.read(decryptedData, 0, 1024);
-
-```
-
-### Configuration
-Currently, two ciphers are supported: JceCipher and OpensslCipher, you can configure which cipher to use as follows:
-
-    $ java -Dchimera.crypto.cipher.classes=org.apache.commons.crypto.cipher.OpensslCipher Sample
-    $ java -Dchimera.crypto.cipher.classes=org.apache.commons.crypto.cipher.JceCipher Sample
-
-More detailed information about the configurations are as follows.
-
-| Property Name | Default | Meaning         |
-| --------------|---------|-------------------------|
-| chimera.crypto.cipher.transformation | AES/CTR/NoPadding | The value is identical to the transformations described in the Cipher section of the Java Cryptography Architecture Standard Algorithm Name Documentation. Currently only "AES/CTR/NoPadding" algorithm is supported.|
-| chimera.crypto.cipher.classes | org.apache.commons.crypto.cipher.OpensslCipher, org.apache.commons.crypto.cipher.JceCipher | Comma-separated list of cipher classes which implement cipher algorithm of "AES/CTR/NoPadding". A cipher implementation encapsulates the encryption and decryption details. The first  available implementation appearing in this list will be used. |
-
-## Building from the source code
-Building from the source code is an option when your OS platform and CPU architecture is not supported. To build Chimera, you need JDK 1.7 or higher, OpenSSL 1.0.1c or higher, etc.
-
-    $ git clone https://github.com/intel-hadoop/chimera.git
-    $ cd chimera
-    $ mvn clean install
-
-A file `target/chimera-$(version).jar` is the product additionally containing the native library built for your platform.
-
-## Discussion
-For development related discussion, please go to [dev google group](https://groups.google.com/forum/#!forum/chimera-dev).
-For issues or bugs, please file tickets through [github](https://github.com/intel-hadoop/chimera/issues).

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/cipher/Cipher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/cipher/Cipher.java b/src/main/java/org/apache/commons/crypto/cipher/Cipher.java
deleted file mode 100644
index 3cbbe3a..0000000
--- a/src/main/java/org/apache/commons/crypto/cipher/Cipher.java
+++ /dev/null
@@ -1,157 +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.cipher;
-
-import java.io.Closeable;
-import java.nio.ByteBuffer;
-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;
-
-/**
- * The interface of cryptographic cipher for encryption and decryption.
- */
-public interface Cipher extends Closeable {
-
-  /**
-   * A constant representing encrypt mode.  The mode constant to be used
-   * when calling init method of the Cipher.
-   */
-  int ENCRYPT_MODE = javax.crypto.Cipher.ENCRYPT_MODE;
-
-  /**
-   * A constant representing decrypt mode.  The mode constant to be used 
-   * when calling init method of the Cipher.
-   */
-  int DECRYPT_MODE = javax.crypto.Cipher.DECRYPT_MODE;
-
-  /**
-   * Gets the CipherTransformation for this cipher.
-   *
-   * @return the CipherTransformation for this cipher.
-   */
-  CipherTransformation getTransformation();
-
-  /**
-   * Gets the properties for this cipher.
-   * 
-   * @return the properties for this cipher.
-   */
-  Properties getProperties();
-
-  /**
-   * Initializes the cipher with mode, key and iv.
-   * 
-   * @param mode {@link #ENCRYPT_MODE} or {@link #DECRYPT_MODE}
-   * @param key crypto key for the cipher
-   * @param params the algorithm parameters
-   * @throws InvalidKeyException if the given key is inappropriate for
-   * initializing this cipher, or its keysize exceeds the maximum allowable
-   * keysize (as determined from the configured jurisdiction policy files).
-   * @throws InvalidAlgorithmParameterException if the given algorithm
-   * parameters are inappropriate for this cipher, or this cipher requires
-   * algorithm parameters and <code>params</code> is null, or the given
-   * algorithm parameters imply a cryptographic strength that would exceed
-   * the legal limits (as determined from the configured jurisdiction
-   * policy files).
-   */
-  void init(int mode, Key key, AlgorithmParameterSpec params)
-      throws InvalidKeyException, InvalidAlgorithmParameterException;
-
-  /**
-   * Continues a multiple-part encryption/decryption operation. The data
-   * is encrypted or decrypted, depending on how this cipher was initialized.
-   * 
-   * @param inBuffer the input ByteBuffer
-   * @param outBuffer the output ByteBuffer
-   * @return int number of bytes stored in <code>output</code>
-   * @throws ShortBufferException if there is insufficient space
-   * in the output buffer
-   */
-  int update(ByteBuffer inBuffer, ByteBuffer outBuffer)
-      throws ShortBufferException;
-
-  /**
-   * Continues a multiple-part encryption/decryption operation. The data
-   * is encrypted or decrypted, depending on how this cipher was initialized.
-   *
-   * @param input the input byte array
-   * @param inputOffset the offset in input where the input starts
-   * @param inputLen the input length
-   * @param output the byte array for the result
-   * @param outputOffset the offset in output where the result is stored
-   * @return the number of bytes stored in output
-   * @throws ShortBufferException if there is insufficient space in the output byte array
-   */
-  int update(byte[] input, int inputOffset, int inputLen,
-      byte[] output, int outputOffset)
-      throws ShortBufferException;
-
-  /**
-   * Encrypts or decrypts data in a single-part operation, or finishes a
-   * multiple-part operation.
-   * 
-   * @param inBuffer the input ByteBuffer
-   * @param outBuffer the output ByteBuffer
-   * @return int number of bytes stored in <code>output</code>
-   * @throws BadPaddingException if this cipher is in decryption mode,
-   * and (un)padding has been requested, but the decrypted data is not
-   * bounded by the appropriate padding bytes
-   * @throws IllegalBlockSizeException if this cipher is a block cipher,
-   * no padding has been requested (only in encryption mode), and the total
-   * input length of the data processed by this cipher is not a multiple of
-   * block size; or if this encryption algorithm is unable to
-   * process the input data provided.
-   * @throws ShortBufferException if the given output buffer is too small
-   * to hold the result
-   */
-  int doFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
-      throws ShortBufferException, IllegalBlockSizeException,
-      BadPaddingException;
-
-  /**
-   * Encrypts or decrypts data in a single-part operation, or finishes a
-   * multiple-part operation.
-   *
-   * @param input the input byte array
-   * @param inputOffset the offset in input where the input starts
-   * @param inputLen the input length
-   * @param output the byte array for the result
-   * @param outputOffset the offset in output where the result is stored
-   * @return the number of bytes stored in output
-   * @throws ShortBufferException if the given output byte array is too small
-   * to hold the result
-   * @throws BadPaddingException if this cipher is in decryption mode,
-   * and (un)padding has been requested, but the decrypted data is not
-   * bounded by the appropriate padding bytes
-   * @throws IllegalBlockSizeException if this cipher is a block cipher,
-   * no padding has been requested (only in encryption mode), and the total
-   * input length of the data processed by this cipher is not a multiple of
-   * block size; or if this encryption algorithm is unable to
-   * process the input data provided.
-   */
-  int doFinal(byte[] input, int inputOffset, int inputLen,
-      byte[] output, int outputOffset)
-      throws ShortBufferException, IllegalBlockSizeException, BadPaddingException;
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/cipher/CipherFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/cipher/CipherFactory.java b/src/main/java/org/apache/commons/crypto/cipher/CipherFactory.java
deleted file mode 100644
index fdaf64c..0000000
--- a/src/main/java/org/apache/commons/crypto/cipher/CipherFactory.java
+++ /dev/null
@@ -1,105 +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.cipher;
-
-import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-
-import org.apache.commons.crypto.utils.ReflectionUtils;
-import org.apache.commons.crypto.utils.Utils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This is the factory class used for creating cipher class
- */
-public class CipherFactory {
-
-  /** LOG instance for {@CipherFactory} */
-  public final static Logger LOG = LoggerFactory.getLogger(CipherFactory.class);
-
-  private CipherFactory() {}
-
-  /**
-   * Gets a cipher instance for specified algorithm/mode/padding.
-   *
-   * @param props
-   *          the configuration properties
-   * @param transformation
-   *          algorithm/mode/padding
-   * @return Cipher the cipher. Null value will be returned if no
-   *         cipher classes with transformation configured.
-   */
-  public static Cipher getInstance(CipherTransformation transformation,
-      Properties props) throws GeneralSecurityException {
-    List<Class<? extends Cipher>> klasses = getCipherClasses(props);
-    Cipher cipher = null;
-    if (klasses != null) {
-      for (Class<? extends Cipher> klass : klasses) {
-        try {
-          cipher = ReflectionUtils.newInstance(klass, props, transformation);
-          if (cipher != null) {
-            LOG.debug("Using cipher {} for transformation {}.", klass.getName(),
-                transformation.getName());
-            break;
-          }
-        } catch (Exception e) {
-          LOG.error("Cipher {} is not available or transformation {} is not " +
-            "supported.", klass.getName(), transformation.getName());
-        }
-      }
-    }
-
-    return (cipher == null) ? new JceCipher(props, transformation) : cipher;
-  }
-
-  /**
-   * Gets a cipher for algorithm/mode/padding in config value
-   * commons.crypto.cipher.transformation
-   *
-   * @return Cipher the cipher object Null value will be returned if no
-   *         cipher classes with transformation configured.
-   */
-  public static Cipher getInstance(CipherTransformation transformation)
-      throws GeneralSecurityException {
-    return getInstance(transformation, new Properties());
-  }
-
-  // Return OpenSSLCipher if Properties is null or empty by default
-  private static List<Class<? extends Cipher>> getCipherClasses(Properties props) {
-    List<Class<? extends Cipher>> result = new ArrayList<Class<? extends
-        Cipher>>();
-    String cipherClassString = Utils.getCipherClassString(props);
-
-    for (String c : Utils.splitClassNames(cipherClassString, ",")) {
-      try {
-        Class<?> cls = ReflectionUtils.getClassByName(c);
-        result.add(cls.asSubclass(Cipher.class));
-      } catch (ClassCastException e) {
-        LOG.error("Class {} is not a Cipher.", c);
-      } catch (ClassNotFoundException e) {
-        LOG.error("Cipher {} not found.", c);
-      }
-    }
-
-    return result;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/cipher/CryptoCipher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/cipher/CryptoCipher.java b/src/main/java/org/apache/commons/crypto/cipher/CryptoCipher.java
new file mode 100644
index 0000000..a47de36
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/cipher/CryptoCipher.java
@@ -0,0 +1,157 @@
+/**
+ * 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.cipher;
+
+import java.io.Closeable;
+import java.nio.ByteBuffer;
+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;
+
+/**
+ * The interface of cryptographic cipher for encryption and decryption.
+ */
+public interface CryptoCipher extends Closeable {
+
+  /**
+   * A constant representing encrypt mode.  The mode constant to be used
+   * when calling init method of the CryptoCipher.
+   */
+  int ENCRYPT_MODE = javax.crypto.Cipher.ENCRYPT_MODE;
+
+  /**
+   * A constant representing decrypt mode.  The mode constant to be used 
+   * when calling init method of the CryptoCipher.
+   */
+  int DECRYPT_MODE = javax.crypto.Cipher.DECRYPT_MODE;
+
+  /**
+   * Gets the CipherTransformation for this cipher.
+   *
+   * @return the CipherTransformation for this cipher.
+   */
+  CipherTransformation getTransformation();
+
+  /**
+   * Gets the properties for this cipher.
+   * 
+   * @return the properties for this cipher.
+   */
+  Properties getProperties();
+
+  /**
+   * Initializes the cipher with mode, key and iv.
+   * 
+   * @param mode {@link #ENCRYPT_MODE} or {@link #DECRYPT_MODE}
+   * @param key crypto key for the cipher
+   * @param params the algorithm parameters
+   * @throws InvalidKeyException if the given key is inappropriate for
+   * initializing this cipher, or its keysize exceeds the maximum allowable
+   * keysize (as determined from the configured jurisdiction policy files).
+   * @throws InvalidAlgorithmParameterException if the given algorithm
+   * parameters are inappropriate for this cipher, or this cipher requires
+   * algorithm parameters and <code>params</code> is null, or the given
+   * algorithm parameters imply a cryptographic strength that would exceed
+   * the legal limits (as determined from the configured jurisdiction
+   * policy files).
+   */
+  void init(int mode, Key key, AlgorithmParameterSpec params)
+      throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+  /**
+   * Continues a multiple-part encryption/decryption operation. The data
+   * is encrypted or decrypted, depending on how this cipher was initialized.
+   * 
+   * @param inBuffer the input ByteBuffer
+   * @param outBuffer the output ByteBuffer
+   * @return int number of bytes stored in <code>output</code>
+   * @throws ShortBufferException if there is insufficient space
+   * in the output buffer
+   */
+  int update(ByteBuffer inBuffer, ByteBuffer outBuffer)
+      throws ShortBufferException;
+
+  /**
+   * Continues a multiple-part encryption/decryption operation. The data
+   * is encrypted or decrypted, depending on how this cipher was initialized.
+   *
+   * @param input the input byte array
+   * @param inputOffset the offset in input where the input starts
+   * @param inputLen the input length
+   * @param output the byte array for the result
+   * @param outputOffset the offset in output where the result is stored
+   * @return the number of bytes stored in output
+   * @throws ShortBufferException if there is insufficient space in the output byte array
+   */
+  int update(byte[] input, int inputOffset, int inputLen,
+      byte[] output, int outputOffset)
+      throws ShortBufferException;
+
+  /**
+   * Encrypts or decrypts data in a single-part operation, or finishes a
+   * multiple-part operation.
+   * 
+   * @param inBuffer the input ByteBuffer
+   * @param outBuffer the output ByteBuffer
+   * @return int number of bytes stored in <code>output</code>
+   * @throws BadPaddingException if this cipher is in decryption mode,
+   * and (un)padding has been requested, but the decrypted data is not
+   * bounded by the appropriate padding bytes
+   * @throws IllegalBlockSizeException if this cipher is a block cipher,
+   * no padding has been requested (only in encryption mode), and the total
+   * input length of the data processed by this cipher is not a multiple of
+   * block size; or if this encryption algorithm is unable to
+   * process the input data provided.
+   * @throws ShortBufferException if the given output buffer is too small
+   * to hold the result
+   */
+  int doFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
+      throws ShortBufferException, IllegalBlockSizeException,
+      BadPaddingException;
+
+  /**
+   * Encrypts or decrypts data in a single-part operation, or finishes a
+   * multiple-part operation.
+   *
+   * @param input the input byte array
+   * @param inputOffset the offset in input where the input starts
+   * @param inputLen the input length
+   * @param output the byte array for the result
+   * @param outputOffset the offset in output where the result is stored
+   * @return the number of bytes stored in output
+   * @throws ShortBufferException if the given output byte array is too small
+   * to hold the result
+   * @throws BadPaddingException if this cipher is in decryption mode,
+   * and (un)padding has been requested, but the decrypted data is not
+   * bounded by the appropriate padding bytes
+   * @throws IllegalBlockSizeException if this cipher is a block cipher,
+   * no padding has been requested (only in encryption mode), and the total
+   * input length of the data processed by this cipher is not a multiple of
+   * block size; or if this encryption algorithm is unable to
+   * process the input data provided.
+   */
+  int doFinal(byte[] input, int inputOffset, int inputLen,
+      byte[] output, int outputOffset)
+      throws ShortBufferException, IllegalBlockSizeException, BadPaddingException;
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/cipher/CryptoCipherFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/cipher/CryptoCipherFactory.java b/src/main/java/org/apache/commons/crypto/cipher/CryptoCipherFactory.java
new file mode 100644
index 0000000..20be0cb
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/cipher/CryptoCipherFactory.java
@@ -0,0 +1,105 @@
+/**
+ * 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.cipher;
+
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.crypto.utils.ReflectionUtils;
+import org.apache.commons.crypto.utils.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is the factory class used for creating cipher class
+ */
+public class CryptoCipherFactory {
+
+  /** LOG instance for {@CipherFactory} */
+  public final static Logger LOG = LoggerFactory.getLogger(CryptoCipherFactory.class);
+
+  private CryptoCipherFactory() {}
+
+  /**
+   * Gets a cipher instance for specified algorithm/mode/padding.
+   *
+   * @param props
+   *          the configuration properties
+   * @param transformation
+   *          algorithm/mode/padding
+   * @return CryptoCipher the cipher. Null value will be returned if no
+   *         cipher classes with transformation configured.
+   */
+  public static CryptoCipher getInstance(CipherTransformation transformation,
+                                         Properties props) throws GeneralSecurityException {
+    List<Class<? extends CryptoCipher>> klasses = getCipherClasses(props);
+    CryptoCipher cipher = null;
+    if (klasses != null) {
+      for (Class<? extends CryptoCipher> klass : klasses) {
+        try {
+          cipher = ReflectionUtils.newInstance(klass, props, transformation);
+          if (cipher != null) {
+            LOG.debug("Using cipher {} for transformation {}.", klass.getName(),
+                transformation.getName());
+            break;
+          }
+        } catch (Exception e) {
+          LOG.error("CryptoCipher {} is not available or transformation {} is not " +
+            "supported.", klass.getName(), transformation.getName());
+        }
+      }
+    }
+
+    return (cipher == null) ? new JceCipher(props, transformation) : cipher;
+  }
+
+  /**
+   * Gets a cipher for algorithm/mode/padding in config value
+   * commons.crypto.cipher.transformation
+   *
+   * @return CryptoCipher the cipher object Null value will be returned if no
+   *         cipher classes with transformation configured.
+   */
+  public static CryptoCipher getInstance(CipherTransformation transformation)
+      throws GeneralSecurityException {
+    return getInstance(transformation, new Properties());
+  }
+
+  // Return OpenSSLCipher if Properties is null or empty by default
+  private static List<Class<? extends CryptoCipher>> getCipherClasses(Properties props) {
+    List<Class<? extends CryptoCipher>> result = new ArrayList<Class<? extends
+            CryptoCipher>>();
+    String cipherClassString = Utils.getCipherClassString(props);
+
+    for (String c : Utils.splitClassNames(cipherClassString, ",")) {
+      try {
+        Class<?> cls = ReflectionUtils.getClassByName(c);
+        result.add(cls.asSubclass(CryptoCipher.class));
+      } catch (ClassCastException e) {
+        LOG.error("Class {} is not a CryptoCipher.", c);
+      } catch (ClassNotFoundException e) {
+        LOG.error("CryptoCipher {} not found.", c);
+      }
+    }
+
+    return result;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/cipher/JceCipher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/cipher/JceCipher.java b/src/main/java/org/apache/commons/crypto/cipher/JceCipher.java
index 873d092..57750c2 100644
--- a/src/main/java/org/apache/commons/crypto/cipher/JceCipher.java
+++ b/src/main/java/org/apache/commons/crypto/cipher/JceCipher.java
@@ -32,15 +32,15 @@ import javax.crypto.ShortBufferException;
 import org.apache.commons.crypto.utils.Utils;
 
 /**
- * Implements the {@link org.apache.commons.crypto.cipher.Cipher} using JCE provider.
+ * Implements the {@link org.apache.commons.crypto.cipher.CryptoCipher} using JCE provider.
  */
-public class JceCipher implements Cipher {
+public class JceCipher implements CryptoCipher {
   private final Properties props;
   private final CipherTransformation transformation;
   private final javax.crypto.Cipher cipher;
 
   /**
-   * Constructs a {@link org.apache.commons.crypto.cipher.Cipher} based on JCE
+   * Constructs a {@link org.apache.commons.crypto.cipher.CryptoCipher} based on JCE
    * Cipher {@link javax.crypto.Cipher}.
    * @param props properties for JCE cipher
    * @param transformation transformation for JCE cipher

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/cipher/Openssl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/cipher/Openssl.java b/src/main/java/org/apache/commons/crypto/cipher/Openssl.java
index 9365859..488438b 100644
--- a/src/main/java/org/apache/commons/crypto/cipher/Openssl.java
+++ b/src/main/java/org/apache/commons/crypto/cipher/Openssl.java
@@ -87,7 +87,7 @@ public final class Openssl {
       }
     } catch (Throwable t) {
       loadingFailure = t.getMessage();
-      LOG.debug("Failed to load OpenSSL Cipher.", t);
+      LOG.debug("Failed to load OpenSSL CryptoCipher.", t);
     } finally {
       loadingFailureReason = loadingFailure;
     }

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/cipher/OpensslCipher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/cipher/OpensslCipher.java b/src/main/java/org/apache/commons/crypto/cipher/OpensslCipher.java
index 72b247b..e258466 100644
--- a/src/main/java/org/apache/commons/crypto/cipher/OpensslCipher.java
+++ b/src/main/java/org/apache/commons/crypto/cipher/OpensslCipher.java
@@ -34,15 +34,15 @@ import javax.crypto.spec.IvParameterSpec;
 import org.apache.commons.crypto.utils.Utils;
 
 /**
- * Implements the Cipher using JNI into OpenSSL.
+ * Implements the CryptoCipher using JNI into OpenSSL.
  */
-public class OpensslCipher implements Cipher {
+public class OpensslCipher implements CryptoCipher {
   private final Properties props;
   private final CipherTransformation transformation;
   private final Openssl cipher;
 
   /**
-   * Constructs a {@link org.apache.commons.crypto.cipher.Cipher} using JNI into OpenSSL
+   * Constructs a {@link org.apache.commons.crypto.cipher.CryptoCipher} using JNI into OpenSSL
    * 
    * @param props properties for OpenSSL cipher
    * @param transformation transformation for OpenSSL cipher

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/cipher/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/cipher/package-info.java b/src/main/java/org/apache/commons/crypto/cipher/package-info.java
index c650b57..0da563f 100644
--- a/src/main/java/org/apache/commons/crypto/cipher/package-info.java
+++ b/src/main/java/org/apache/commons/crypto/cipher/package-info.java
@@ -17,6 +17,6 @@
  */
 
 /**
- * Cipher classes
+ * CryptoCipher classes
  */
 package org.apache.commons.crypto.cipher;

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java b/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java
index ae07758..989cee3 100644
--- a/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java
+++ b/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java
@@ -17,7 +17,9 @@
  */
 package org.apache.commons.crypto.conf;
 
+import org.apache.commons.crypto.cipher.CryptoCipher;
 import org.apache.commons.crypto.cipher.OpensslCipher;
+import org.apache.commons.crypto.random.CryptoRandom;
 
 /**
  * The ConfigurationKeys contains Configuration keys and default values.
@@ -41,7 +43,7 @@ public class ConfigurationKeys {
    * "org.apache.commons.crypto.cipher.JceCipher" and "org.apache.commons.crypto.cipher.OpensslCipher".
    * And it takes a common separated list.
    * The "org.apache.commons.crypto.cipher.JceCipher" use jce provider to
-   * implement {@link org.apache.commons.crypto.cipher.Cipher} and
+   * implement {@link org.apache.commons.crypto.cipher.CryptoCipher} and
    * the "org.apache.commons.crypto.cipher.OpensslCipher" use jni into openssl to implement.
    * Note that for each value,the first value which can be created without exception
    * will be used (priority by order).
@@ -89,11 +91,11 @@ public class ConfigurationKeys {
   /**
    * The configuration key of the implementation class for secure random.
    * The values of COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY can be
-   * "org.apache.commons.crypto.random.JavaSecureRandom" and "org.apache.commons.crypto.random.OpensslSecureRandom".
+   * "org.apache.commons.crypto.random.JavaCryptoRandom" and "org.apache.commons.crypto.random.OpensslCryptoRandom".
    * And it takes a common separated list.
-   * The "org.apache.commons.crypto.random.JavaSecureRandom" use java to
-   * implement {@link org.apache.commons.crypto.random.SecureRandom} and
-   * the "org.apache.commons.crypto.random.OpensslSecureRandom" use jni into openssl to implement.
+   * The "org.apache.commons.crypto.random.JavaCryptoRandom" use java to
+   * implement {@link CryptoRandom} and
+   * the "org.apache.commons.crypto.random.OpensslCryptoRandom" use jni into openssl to implement.
    * Note that for each value,the first value which can be created without exception
    * will be used (priority by order).
    */

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/CryptoRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/CryptoRandom.java b/src/main/java/org/apache/commons/crypto/random/CryptoRandom.java
new file mode 100644
index 0000000..8194a9b
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/random/CryptoRandom.java
@@ -0,0 +1,36 @@
+/**
+ * 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.random;
+
+import java.io.Closeable;
+
+/**
+ * The interface for CryptoRandom.
+ */
+public interface CryptoRandom extends Closeable {
+
+  /**
+   * Generates random bytes and places them into a user-supplied
+   * byte array.  The number of random bytes produced is equal to
+   * the length of the byte array.
+   *
+   * @param bytes the byte array to fill with random bytes
+   */
+  void nextBytes(byte[] bytes);
+
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/CryptoRandomFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/CryptoRandomFactory.java b/src/main/java/org/apache/commons/crypto/random/CryptoRandomFactory.java
new file mode 100644
index 0000000..8c9fd35
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/random/CryptoRandomFactory.java
@@ -0,0 +1,76 @@
+/**
+ * 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.random;
+
+import java.security.GeneralSecurityException;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.commons.crypto.utils.Utils;
+import org.apache.commons.crypto.utils.ReflectionUtils;
+
+import static org.apache.commons.crypto.conf.ConfigurationKeys
+    .COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY;
+
+/**
+ * This is the factory class used for {@link CryptoRandom}.
+ */
+public class CryptoRandomFactory {
+  public final static Logger LOG = LoggerFactory
+      .getLogger(CryptoRandomFactory.class);
+
+  private CryptoRandomFactory() {}
+
+  /**
+   * Gets a CryptoRandom instance for specified props.
+   *
+   * @param props the configuration properties.
+   * @return CryptoRandom the cryptoRandom object.Null value will be returned if no CryptoRandom
+   *         classes with props.
+   * @throws GeneralSecurityException if fail to create the {@link CryptoRandom}.
+   */
+  public static CryptoRandom getCryptoRandom(Properties props) throws GeneralSecurityException {
+    String cryptoRandomClasses = props.getProperty(
+        COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY);
+    if (cryptoRandomClasses == null) {
+      cryptoRandomClasses = System.getProperty(
+          COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY);
+    }
+
+    CryptoRandom random = null;
+    if (cryptoRandomClasses != null) {
+      for (String klassName : Utils.splitClassNames(cryptoRandomClasses, ",")) {
+        try {
+          final Class<?> klass = ReflectionUtils.getClassByName(klassName);
+          random = (CryptoRandom) ReflectionUtils.newInstance(klass, props);
+          if (random != null) {
+            break;
+          }
+        } catch (ClassCastException e) {
+          LOG.error("Class {} is not a CryptoCipher.", klassName);
+        } catch (ClassNotFoundException e) {
+          LOG.error("CryptoCipher {} not found.", klassName);
+        }
+      }
+    }
+
+    return (random == null) ? new JavaCryptoRandom(props) : random;
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/JavaCryptoRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/JavaCryptoRandom.java b/src/main/java/org/apache/commons/crypto/random/JavaCryptoRandom.java
new file mode 100644
index 0000000..aff8f39
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/random/JavaCryptoRandom.java
@@ -0,0 +1,76 @@
+/**
+ * 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.random;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.commons.crypto.conf.ConfigurationKeys;
+
+/**
+ * A CryptoRandom of Java implementation.
+ */
+public class JavaCryptoRandom implements CryptoRandom {
+  private static final Log LOG =
+      LogFactory.getLog(JavaCryptoRandom.class.getName());
+
+  private java.security.SecureRandom instance;
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.random.JavaCryptoRandom}.
+   *
+   * @param properties the configuration properties.
+   * @throws NoSuchAlgorithmException if no Provider supports a SecureRandomSpi implementation for
+   *         the specified algorithm.
+   */
+  public JavaCryptoRandom(Properties properties) throws NoSuchAlgorithmException {
+    try {
+      instance = java.security.SecureRandom
+          .getInstance(properties.getProperty(
+              ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_KEY,
+              ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_DEFAULT));
+    } catch (NoSuchAlgorithmException e) {
+      LOG.error("Failed to create java secure random due to error: " + e);
+      throw e;
+    }
+  }
+
+  /**
+   * Overrides {@link java.lang.AutoCloseable#close()}.
+   * For{@link JavaCryptoRandom}, we don't need to recycle resource.
+   */
+  @Override
+  public void close() {
+    // do nothing
+  }
+
+  /**
+   * Overrides {@link org.apache.commons.crypto.random.CryptoRandom#nextBytes(byte[])}.
+   * Generates random bytes and places them into a user-supplied byte array.
+   * The number of random bytes produced is equal to the length of the byte array.
+   *
+   * @param bytes the array to be filled in with random bytes.
+   */
+  @Override
+  public void nextBytes(byte[] bytes) {
+    instance.nextBytes(bytes);
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/JavaSecureRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/JavaSecureRandom.java b/src/main/java/org/apache/commons/crypto/random/JavaSecureRandom.java
deleted file mode 100644
index 60b8448..0000000
--- a/src/main/java/org/apache/commons/crypto/random/JavaSecureRandom.java
+++ /dev/null
@@ -1,76 +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.random;
-
-import java.security.NoSuchAlgorithmException;
-import java.util.Properties;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.apache.commons.crypto.conf.ConfigurationKeys;
-
-/**
- * A SecureRandom of Java implementation.
- */
-public class JavaSecureRandom implements SecureRandom {
-  private static final Log LOG =
-      LogFactory.getLog(JavaSecureRandom.class.getName());
-
-  private java.security.SecureRandom instance;
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.random.JavaSecureRandom}.
-   *
-   * @param properties the configuration properties.
-   * @throws NoSuchAlgorithmException if no Provider supports a SecureRandomSpi implementation for
-   *         the specified algorithm.
-   */
-  public JavaSecureRandom(Properties properties) throws NoSuchAlgorithmException {
-    try {
-      instance = java.security.SecureRandom
-          .getInstance(properties.getProperty(
-              ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_KEY,
-              ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_DEFAULT));
-    } catch (NoSuchAlgorithmException e) {
-      LOG.error("Failed to create java secure random due to error: " + e);
-      throw e;
-    }
-  }
-
-  /**
-   * Overrides {@link java.lang.AutoCloseable#close()}.
-   * For{@link JavaSecureRandom}, we don't need to recycle resource.
-   */
-  @Override
-  public void close() {
-    // do nothing
-  }
-
-  /**
-   * Overrides {@link org.apache.commons.crypto.random.SecureRandom#nextBytes(byte[])}.
-   * Generates random bytes and places them into a user-supplied byte array.
-   * The number of random bytes produced is equal to the length of the byte array.
-   *
-   * @param bytes the array to be filled in with random bytes.
-   */
-  @Override
-  public void nextBytes(byte[] bytes) {
-    instance.nextBytes(bytes);
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandom.java b/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandom.java
new file mode 100644
index 0000000..406ddef
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandom.java
@@ -0,0 +1,143 @@
+/**
+ * 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.random;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.Properties;
+import java.util.Random;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.commons.crypto.utils.NativeCodeLoader;
+import org.apache.commons.crypto.utils.Utils;
+
+/**
+ * OpenSSL secure random using JNI.
+ * This implementation is thread-safe.
+ * <p/>
+ *
+ * If using an Intel chipset with RDRAND, the high-performance hardware
+ * random number generator will be used and it's much faster than
+ * {@link java.security.SecureRandom}. If RDRAND is unavailable, default
+ * OpenSSL secure random generator will be used. It's still faster
+ * and can generate strong random bytes.
+ * <p/>
+ * @see https://wiki.openssl.org/index.php/Random_Numbers
+ * @see http://en.wikipedia.org/wiki/RdRand
+ */
+public class OpensslCryptoRandom extends Random implements CryptoRandom {
+  private static final long serialVersionUID = -7828193502768789584L;
+  private static final Log LOG =
+      LogFactory.getLog(OpensslCryptoRandom.class.getName());
+
+  /** If native CryptoRandom unavailable, use java SecureRandom */
+  private JavaCryptoRandom fallback = null;
+  private static boolean nativeEnabled = false;
+  static {
+    if (NativeCodeLoader.isNativeCodeLoaded()) {
+      try {
+        OpensslCryptoRandomNative.initSR();
+        nativeEnabled = true;
+      } catch (Throwable t) {
+        LOG.error("Failed to load Openssl CryptoRandom", t);
+      }
+    }
+  }
+
+  /**
+   * Judges whether loading native library successfully.
+   *
+   * @return true if loading library successfully.
+   */
+  public static boolean isNativeCodeLoaded() {
+    return nativeEnabled;
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.random.OpensslCryptoRandom}.
+   *
+   * @param props the configuration properties.
+   * @throws NoSuchAlgorithmException if no Provider supports a SecureRandomSpi implementation for
+   *         the specified algorithm.
+   */
+  public OpensslCryptoRandom(Properties props) throws NoSuchAlgorithmException {
+    if (!nativeEnabled) {
+      fallback = new JavaCryptoRandom(props);
+    }
+  }
+
+  /**
+   * Generates a user-specified number of random bytes.
+   * It's thread-safe.
+   *
+   * @param bytes the array to be filled in with random bytes.
+   */
+  @Override
+  public void nextBytes(byte[] bytes) {
+    if (!nativeEnabled || !OpensslCryptoRandomNative.nextRandBytes(bytes)) {
+      fallback.nextBytes(bytes);
+    }
+  }
+
+  /**
+   * Overrides {@link OpensslCryptoRandom}.
+   * For {@link OpensslCryptoRandom}, we don't need to set seed.
+   *
+   * @param seed the initial seed.
+   */
+  @Override
+  public void setSeed(long seed) {
+    // Self-seeding.
+  }
+
+  /**
+   * Overrides {@link java.util.Random# next()}. Generates an integer
+   * containing the user-specified number of random
+   * bits(right justified, with leading zeros).
+   *
+   * @param numBits number of random bits to be generated, where
+   * 0 <= <code>numBits</code> <= 32.
+   * @return int an <code>int</code> containing the user-specified number
+   * of random bits (right justified, with leading zeros).
+   */
+  @Override
+  final protected int next(int numBits) {
+    Utils.checkArgument(numBits >= 0 && numBits <= 32);
+    int numBytes = (numBits + 7) / 8;
+    byte b[] = new byte[numBytes];
+    int next = 0;
+
+    nextBytes(b);
+    for (int i = 0; i < numBytes; i++) {
+      next = (next << 8) + (b[i] & 0xFF);
+    }
+
+    return next >>> (numBytes * 8 - numBits);
+  }
+
+  /**
+   * Overrides {@link java.lang.AutoCloseable#close()}. Closes openssl context if native enabled.
+   */
+  @Override
+  public void close() {
+    if (!nativeEnabled && fallback !=null) {
+      fallback.close();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java b/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java
new file mode 100644
index 0000000..c72cad6
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java
@@ -0,0 +1,43 @@
+/**
+ * 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.random;
+
+/**
+ * JNI interface of {@link CryptoRandom} implementation.
+ * The native method in this class is defined in
+ * OpensslCryptoRandomNative.h(genereted by javah).
+ */
+public class OpensslCryptoRandomNative {
+
+  private OpensslCryptoRandomNative() {}
+
+  /**
+   * Declares a native method to initialize SR.
+   */
+  public native static void initSR();
+
+  /**
+   * Judges whether use {@link OpensslCryptoRandomNative} to
+   * generate the user-specified number of random bits.
+   *
+   * @param bytes the array to be filled in with random bytes.
+   * @return true if use {@link OpensslCryptoRandomNative} to
+   * generate the user-specified number of random bits.
+   */
+  public native static boolean nextRandBytes(byte[] bytes); 
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/OpensslSecureRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/OpensslSecureRandom.java b/src/main/java/org/apache/commons/crypto/random/OpensslSecureRandom.java
deleted file mode 100644
index 2ad3244..0000000
--- a/src/main/java/org/apache/commons/crypto/random/OpensslSecureRandom.java
+++ /dev/null
@@ -1,143 +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.random;
-
-import java.security.NoSuchAlgorithmException;
-import java.util.Properties;
-import java.util.Random;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.apache.commons.crypto.utils.NativeCodeLoader;
-import org.apache.commons.crypto.utils.Utils;
-
-/**
- * OpenSSL secure random using JNI.
- * This implementation is thread-safe.
- * <p/>
- *
- * If using an Intel chipset with RDRAND, the high-performance hardware
- * random number generator will be used and it's much faster than
- * {@link java.security.SecureRandom}. If RDRAND is unavailable, default
- * OpenSSL secure random generator will be used. It's still faster
- * and can generate strong random bytes.
- * <p/>
- * @see https://wiki.openssl.org/index.php/Random_Numbers
- * @see http://en.wikipedia.org/wiki/RdRand
- */
-public class OpensslSecureRandom extends Random implements SecureRandom {
-  private static final long serialVersionUID = -7828193502768789584L;
-  private static final Log LOG =
-      LogFactory.getLog(OpensslSecureRandom.class.getName());
-
-  /** If native SecureRandom unavailable, use java SecureRandom */
-  private JavaSecureRandom fallback = null;
-  private static boolean nativeEnabled = false;
-  static {
-    if (NativeCodeLoader.isNativeCodeLoaded()) {
-      try {
-        OpensslSecureRandomNative.initSR();
-        nativeEnabled = true;
-      } catch (Throwable t) {
-        LOG.error("Failed to load Openssl SecureRandom", t);
-      }
-    }
-  }
-
-  /**
-   * Judges whether loading native library successfully.
-   *
-   * @return true if loading library successfully.
-   */
-  public static boolean isNativeCodeLoaded() {
-    return nativeEnabled;
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.random.OpensslSecureRandom}.
-   *
-   * @param props the configuration properties.
-   * @throws NoSuchAlgorithmException if no Provider supports a SecureRandomSpi implementation for
-   *         the specified algorithm.
-   */
-  public OpensslSecureRandom(Properties props) throws NoSuchAlgorithmException {
-    if (!nativeEnabled) {
-      fallback = new JavaSecureRandom(props);
-    }
-  }
-
-  /**
-   * Generates a user-specified number of random bytes.
-   * It's thread-safe.
-   *
-   * @param bytes the array to be filled in with random bytes.
-   */
-  @Override
-  public void nextBytes(byte[] bytes) {
-    if (!nativeEnabled || !OpensslSecureRandomNative.nextRandBytes(bytes)) {
-      fallback.nextBytes(bytes);
-    }
-  }
-
-  /**
-   * Overrides {@link OpensslSecureRandom}.
-   * For {@link OpensslSecureRandom}, we don't need to set seed.
-   *
-   * @param seed the initial seed.
-   */
-  @Override
-  public void setSeed(long seed) {
-    // Self-seeding.
-  }
-
-  /**
-   * Overrides {@link java.util.Random# next()}. Generates an integer
-   * containing the user-specified number of random
-   * bits(right justified, with leading zeros).
-   *
-   * @param numBits number of random bits to be generated, where
-   * 0 <= <code>numBits</code> <= 32.
-   * @return int an <code>int</code> containing the user-specified number
-   * of random bits (right justified, with leading zeros).
-   */
-  @Override
-  final protected int next(int numBits) {
-    Utils.checkArgument(numBits >= 0 && numBits <= 32);
-    int numBytes = (numBits + 7) / 8;
-    byte b[] = new byte[numBytes];
-    int next = 0;
-
-    nextBytes(b);
-    for (int i = 0; i < numBytes; i++) {
-      next = (next << 8) + (b[i] & 0xFF);
-    }
-
-    return next >>> (numBytes * 8 - numBits);
-  }
-
-  /**
-   * Overrides {@link java.lang.AutoCloseable#close()}. Closes openssl context if native enabled.
-   */
-  @Override
-  public void close() {
-    if (!nativeEnabled && fallback !=null) {
-      fallback.close();
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/OpensslSecureRandomNative.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/OpensslSecureRandomNative.java b/src/main/java/org/apache/commons/crypto/random/OpensslSecureRandomNative.java
deleted file mode 100644
index c36083f..0000000
--- a/src/main/java/org/apache/commons/crypto/random/OpensslSecureRandomNative.java
+++ /dev/null
@@ -1,43 +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.random;
-
-/**
- * JNI interface of {@link SecureRandom} implementation.
- * The native method in this class is defined in
- * OpensslSecureRandomNative.h(genereted by javah).
- */
-public class OpensslSecureRandomNative {
-
-  private OpensslSecureRandomNative() {}
-
-  /**
-   * Declares a native method to initialize SR.
-   */
-  public native static void initSR();
-
-  /**
-   * Judges whether use {@link OpensslSecureRandomNative} to
-   * generate the user-specified number of random bits.
-   *
-   * @param bytes the array to be filled in with random bytes.
-   * @return true if use {@link OpensslSecureRandomNative} to
-   * generate the user-specified number of random bits.
-   */
-  public native static boolean nextRandBytes(byte[] bytes); 
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/OsCryptoRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/OsCryptoRandom.java b/src/main/java/org/apache/commons/crypto/random/OsCryptoRandom.java
new file mode 100644
index 0000000..4e6c063
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/random/OsCryptoRandom.java
@@ -0,0 +1,133 @@
+/**
+ * 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.random;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Random;
+
+import org.apache.commons.crypto.utils.IOUtils;
+import org.apache.commons.crypto.utils.Utils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A Random implementation that uses random bytes sourced from the
+ * operating system.
+ */
+public class OsCryptoRandom extends Random implements CryptoRandom {
+  public static final Log LOG = LogFactory.getLog(OsCryptoRandom.class);
+  
+  private static final long serialVersionUID = 6391500337172057900L;
+
+  private final int RESERVOIR_LENGTH = 8192;
+
+  private String randomDevPath;
+
+  private transient FileInputStream stream;
+
+  private final byte[] reservoir = new byte[RESERVOIR_LENGTH];
+
+  private int pos = reservoir.length;
+
+  private void fillReservoir(int min) {
+    if (pos >= reservoir.length - min) {
+      try {
+        IOUtils.readFully(stream, reservoir, 0, reservoir.length);
+      } catch (IOException e) {
+        throw new RuntimeException("failed to fill reservoir", e);
+      }
+      pos = 0;
+    }
+  }
+
+  /**
+   * Constructs a {@link org.apache.commons.crypto.random.OsCryptoRandom}.
+   *
+   * @param props the configuration properties.
+   */
+  public OsCryptoRandom(Properties props) {
+    randomDevPath = Utils.getRandomDevPath(props);
+    File randomDevFile = new File(randomDevPath);
+
+    try {
+      close();
+      this.stream = new FileInputStream(randomDevFile);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+
+    try {
+      fillReservoir(0);
+    } catch (RuntimeException e) {
+      close();
+      throw e;
+    }
+  }
+
+  /**
+   * Overrides {@link org.apache.commons.crypto.random.CryptoRandom#nextBytes(byte[])}.
+   * Generates random bytes and places them into a user-supplied byte array.
+   * The number of random bytes produced is equal to the length of the byte array.
+   *
+   * @param bytes the array to be filled in with random bytes.
+   */
+  @Override
+  synchronized public void nextBytes(byte[] bytes) {
+    int off = 0;
+    int n = 0;
+    while (off < bytes.length) {
+      fillReservoir(0);
+      n = Math.min(bytes.length - off, reservoir.length - pos);
+      System.arraycopy(reservoir, pos, bytes, off, n);
+      off += n;
+      pos += n;
+    }
+  }
+
+  /**
+   * Overrides {@link java.util.Random# next()}. Generates the next pseudorandom number.
+   * Subclasses should override this, as this is used by all other methods.
+   *
+   * @param  nbits random bits.
+   * @return the next pseudorandom value from this random number
+   *         generator's sequence.
+   */
+  @Override
+  synchronized protected int next(int nbits) {
+    fillReservoir(4);
+    int n = 0;
+    for (int i = 0; i < 4; i++) {
+      n = ((n << 8) | (reservoir[pos++] & 0xff));
+    }
+    return n & (0xffffffff >> (32 - nbits));
+  }
+
+  /**
+   * Overrides {@link java.lang.AutoCloseable#close()}. Closes the OS stream.
+   */
+  @Override
+  synchronized public void close() {
+    if (stream != null) {
+      IOUtils.cleanup(LOG, stream);
+      stream = null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/OsSecureRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/OsSecureRandom.java b/src/main/java/org/apache/commons/crypto/random/OsSecureRandom.java
deleted file mode 100644
index 916ad10..0000000
--- a/src/main/java/org/apache/commons/crypto/random/OsSecureRandom.java
+++ /dev/null
@@ -1,133 +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.random;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Properties;
-import java.util.Random;
-
-import org.apache.commons.crypto.utils.IOUtils;
-import org.apache.commons.crypto.utils.Utils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * A Random implementation that uses random bytes sourced from the
- * operating system.
- */
-public class OsSecureRandom extends Random implements SecureRandom {
-  public static final Log LOG = LogFactory.getLog(OsSecureRandom.class);
-  
-  private static final long serialVersionUID = 6391500337172057900L;
-
-  private final int RESERVOIR_LENGTH = 8192;
-
-  private String randomDevPath;
-
-  private transient FileInputStream stream;
-
-  private final byte[] reservoir = new byte[RESERVOIR_LENGTH];
-
-  private int pos = reservoir.length;
-
-  private void fillReservoir(int min) {
-    if (pos >= reservoir.length - min) {
-      try {
-        IOUtils.readFully(stream, reservoir, 0, reservoir.length);
-      } catch (IOException e) {
-        throw new RuntimeException("failed to fill reservoir", e);
-      }
-      pos = 0;
-    }
-  }
-
-  /**
-   * Constructs a {@link org.apache.commons.crypto.random.OsSecureRandom}.
-   *
-   * @param props the configuration properties.
-   */
-  public OsSecureRandom(Properties props) {
-    randomDevPath = Utils.getRandomDevPath(props);
-    File randomDevFile = new File(randomDevPath);
-
-    try {
-      close();
-      this.stream = new FileInputStream(randomDevFile);
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-
-    try {
-      fillReservoir(0);
-    } catch (RuntimeException e) {
-      close();
-      throw e;
-    }
-  }
-
-  /**
-   * Overrides {@link org.apache.commons.crypto.random.SecureRandom#nextBytes(byte[])}.
-   * Generates random bytes and places them into a user-supplied byte array.
-   * The number of random bytes produced is equal to the length of the byte array.
-   *
-   * @param bytes the array to be filled in with random bytes.
-   */
-  @Override
-  synchronized public void nextBytes(byte[] bytes) {
-    int off = 0;
-    int n = 0;
-    while (off < bytes.length) {
-      fillReservoir(0);
-      n = Math.min(bytes.length - off, reservoir.length - pos);
-      System.arraycopy(reservoir, pos, bytes, off, n);
-      off += n;
-      pos += n;
-    }
-  }
-
-  /**
-   * Overrides {@link java.util.Random# next()}. Generates the next pseudorandom number.
-   * Subclasses should override this, as this is used by all other methods.
-   *
-   * @param  nbits random bits.
-   * @return the next pseudorandom value from this random number
-   *         generator's sequence.
-   */
-  @Override
-  synchronized protected int next(int nbits) {
-    fillReservoir(4);
-    int n = 0;
-    for (int i = 0; i < 4; i++) {
-      n = ((n << 8) | (reservoir[pos++] & 0xff));
-    }
-    return n & (0xffffffff >> (32 - nbits));
-  }
-
-  /**
-   * Overrides {@link java.lang.AutoCloseable#close()}. Closes the OS stream.
-   */
-  @Override
-  synchronized public void close() {
-    if (stream != null) {
-      IOUtils.cleanup(LOG, stream);
-      stream = null;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/SecureRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/SecureRandom.java b/src/main/java/org/apache/commons/crypto/random/SecureRandom.java
deleted file mode 100644
index 69c5559..0000000
--- a/src/main/java/org/apache/commons/crypto/random/SecureRandom.java
+++ /dev/null
@@ -1,36 +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.random;
-
-import java.io.Closeable;
-
-/**
- * The interface for SecureRandom.
- */
-public interface SecureRandom extends Closeable {
-
-  /**
-   * Generates random bytes and places them into a user-supplied
-   * byte array.  The number of random bytes produced is equal to
-   * the length of the byte array.
-   *
-   * @param bytes the byte array to fill with random bytes
-   */
-  void nextBytes(byte[] bytes);
-
-}

http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ea89d802/src/main/java/org/apache/commons/crypto/random/SecureRandomFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/random/SecureRandomFactory.java b/src/main/java/org/apache/commons/crypto/random/SecureRandomFactory.java
deleted file mode 100644
index 3e42857..0000000
--- a/src/main/java/org/apache/commons/crypto/random/SecureRandomFactory.java
+++ /dev/null
@@ -1,76 +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.random;
-
-import java.security.GeneralSecurityException;
-import java.util.Properties;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.commons.crypto.utils.Utils;
-import org.apache.commons.crypto.utils.ReflectionUtils;
-
-import static org.apache.commons.crypto.conf.ConfigurationKeys
-    .COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY;
-
-/**
- * This is the factory class used for {@link SecureRandom}.
- */
-public class SecureRandomFactory {
-  public final static Logger LOG = LoggerFactory
-      .getLogger(SecureRandomFactory.class);
-
-  private SecureRandomFactory() {}
-
-  /**
-   * Gets a SecureRandom instance for specified props.
-   *
-   * @param props the configuration properties.
-   * @return SecureRandom the secureRandom object.Null value will be returned if no SecureRandom
-   *         classes with props.
-   * @throws GeneralSecurityException if fail to create the {@link SecureRandom}.
-   */
-  public static SecureRandom getSecureRandom(Properties props) throws GeneralSecurityException {
-    String secureRandomClasses = props.getProperty(
-        COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY);
-    if (secureRandomClasses == null) {
-      secureRandomClasses = System.getProperty(
-          COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY);
-    }
-
-    SecureRandom random = null;
-    if (secureRandomClasses != null) {
-      for (String klassName : Utils.splitClassNames(secureRandomClasses, ",")) {
-        try {
-          final Class<?> klass = ReflectionUtils.getClassByName(klassName);
-          random = (SecureRandom) ReflectionUtils.newInstance(klass, props);
-          if (random != null) {
-            break;
-          }
-        } catch (ClassCastException e) {
-          LOG.error("Class {} is not a Cipher.", klassName);
-        } catch (ClassNotFoundException e) {
-          LOG.error("Cipher {} not found.", klassName);
-        }
-      }
-    }
-
-    return (random == null) ? new JavaSecureRandom(props) : random;
-  }
-}


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

Posted by sd...@apache.org.
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);
     }