diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/io')
6 files changed, 620 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java new file mode 100644 index 0000000..bb09a76 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java @@ -0,0 +1,244 @@ +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.StreamCipher; + +/** + * A CipherInputStream is composed of an InputStream and a BufferedBlockCipher 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 BufferedBlockCipher bufferedBlockCipher; + private StreamCipher streamCipher; + + private byte[] buf; + private byte[] inBuf; + + private int bufOff; + private int maxBuf; + private boolean finalized; + + private static final int INPUT_BUF_SIZE = 2048; + + /** + * Constructs a CipherInputStream from an InputStream and a + * BufferedBlockCipher. + */ + public CipherInputStream( + InputStream is, + BufferedBlockCipher cipher) + { + super(is); + + this.bufferedBlockCipher = cipher; + + buf = new byte[cipher.getOutputSize(INPUT_BUF_SIZE)]; + inBuf = new byte[INPUT_BUF_SIZE]; + } + + public CipherInputStream( + InputStream is, + StreamCipher cipher) + { + super(is); + + this.streamCipher = cipher; + + buf = new byte[INPUT_BUF_SIZE]; + inBuf = new byte[INPUT_BUF_SIZE]; + } + + /** + * grab the next chunk of input from the underlying input stream + */ + private int nextChunk() + throws IOException + { + int available = super.available(); + + // must always try to read 1 byte! + // some buggy InputStreams return < 0! + if (available <= 0) + { + available = 1; + } + + if (available > inBuf.length) + { + available = super.read(inBuf, 0, inBuf.length); + } + else + { + available = super.read(inBuf, 0, available); + } + + if (available < 0) + { + if (finalized) + { + return -1; + } + + try + { + if (bufferedBlockCipher != null) + { + maxBuf = bufferedBlockCipher.doFinal(buf, 0); + } + else + { + maxBuf = 0; // a stream cipher + } + } + catch (Exception e) + { + throw new IOException("error processing stream: " + e.toString()); + } + + bufOff = 0; + + finalized = true; + + if (bufOff == maxBuf) + { + return -1; + } + } + else + { + bufOff = 0; + + try + { + if (bufferedBlockCipher != null) + { + maxBuf = bufferedBlockCipher.processBytes(inBuf, 0, available, buf, 0); + } + else + { + streamCipher.processBytes(inBuf, 0, available, buf, 0); + maxBuf = available; + } + } + catch (Exception e) + { + throw new IOException("error processing stream: " + e.toString()); + } + + if (maxBuf == 0) // not enough bytes read for first block... + { + return nextChunk(); + } + } + + return maxBuf; + } + + public int read() + throws IOException + { + if (bufOff == maxBuf) + { + if (nextChunk() < 0) + { + return -1; + } + } + + return buf[bufOff++] & 0xff; + } + + public int read( + byte[] b) + throws IOException + { + return read(b, 0, b.length); + } + + public int read( + byte[] b, + int off, + int len) + throws IOException + { + if (bufOff == maxBuf) + { + if (nextChunk() < 0) + { + return -1; + } + } + + int available = maxBuf - bufOff; + + if (len > available) + { + System.arraycopy(buf, bufOff, b, off, available); + bufOff = maxBuf; + + return available; + } + else + { + System.arraycopy(buf, bufOff, b, off, len); + bufOff += len; + + return len; + } + } + + public long skip( + long n) + throws IOException + { + if (n <= 0) + { + return 0; + } + + int available = maxBuf - bufOff; + + if (n > available) + { + bufOff = maxBuf; + + return available; + } + else + { + bufOff += (int)n; + + return (int)n; + } + } + + public int available() + throws IOException + { + return maxBuf - bufOff; + } + + public void close() + throws IOException + { + super.close(); + } + + public boolean markSupported() + { + return false; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java new file mode 100644 index 0000000..17a7b6d --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java @@ -0,0 +1,188 @@ +package org.bouncycastle.crypto.io; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.bouncycastle.crypto.BufferedBlockCipher; +import org.bouncycastle.crypto.StreamCipher; + +public class CipherOutputStream + extends FilterOutputStream +{ + private BufferedBlockCipher bufferedBlockCipher; + private StreamCipher streamCipher; + + private byte[] oneByte = new byte[1]; + private byte[] buf; + + /** + * Constructs a CipherOutputStream from an OutputStream and a + * BufferedBlockCipher. + */ + public CipherOutputStream( + OutputStream os, + BufferedBlockCipher cipher) + { + super(os); + this.bufferedBlockCipher = cipher; + this.buf = new byte[cipher.getBlockSize()]; + } + + /** + * Constructs a CipherOutputStream from an OutputStream and a + * BufferedBlockCipher. + */ + public CipherOutputStream( + OutputStream os, + StreamCipher cipher) + { + super(os); + this.streamCipher = cipher; + } + + /** + * Writes the specified byte to this output stream. + * + * @param b the <code>byte</code>. + * @exception java.io.IOException if an I/O error occurs. + */ + public void write( + int b) + throws IOException + { + oneByte[0] = (byte)b; + + if (bufferedBlockCipher != null) + { + int len = bufferedBlockCipher.processBytes(oneByte, 0, 1, buf, 0); + + if (len != 0) + { + out.write(buf, 0, len); + } + } + else + { + out.write(streamCipher.returnByte((byte)b)); + } + } + + /** + * Writes <code>b.length</code> bytes from the specified byte array + * to this output stream. + * <p> + * The <code>write</code> method of + * <code>CipherOutputStream</code> calls the <code>write</code> + * method of three arguments with the three arguments + * <code>b</code>, <code>0</code>, and <code>b.length</code>. + * + * @param b the data. + * @exception java.io.IOException if an I/O error occurs. + * @see #write(byte[], int, int) + */ + public void write( + byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + /** + * Writes <code>len</code> bytes from the specified byte array + * starting at offset <code>off</code> to this output stream. + * + * @param b the data. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @exception java.io.IOException if an I/O error occurs. + */ + public void write( + byte[] b, + int off, + int len) + throws IOException + { + if (bufferedBlockCipher != null) + { + byte[] buf = new byte[bufferedBlockCipher.getOutputSize(len)]; + + int outLen = bufferedBlockCipher.processBytes(b, off, len, buf, 0); + + if (outLen != 0) + { + out.write(buf, 0, outLen); + } + } + else + { + byte[] buf = new byte[len]; + + streamCipher.processBytes(b, off, len, buf, 0); + + out.write(buf, 0, len); + } + } + + /** + * Flushes this output stream by forcing any buffered output bytes + * that have already been processed by the encapsulated cipher object + * to be written out. + * + * <p> + * Any bytes buffered by the encapsulated cipher + * and waiting to be processed by it will not be written out. For example, + * if the encapsulated cipher is a block cipher, and the total number of + * bytes written using one of the <code>write</code> methods is less than + * the cipher's block size, no bytes will be written out. + * + * @exception java.io.IOException if an I/O error occurs. + */ + public void flush() + throws IOException + { + super.flush(); + } + + /** + * Closes this output stream and releases any system resources + * associated with this stream. + * <p> + * This method invokes the <code>doFinal</code> method of the encapsulated + * cipher object, which causes any bytes buffered by the encapsulated + * cipher to be processed. The result is written out by calling the + * <code>flush</code> method of this output stream. + * <p> + * This method resets the encapsulated cipher object to its initial state + * and calls the <code>close</code> method of the underlying output + * stream. + * + * @exception java.io.IOException if an I/O error occurs. + */ + public void close() + throws IOException + { + try + { + if (bufferedBlockCipher != null) + { + byte[] buf = new byte[bufferedBlockCipher.getOutputSize(0)]; + + int outLen = bufferedBlockCipher.doFinal(buf, 0); + + if (outLen != 0) + { + out.write(buf, 0, outLen); + } + } + } + catch (Exception e) + { + throw new IOException("Error closing stream: " + e.toString()); + } + + flush(); + + super.close(); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java new file mode 100644 index 0000000..ef0b03e --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java @@ -0,0 +1,52 @@ +package org.bouncycastle.crypto.io; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.crypto.Digest; + +public class DigestInputStream + extends FilterInputStream +{ + protected Digest digest; + + public DigestInputStream( + InputStream stream, + Digest digest) + { + super(stream); + this.digest = digest; + } + + public int read() + throws IOException + { + int b = in.read(); + + if (b >= 0) + { + digest.update((byte)b); + } + return b; + } + + public int read( + byte[] b, + int off, + int len) + throws IOException + { + int n = in.read(b, off, len); + if (n > 0) + { + digest.update(b, off, n); + } + return n; + } + + public Digest getDigest() + { + return digest; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java new file mode 100644 index 0000000..23c7e53 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java @@ -0,0 +1,42 @@ +package org.bouncycastle.crypto.io; + +import java.io.IOException; +import java.io.OutputStream; + +import org.bouncycastle.crypto.Digest; + +public class DigestOutputStream + extends OutputStream +{ + protected Digest digest; + + public DigestOutputStream( + Digest Digest) + { + this.digest = Digest; + } + + public void write(int b) + throws IOException + { + digest.update((byte)b); + } + + public void write( + byte[] b, + int off, + int len) + throws IOException + { + digest.update(b, off, len); + } + + public byte[] getDigest() + { + byte[] res = new byte[digest.getDigestSize()]; + + digest.doFinal(res, 0); + + return res; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java new file mode 100644 index 0000000..b78548c --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java @@ -0,0 +1,52 @@ +package org.bouncycastle.crypto.io; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.crypto.Mac; + +public class MacInputStream + extends FilterInputStream +{ + protected Mac mac; + + public MacInputStream( + InputStream stream, + Mac mac) + { + super(stream); + this.mac = mac; + } + + public int read() + throws IOException + { + int b = in.read(); + + if (b >= 0) + { + mac.update((byte)b); + } + return b; + } + + public int read( + byte[] b, + int off, + int len) + throws IOException + { + int n = in.read(b, off, len); + if (n >= 0) + { + mac.update(b, off, n); + } + return n; + } + + public Mac getMac() + { + return mac; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java new file mode 100644 index 0000000..0f0e7db --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java @@ -0,0 +1,42 @@ +package org.bouncycastle.crypto.io; + +import java.io.IOException; +import java.io.OutputStream; + +import org.bouncycastle.crypto.Mac; + +public class MacOutputStream + extends OutputStream +{ + protected Mac mac; + + public MacOutputStream( + Mac mac) + { + this.mac = mac; + } + + public void write(int b) + throws IOException + { + mac.update((byte)b); + } + + public void write( + byte[] b, + int off, + int len) + throws IOException + { + mac.update(b, off, len); + } + + public byte[] getMac() + { + byte[] res = new byte[mac.getMacSize()]; + + mac.doFinal(res, 0); + + return res; + } +} |