http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/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 index 1b76db2..2b86c6d 100644 --- a/src/main/java/org/apache/commons/crypto/stream/CTRCryptoOutputStream.java +++ b/src/main/java/org/apache/commons/crypto/stream/CTRCryptoOutputStream.java @@ -46,342 +46,341 @@ import org.apache.commons.crypto.utils.Utils; * (1) calculating counter and (2) padding through stream position. * </p> * <p> - * counter = base + pos/(algorithm blocksize); - * padding = pos%(algorithm blocksize); + * 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; + /** + * Underlying stream offset. + */ + long streamOffset = 0; - /** - * The initial IV. - */ - protected final byte[] initIV; + /** + * The initial IV. + */ + protected final byte[] initIV; - /** - * Initialization vector for the cipher. - */ - protected byte[] iv; + /** + * 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; + /** + * 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; + /** + * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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)); + /** + * 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. + */ + 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); + } - Utils.checkStreamCipher(cipher); - this.streamOffset = streamOffset; - this.initIV = iv.clone(); - this.iv = iv.clone(); + /** + * 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. + */ + 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)); - resetCipher(); - } + Utils.checkStreamCipher(cipher); + this.streamOffset = streamOffset; + this.initIV = iv.clone(); + this.iv = iv.clone(); - /** - * 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; + resetCipher(); } - inBuffer.flip(); - outBuffer.clear(); - encryptBuffer(outBuffer); - inBuffer.clear(); - outBuffer.flip(); + /** + * 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; + } - 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; - } + 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(); + 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(); - } + /** + * 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 - } + /** + * 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. + /** + * 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); + 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; } - 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); + /** + * 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; - } + /** + * 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; - } + /** + * 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/95a8d486/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 7b4313b..edf3e7f 100644 --- a/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java +++ b/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java @@ -40,521 +40,526 @@ 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. + * 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"); + 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); } - 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; + /** + * 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); } - 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; + /** + * 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); } - } - - /** - * 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; + + /** + * 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); } - long remaining = n; - int nd; + /** + * 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(); + } - while (remaining > 0) { - if(remaining <= outBuffer.remaining()) { - // Skip in the remaining buffer - int pos = outBuffer.position() + (int) remaining; - outBuffer.position(pos); + /** + * 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; + } - remaining = 0; - break; - } else { - remaining -= outBuffer.remaining(); - outBuffer.clear(); - } + /** + * 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"); + } - nd = decryptMore(); - if (nd < 0) { - break; - } + /** + * Overrides the {@link InputStream#markSupported()}. + * + * @return false,the {@link CTRCryptoInputStream} don't support the mark + * method. + */ + @Override + public boolean markSupported() { + return false; } - 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; + /** + * Overrides the {@link Channel#isOpen()}. + * + * @return <tt>true</tt> if, and only if, this channel is open. + */ + @Override + public boolean isOpen() { + return !closed; } - 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 CTRCryptoInputStream} 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; - } + /** + * 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; + } } - // 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 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); + + /** + * Gets the key. + * + * @return the key. + */ + protected Key getKey() { + return key; + } + + /** + * Gets the internal CryptoCipher. + * + * @return the cipher instance. + */ + protected CryptoCipher getCipher() { + return cipher; } - } - - /** - * 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. - * @throws IOException if an I/O error occurs. - */ - protected int decryptMore() throws IOException { - if(finalDone) { - return -1; + + /** + * Gets the specification of cryptographic parameters. + * + * @return the params. + */ + protected AlgorithmParameterSpec getParams() { + return params; } - 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(); + /** + * Gets the input. + * + * @return the input. + */ + protected Input getInput() { + return input; } - } - - /** - * 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); + + /** + * 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); + } } - // 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); + /** + * 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. + * @throws IOException if an I/O error occurs. + */ + 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(); + } } - // 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"); + /** + * 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(); } - } - /** Forcibly free the direct buffers. */ - protected void freeBuffers() { - Utils.freeDirectBuffer(inBuffer); - Utils.freeDirectBuffer(outBuffer); - } + /** + * 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/95a8d486/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 index ef91beb..2fd00d2 100644 --- a/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java +++ b/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java @@ -43,399 +43,393 @@ 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. + * 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 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 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 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 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 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"); + 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 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); + } - 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(); + /** + * Constructs a {@link 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); + } - 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(); - } + /** + * Constructs a {@link 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 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 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 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; + + /** + * 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); } - try { - encryptFinal(); - output.close(); - freeBuffers(); - cipher.close(); - super.close(); - } finally { - closed = true; + /** + * 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 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; + + /** + * 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); } - 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 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); } - } - - /** - * 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); + + protected void checkStream() throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } } - 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); + /** Forcibly free the direct buffers. */ + protected void freeBuffers() { + Utils.freeDirectBuffer(inBuffer); + Utils.freeDirectBuffer(outBuffer); } - inBuffer.clear(); - outBuffer.flip(); + /** + * Gets the outBuffer. + * + * @return the outBuffer. + */ + protected ByteBuffer getOutBuffer() { + return outBuffer; + } - // write to output - output.write(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; + } - protected void checkStream() throws IOException { - if (closed) { - throw new IOException("Stream closed"); + /** + * Gets the inBuffer. + * + * @return the inBuffer. + */ + protected ByteBuffer getInBuffer() { + return inBuffer; } - } - - /** 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; - } }