diff options
Diffstat (limited to 'core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java')
-rw-r--r-- | core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java | 477 |
1 files changed, 0 insertions, 477 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java deleted file mode 100644 index b06d1f53..00000000 --- a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java +++ /dev/null @@ -1,477 +0,0 @@ -package org.bouncycastle.crypto.io; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.SkippingCipher; -import org.bouncycastle.crypto.StreamCipher; -import org.bouncycastle.crypto.modes.AEADBlockCipher; -import org.bouncycastle.util.Arrays; - -/** - * A CipherInputStream is composed of an InputStream and a cipher so that read() methods return data - * that are read in from the underlying InputStream but have been additionally processed by the - * Cipher. The cipher must be fully initialized before being used by a CipherInputStream. - * <p> - * For example, if the Cipher is initialized for decryption, the - * CipherInputStream will attempt to read in data and decrypt them, - * before returning the decrypted data. - */ -public class CipherInputStream - extends FilterInputStream -{ - private static final int INPUT_BUF_SIZE = 2048; - - private SkippingCipher skippingCipher; - private byte[] inBuf; - - private BufferedBlockCipher bufferedBlockCipher; - private StreamCipher streamCipher; - private AEADBlockCipher aeadBlockCipher; - - private byte[] buf; - private byte[] markBuf; - - - private int bufOff; - private int maxBuf; - private boolean finalized; - private long markPosition; - private int markBufOff; - - /** - * Constructs a CipherInputStream from an InputStream and a - * BufferedBlockCipher. - */ - public CipherInputStream( - InputStream is, - BufferedBlockCipher cipher) - { - this(is, cipher, INPUT_BUF_SIZE); - } - - /** - * Constructs a CipherInputStream from an InputStream and a StreamCipher. - */ - public CipherInputStream( - InputStream is, - StreamCipher cipher) - { - this(is, cipher, INPUT_BUF_SIZE); - } - - /** - * Constructs a CipherInputStream from an InputStream and an AEADBlockCipher. - */ - public CipherInputStream( - InputStream is, - AEADBlockCipher cipher) - { - this(is, cipher, INPUT_BUF_SIZE); - } - - /** - * Constructs a CipherInputStream from an InputStream, a - * BufferedBlockCipher, and a specified internal buffer size. - */ - public CipherInputStream( - InputStream is, - BufferedBlockCipher cipher, - int bufSize) - { - super(is); - - this.bufferedBlockCipher = cipher; - this.inBuf = new byte[bufSize]; - this.skippingCipher = (cipher instanceof SkippingCipher) ? (SkippingCipher)cipher : null; - } - - /** - * Constructs a CipherInputStream from an InputStream, a StreamCipher, and a specified internal buffer size. - */ - public CipherInputStream( - InputStream is, - StreamCipher cipher, - int bufSize) - { - super(is); - - this.streamCipher = cipher; - this.inBuf = new byte[bufSize]; - this.skippingCipher = (cipher instanceof SkippingCipher) ? (SkippingCipher)cipher : null; - } - - /** - * Constructs a CipherInputStream from an InputStream, an AEADBlockCipher, and a specified internal buffer size. - */ - public CipherInputStream( - InputStream is, - AEADBlockCipher cipher, - int bufSize) - { - super(is); - - this.aeadBlockCipher = cipher; - this.inBuf = new byte[bufSize]; - this.skippingCipher = (cipher instanceof SkippingCipher) ? (SkippingCipher)cipher : null; - } - - /** - * Read data from underlying stream and process with cipher until end of stream or some data is - * available after cipher processing. - * - * @return -1 to indicate end of stream, or the number of bytes (> 0) available. - */ - private int nextChunk() - throws IOException - { - if (finalized) - { - return -1; - } - - bufOff = 0; - maxBuf = 0; - - // Keep reading until EOF or cipher processing produces data - while (maxBuf == 0) - { - int read = in.read(inBuf); - if (read == -1) - { - finaliseCipher(); - if (maxBuf == 0) - { - return -1; - } - return maxBuf; - } - - try - { - ensureCapacity(read, false); - if (bufferedBlockCipher != null) - { - maxBuf = bufferedBlockCipher.processBytes(inBuf, 0, read, buf, 0); - } - else if (aeadBlockCipher != null) - { - maxBuf = aeadBlockCipher.processBytes(inBuf, 0, read, buf, 0); - } - else - { - streamCipher.processBytes(inBuf, 0, read, buf, 0); - maxBuf = read; - } - } - catch (Exception e) - { - throw new CipherIOException("Error processing stream ", e); - } - } - return maxBuf; - } - - private void finaliseCipher() - throws IOException - { - try - { - finalized = true; - ensureCapacity(0, true); - if (bufferedBlockCipher != null) - { - maxBuf = bufferedBlockCipher.doFinal(buf, 0); - } - else if (aeadBlockCipher != null) - { - maxBuf = aeadBlockCipher.doFinal(buf, 0); - } - else - { - maxBuf = 0; // a stream cipher - } - } - catch (final InvalidCipherTextException e) - { - throw new InvalidCipherTextIOException("Error finalising cipher", e); - } - catch (Exception e) - { - throw new IOException("Error finalising cipher " + e); - } - } - - /** - * Reads data from the underlying stream and processes it with the cipher until the cipher - * outputs data, and returns the next available byte. - * <p> - * If the underlying stream is exhausted by this call, the cipher will be finalised. - * </p> - * @throws IOException if there was an error closing the input stream. - * @throws InvalidCipherTextIOException if the data read from the stream was invalid ciphertext - * (e.g. the cipher is an AEAD cipher and the ciphertext tag check fails). - */ - public int read() - throws IOException - { - if (bufOff >= maxBuf) - { - if (nextChunk() < 0) - { - return -1; - } - } - - return buf[bufOff++] & 0xff; - } - - /** - * Reads data from the underlying stream and processes it with the cipher until the cipher - * outputs data, and then returns up to <code>b.length</code> bytes in the provided array. - * <p> - * If the underlying stream is exhausted by this call, the cipher will be finalised. - * </p> - * @param b the buffer into which the data is read. - * @return the total number of bytes read into the buffer, or <code>-1</code> if there is no - * more data because the end of the stream has been reached. - * @throws IOException if there was an error closing the input stream. - * @throws InvalidCipherTextIOException if the data read from the stream was invalid ciphertext - * (e.g. the cipher is an AEAD cipher and the ciphertext tag check fails). - */ - public int read( - byte[] b) - throws IOException - { - return read(b, 0, b.length); - } - - /** - * Reads data from the underlying stream and processes it with the cipher until the cipher - * outputs data, and then returns up to <code>len</code> bytes in the provided array. - * <p> - * If the underlying stream is exhausted by this call, the cipher will be finalised. - * </p> - * @param b the buffer into which the data is read. - * @param off the start offset in the destination array <code>b</code> - * @param len the maximum number of bytes read. - * @return the total number of bytes read into the buffer, or <code>-1</code> if there is no - * more data because the end of the stream has been reached. - * @throws IOException if there was an error closing the input stream. - * @throws InvalidCipherTextIOException if the data read from the stream was invalid ciphertext - * (e.g. the cipher is an AEAD cipher and the ciphertext tag check fails). - */ - public int read( - byte[] b, - int off, - int len) - throws IOException - { - if (bufOff >= maxBuf) - { - if (nextChunk() < 0) - { - return -1; - } - } - - int toSupply = Math.min(len, available()); - System.arraycopy(buf, bufOff, b, off, toSupply); - bufOff += toSupply; - return toSupply; - } - - public long skip( - long n) - throws IOException - { - if (n <= 0) - { - return 0; - } - - if (skippingCipher != null) - { - int avail = available(); - if (n <= avail) - { - bufOff += n; - - return n; - } - - bufOff = maxBuf; - - long skip = in.skip(n - avail); - - long cSkip = skippingCipher.skip(skip); - - if (skip != cSkip) - { - throw new IOException("Unable to skip cipher " + skip + " bytes."); - } - - return skip + avail; - } - else - { - int skip = (int)Math.min(n, available()); - bufOff += skip; - - return skip; - } - } - - public int available() - throws IOException - { - return maxBuf - bufOff; - } - - /** - * Ensure the cipher text buffer has space sufficient to accept an upcoming output. - * - * @param updateSize the size of the pending update. - * @param finalOutput <code>true</code> iff this the cipher is to be finalised. - */ - private void ensureCapacity(int updateSize, boolean finalOutput) - { - int bufLen = updateSize; - if (finalOutput) - { - if (bufferedBlockCipher != null) - { - bufLen = bufferedBlockCipher.getOutputSize(updateSize); - } - else if (aeadBlockCipher != null) - { - bufLen = aeadBlockCipher.getOutputSize(updateSize); - } - } - else - { - if (bufferedBlockCipher != null) - { - bufLen = bufferedBlockCipher.getUpdateOutputSize(updateSize); - } - else if (aeadBlockCipher != null) - { - bufLen = aeadBlockCipher.getUpdateOutputSize(updateSize); - } - } - - if ((buf == null) || (buf.length < bufLen)) - { - buf = new byte[bufLen]; - } - } - - /** - * Closes the underlying input stream and finalises the processing of the data by the cipher. - * - * @throws IOException if there was an error closing the input stream. - * @throws InvalidCipherTextIOException if the data read from the stream was invalid ciphertext - * (e.g. the cipher is an AEAD cipher and the ciphertext tag check fails). - */ - public void close() - throws IOException - { - try - { - in.close(); - } - finally - { - if (!finalized) - { - // Reset the cipher, discarding any data buffered in it - // Errors in cipher finalisation trump I/O error closing input - finaliseCipher(); - } - } - maxBuf = bufOff = 0; - markBufOff = 0; - markPosition = 0; - if (markBuf != null) - { - Arrays.fill(markBuf, (byte)0); - markBuf = null; - } - if (buf != null) - { - Arrays.fill(buf, (byte)0); - buf = null; - } - Arrays.fill(inBuf, (byte)0); - } - - /** - * Mark the current position. - * <p> - * This method only works if markSupported() returns true - which means the underlying stream supports marking, and the cipher passed - * in to this stream's constructor is a SkippingCipher (so capable of being reset to an arbitrary point easily). - * </p> - * @param readlimit the maximum read ahead required before a reset() may be called. - */ - public void mark(int readlimit) - { - in.mark(readlimit); - if (skippingCipher != null) - { - markPosition = skippingCipher.getPosition(); - } - - if (buf != null) - { - markBuf = new byte[buf.length]; - System.arraycopy(buf, 0, markBuf, 0, buf.length); - } - - markBufOff = bufOff; - } - - /** - * Reset to the last marked position, if supported. - * - * @throws IOException if marking not supported by the cipher used, or the underlying stream. - */ - public void reset() - throws IOException - { - if (skippingCipher == null) - { - throw new IOException("cipher must implement SkippingCipher to be used with reset()"); - } - - in.reset(); - - skippingCipher.seekTo(markPosition); - - if (markBuf != null) - { - buf = markBuf; - } - - bufOff = markBufOff; - } - - /** - * Return true if mark(readlimit) is supported. This will be true if the underlying stream supports marking and the - * cipher used is a SkippingCipher, - * - * @return true if mark(readlimit) supported, false otherwise. - */ - public boolean markSupported() - { - if (skippingCipher != null) - { - return in.markSupported(); - } - - return false; - } - -} |