You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2016/06/30 16:03:58 UTC
[2/2] commons-crypto git commit: [CRYPTO-94] Consistently camel-case
type names: Ctr*.
[CRYPTO-94] Consistently camel-case type names: Ctr*.
Project: http://git-wip-us.apache.org/repos/asf/commons-crypto/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-crypto/commit/ba14d801
Tree: http://git-wip-us.apache.org/repos/asf/commons-crypto/tree/ba14d801
Diff: http://git-wip-us.apache.org/repos/asf/commons-crypto/diff/ba14d801
Branch: refs/heads/master
Commit: ba14d801935decdb9399d6b2f038e0d1a71609e1
Parents: 294d73b
Author: Gary Gregory <gg...@apache.org>
Authored: Thu Jun 30 09:03:53 2016 -0700
Committer: Gary Gregory <gg...@apache.org>
Committed: Thu Jun 30 09:03:53 2016 -0700
----------------------------------------------------------------------
.../crypto/stream/CTRCryptoInputStream.java | 672 -------------------
.../crypto/stream/CTRCryptoOutputStream.java | 384 -----------
.../crypto/stream/CryptoInputStream.java | 2 +-
.../crypto/stream/CtrCryptoInputStream.java | 672 +++++++++++++++++++
.../crypto/stream/CtrCryptoOutputStream.java | 384 +++++++++++
.../stream/PositionedCryptoInputStream.java | 4 +-
.../crypto/stream/CTRCryptoStreamTest.java | 55 --
.../stream/CTRNoPaddingCipherStreamTest.java | 29 -
.../crypto/stream/CtrCryptoStreamTest.java | 55 ++
.../stream/CtrNoPaddingCipherStreamTest.java | 29 +
10 files changed, 1143 insertions(+), 1143 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ba14d801/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
deleted file mode 100644
index 6c6dacc..0000000
--- a/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java
+++ /dev/null
@@ -1,672 +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.Cipher;
-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.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;
-
-/**
- * <p>
- * 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>
- * <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
- */
- private long streamOffset = 0;
-
- /**
- * The initial IV.
- */
- private final byte[] initIV;
-
- /**
- * Initialization vector for the cipher.
- */
- private 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;
-
- /**
- * For AES, the algorithm block is fixed size of 128 bits.
- *
- * @see <a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard">
- * http://en.wikipedia.org/wiki/Advanced_Encryption_Standard</a>
- */
- private static final int AES_BLOCK_SIZE = 16;
-
- /**
- * Constructs a {@link 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 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 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.
- */
- protected CTRCryptoInputStream(InputStream in, CryptoCipher cipher,
- int bufferSize, byte[] key, byte[] iv) throws IOException {
- this(in, cipher, bufferSize, key, iv, 0);
- }
-
- /**
- * Constructs a {@link 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.
- */
- protected CTRCryptoInputStream(ReadableByteChannel in, CryptoCipher cipher,
- int bufferSize, byte[] key, byte[] iv) throws IOException {
- this(in, cipher, bufferSize, key, iv, 0);
- }
-
- /**
- * Constructs a {@link 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.
- */
- protected CTRCryptoInputStream(Input input, CryptoCipher cipher,
- int bufferSize, byte[] key, byte[] iv) throws IOException {
- this(input, cipher, bufferSize, key, iv, 0);
- }
-
- /**
- * Constructs a {@link 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(
- "AES/CTR/NoPadding", props),
- CryptoInputStream.getBufferSize(props), key, iv, streamOffset);
- }
-
- /**
- * Constructs a {@link 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(
- "AES/CTR/NoPadding", props),
- CryptoInputStream.getBufferSize(props), key, iv, streamOffset);
- }
-
- /**
- * Constructs a {@link 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.
- */
- protected 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 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.
- */
- protected 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 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.
- */
- protected 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();
-
- CryptoInputStream.checkStreamCipher(cipher);
-
- resetStreamOffset(streamOffset);
- }
-
- /**
- * Overrides the {@link 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 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;
- }
- // 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;
- }
- 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;
- }
-
- /**
- * Sets the offset of stream.
- *
- * @param streamOffset the stream offset.
- */
- 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> <tt>+</tt> <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.
- * @throws IOException if an I/O error occurs.
- */
- 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.getBlockSize();
- }
-
- /**
- * 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.getBlockSize());
- }
-
- /**
- * 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);
- CTRCryptoInputStream.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. 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);
- }
- }
-
- /**
- * <p>
- * This method is only for Counter (CTR) mode. Generally the CryptoCipher
- * calculates the IV and maintain encryption context internally.For example
- * a Cipher will maintain its encryption context internally when we do
- * encryption/decryption using the CryptoCipher#update interface.
- * </p>
- * <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). In
- * these situations, the counter is derived from the file position.
- * </p>
- * The IV can be calculated by combining the initial IV and the counter with
- * a lossless operation (concatenation, addition, or XOR).
- *
- * @see <a
- * href="http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29">
- * http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29</a>
- *
- * @param initIV initial IV
- * @param counter counter for input stream position
- * @param IV the IV for input stream position
- */
- static void calculateIV(byte[] initIV, long counter, byte[] IV) {
- Utils.checkArgument(initIV.length == CTRCryptoInputStream.AES_BLOCK_SIZE);
- Utils.checkArgument(IV.length == CTRCryptoInputStream.AES_BLOCK_SIZE);
-
- int i = IV.length; // IV length
- int j = 0; // counter bytes index
- int sum = 0;
- while (i-- > 0) {
- // (sum >>> Byte.SIZE) is the carry for addition
- sum = (initIV[i] & 0xff) + (sum >>> Byte.SIZE); // NOPMD
- if (j++ < 8) { // Big-endian, and long is 8 bytes length
- sum += (byte) counter & 0xff;
- counter >>>= 8;
- }
- IV[i] = (byte) sum;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ba14d801/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
deleted file mode 100644
index 6f9ea6b..0000000
--- a/src/main/java/org/apache/commons/crypto/stream/CTRCryptoOutputStream.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 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.Cipher;
-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.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;
-
-/**
- * <p>
- * 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>
- * <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.
- */
- private long streamOffset = 0;
-
- /**
- * The initial IV.
- */
- private final byte[] initIV;
-
- /**
- * Initialization vector for the cipher.
- */
- private 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 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 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 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.
- */
- protected CTRCryptoOutputStream(OutputStream out, CryptoCipher cipher,
- int bufferSize, byte[] key, byte[] iv) throws IOException {
- this(out, cipher, bufferSize, key, iv, 0);
- }
-
- /**
- * Constructs a {@link 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.
- */
- protected CTRCryptoOutputStream(WritableByteChannel channel,
- CryptoCipher cipher, int bufferSize, byte[] key, byte[] iv)
- throws IOException {
- this(channel, cipher, bufferSize, key, iv, 0);
- }
-
- /**
- * Constructs a {@link 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.
- */
- protected CTRCryptoOutputStream(Output output, CryptoCipher cipher,
- int bufferSize, byte[] key, byte[] iv) throws IOException {
- this(output, cipher, bufferSize, key, iv, 0);
- }
-
- /**
- * Constructs a {@link 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(
- "AES/CTR/NoPadding", props),
- CryptoInputStream.getBufferSize(props), key, iv, streamOffset);
- }
-
- /**
- * Constructs a {@link 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(
- "AES/CTR/NoPadding", props),
- CryptoInputStream.getBufferSize(props), key, iv, streamOffset);
- }
-
- /**
- * Constructs a {@link 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.
- */
- protected 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 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.
- */
- protected 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 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.
- */
- protected 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));
-
- CryptoInputStream.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.getBlockSize();
- padding = (byte) (streamOffset % cipher.getBlockSize());
- inBuffer.position(padding); // Set proper position for input data.
-
- CTRCryptoInputStream.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. 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/ba14d801/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
index 655f3b5..334d391 100644
--- a/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java
+++ b/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java
@@ -356,7 +356,7 @@ public class CryptoInputStream extends InputStream implements
/**
* Overrides the {@link InputStream#markSupported()}.
*
- * @return false,the {@link CTRCryptoInputStream} don't support the mark
+ * @return false,the {@link CtrCryptoInputStream} don't support the mark
* method.
*/
@Override
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ba14d801/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..56ad048
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/stream/CtrCryptoInputStream.java
@@ -0,0 +1,672 @@
+/**
+ * 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.Cipher;
+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.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;
+
+/**
+ * <p>
+ * 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>
+ * <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
+ */
+ private long streamOffset = 0;
+
+ /**
+ * The initial IV.
+ */
+ private final byte[] initIV;
+
+ /**
+ * Initialization vector for the cipher.
+ */
+ private 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;
+
+ /**
+ * For AES, the algorithm block is fixed size of 128 bits.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard">
+ * http://en.wikipedia.org/wiki/Advanced_Encryption_Standard</a>
+ */
+ private static final int AES_BLOCK_SIZE = 16;
+
+ /**
+ * Constructs a {@link 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 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 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.
+ */
+ protected CtrCryptoInputStream(InputStream in, CryptoCipher cipher,
+ int bufferSize, byte[] key, byte[] iv) throws IOException {
+ this(in, cipher, bufferSize, key, iv, 0);
+ }
+
+ /**
+ * Constructs a {@link 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.
+ */
+ protected CtrCryptoInputStream(ReadableByteChannel in, CryptoCipher cipher,
+ int bufferSize, byte[] key, byte[] iv) throws IOException {
+ this(in, cipher, bufferSize, key, iv, 0);
+ }
+
+ /**
+ * Constructs a {@link 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.
+ */
+ protected CtrCryptoInputStream(Input input, CryptoCipher cipher,
+ int bufferSize, byte[] key, byte[] iv) throws IOException {
+ this(input, cipher, bufferSize, key, iv, 0);
+ }
+
+ /**
+ * Constructs a {@link 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(
+ "AES/CTR/NoPadding", props),
+ CryptoInputStream.getBufferSize(props), key, iv, streamOffset);
+ }
+
+ /**
+ * Constructs a {@link 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(
+ "AES/CTR/NoPadding", props),
+ CryptoInputStream.getBufferSize(props), key, iv, streamOffset);
+ }
+
+ /**
+ * Constructs a {@link 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.
+ */
+ protected 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 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.
+ */
+ protected 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 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.
+ */
+ protected 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();
+
+ CryptoInputStream.checkStreamCipher(cipher);
+
+ resetStreamOffset(streamOffset);
+ }
+
+ /**
+ * Overrides the {@link 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 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;
+ }
+ // 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;
+ }
+ 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;
+ }
+
+ /**
+ * Sets the offset of stream.
+ *
+ * @param streamOffset the stream offset.
+ */
+ 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> <tt>+</tt> <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.
+ * @throws IOException if an I/O error occurs.
+ */
+ 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.getBlockSize();
+ }
+
+ /**
+ * 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.getBlockSize());
+ }
+
+ /**
+ * 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);
+ CtrCryptoInputStream.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. 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);
+ }
+ }
+
+ /**
+ * <p>
+ * This method is only for Counter (CTR) mode. Generally the CryptoCipher
+ * calculates the IV and maintain encryption context internally.For example
+ * a Cipher will maintain its encryption context internally when we do
+ * encryption/decryption using the CryptoCipher#update interface.
+ * </p>
+ * <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). In
+ * these situations, the counter is derived from the file position.
+ * </p>
+ * The IV can be calculated by combining the initial IV and the counter with
+ * a lossless operation (concatenation, addition, or XOR).
+ *
+ * @see <a
+ * href="http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29">
+ * http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29</a>
+ *
+ * @param initIV initial IV
+ * @param counter counter for input stream position
+ * @param IV the IV for input stream position
+ */
+ static void calculateIV(byte[] initIV, long counter, byte[] IV) {
+ Utils.checkArgument(initIV.length == CtrCryptoInputStream.AES_BLOCK_SIZE);
+ Utils.checkArgument(IV.length == CtrCryptoInputStream.AES_BLOCK_SIZE);
+
+ int i = IV.length; // IV length
+ int j = 0; // counter bytes index
+ int sum = 0;
+ while (i-- > 0) {
+ // (sum >>> Byte.SIZE) is the carry for addition
+ sum = (initIV[i] & 0xff) + (sum >>> Byte.SIZE); // NOPMD
+ if (j++ < 8) { // Big-endian, and long is 8 bytes length
+ sum += (byte) counter & 0xff;
+ counter >>>= 8;
+ }
+ IV[i] = (byte) sum;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ba14d801/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..c05b0c0
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/stream/CtrCryptoOutputStream.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 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.Cipher;
+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.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;
+
+/**
+ * <p>
+ * 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>
+ * <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.
+ */
+ private long streamOffset = 0;
+
+ /**
+ * The initial IV.
+ */
+ private final byte[] initIV;
+
+ /**
+ * Initialization vector for the cipher.
+ */
+ private 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 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 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 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.
+ */
+ protected CtrCryptoOutputStream(OutputStream out, CryptoCipher cipher,
+ int bufferSize, byte[] key, byte[] iv) throws IOException {
+ this(out, cipher, bufferSize, key, iv, 0);
+ }
+
+ /**
+ * Constructs a {@link 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.
+ */
+ protected CtrCryptoOutputStream(WritableByteChannel channel,
+ CryptoCipher cipher, int bufferSize, byte[] key, byte[] iv)
+ throws IOException {
+ this(channel, cipher, bufferSize, key, iv, 0);
+ }
+
+ /**
+ * Constructs a {@link 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.
+ */
+ protected CtrCryptoOutputStream(Output output, CryptoCipher cipher,
+ int bufferSize, byte[] key, byte[] iv) throws IOException {
+ this(output, cipher, bufferSize, key, iv, 0);
+ }
+
+ /**
+ * Constructs a {@link 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(
+ "AES/CTR/NoPadding", props),
+ CryptoInputStream.getBufferSize(props), key, iv, streamOffset);
+ }
+
+ /**
+ * Constructs a {@link 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(
+ "AES/CTR/NoPadding", props),
+ CryptoInputStream.getBufferSize(props), key, iv, streamOffset);
+ }
+
+ /**
+ * Constructs a {@link 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.
+ */
+ protected 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 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.
+ */
+ protected 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 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.
+ */
+ protected 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));
+
+ CryptoInputStream.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.getBlockSize();
+ padding = (byte) (streamOffset % cipher.getBlockSize());
+ inBuffer.position(padding); // Set proper position for input data.
+
+ CtrCryptoInputStream.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. 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/ba14d801/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
index bd6c39d..b3d0509 100644
--- a/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java
+++ b/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java
@@ -42,7 +42,7 @@ import org.apache.commons.crypto.utils.Utils;
* 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 {
+public class PositionedCryptoInputStream extends CtrCryptoInputStream {
/**
* DirectBuffer pool
@@ -296,7 +296,7 @@ public class PositionedCryptoInputStream extends CTRCryptoInputStream {
private void resetCipher(CipherState state, long position, byte[] iv)
throws IOException {
final long counter = getCounter(position);
- CTRCryptoInputStream.calculateIV(getInitIV(), counter, iv);
+ CtrCryptoInputStream.calculateIV(getInitIV(), counter, iv);
try {
state.getCipher().init(Cipher.DECRYPT_MODE, key,
new IvParameterSpec(iv));
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ba14d801/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java
deleted file mode 100644
index 3ba55ec..0000000
--- a/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java
+++ /dev/null
@@ -1,55 +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.CryptoCipher;
-
-public class CTRCryptoStreamTest extends AbstractCipherStreamTest {
-
- @Override
- public void setUp() throws IOException {
- transformation = "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);
- }
- 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);
- }
- return new CTRCryptoOutputStream(baos, cipher, bufferSize, key, iv);
- }
-}
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ba14d801/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCipherStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCipherStreamTest.java
deleted file mode 100644
index 76b8a7e..0000000
--- a/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCipherStreamTest.java
+++ /dev/null
@@ -1,29 +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;
-
-public class CTRNoPaddingCipherStreamTest extends AbstractCipherStreamTest {
-
- @Override
- public void setUp() throws IOException {
- transformation = "AES/CTR/NoPadding";
- }
-
-}
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/ba14d801/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..7b9c12b
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/stream/CtrCryptoStreamTest.java
@@ -0,0 +1,55 @@
+/**
+ * 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;
+
+public class CtrCryptoStreamTest extends AbstractCipherStreamTest {
+
+ @Override
+ public void setUp() throws IOException {
+ transformation = "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);
+ }
+ 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);
+ }
+ return new CtrCryptoOutputStream(baos, cipher, bufferSize, key, iv);
+ }
+}