diff --git a/Crypto/src/crypto/io/CipherStream.cs b/Crypto/src/crypto/io/CipherStream.cs
new file mode 100644
index 000000000..bf7effb0a
--- /dev/null
+++ b/Crypto/src/crypto/io/CipherStream.cs
@@ -0,0 +1,237 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.IO
+{
+ public class CipherStream
+ : Stream
+ {
+ internal Stream stream;
+ internal IBufferedCipher inCipher, outCipher;
+ private byte[] mInBuf;
+ private int mInPos;
+ private bool inStreamEnded;
+
+ public CipherStream(
+ Stream stream,
+ IBufferedCipher readCipher,
+ IBufferedCipher writeCipher)
+ {
+ this.stream = stream;
+
+ if (readCipher != null)
+ {
+ this.inCipher = readCipher;
+ mInBuf = null;
+ }
+
+ if (writeCipher != null)
+ {
+ this.outCipher = writeCipher;
+ }
+ }
+
+ public IBufferedCipher ReadCipher
+ {
+ get { return inCipher; }
+ }
+
+ public IBufferedCipher WriteCipher
+ {
+ get { return outCipher; }
+ }
+
+ public override int ReadByte()
+ {
+ if (inCipher == null)
+ return stream.ReadByte();
+
+ if (mInBuf == null || mInPos >= mInBuf.Length)
+ {
+ if (!FillInBuf())
+ return -1;
+ }
+
+ return mInBuf[mInPos++];
+ }
+
+ public override int Read(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (inCipher == null)
+ return stream.Read(buffer, offset, count);
+
+ int num = 0;
+ while (num < count)
+ {
+ if (mInBuf == null || mInPos >= mInBuf.Length)
+ {
+ if (!FillInBuf())
+ break;
+ }
+
+ int numToCopy = System.Math.Min(count - num, mInBuf.Length - mInPos);
+ Array.Copy(mInBuf, mInPos, buffer, offset + num, numToCopy);
+ mInPos += numToCopy;
+ num += numToCopy;
+ }
+
+ return num;
+ }
+
+ private bool FillInBuf()
+ {
+ if (inStreamEnded)
+ return false;
+
+ mInPos = 0;
+
+ do
+ {
+ mInBuf = ReadAndProcessBlock();
+ }
+ while (!inStreamEnded && mInBuf == null);
+
+ return mInBuf != null;
+ }
+
+ private byte[] ReadAndProcessBlock()
+ {
+ int blockSize = inCipher.GetBlockSize();
+ int readSize = (blockSize == 0) ? 256 : blockSize;
+
+ byte[] block = new byte[readSize];
+ int numRead = 0;
+ do
+ {
+ int count = stream.Read(block, numRead, block.Length - numRead);
+ if (count < 1)
+ {
+ inStreamEnded = true;
+ break;
+ }
+ numRead += count;
+ }
+ while (numRead < block.Length);
+
+ Debug.Assert(inStreamEnded || numRead == block.Length);
+
+ byte[] bytes = inStreamEnded
+ ? inCipher.DoFinal(block, 0, numRead)
+ : inCipher.ProcessBytes(block);
+
+ if (bytes != null && bytes.Length == 0)
+ {
+ bytes = null;
+ }
+
+ return bytes;
+ }
+
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ Debug.Assert(buffer != null);
+ Debug.Assert(0 <= offset && offset <= buffer.Length);
+ Debug.Assert(count >= 0);
+
+ int end = offset + count;
+
+ Debug.Assert(0 <= end && end <= buffer.Length);
+
+ if (outCipher == null)
+ {
+ stream.Write(buffer, offset, count);
+ return;
+ }
+
+ byte[] data = outCipher.ProcessBytes(buffer, offset, count);
+ if (data != null)
+ {
+ stream.Write(data, 0, data.Length);
+ }
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ if (outCipher == null)
+ {
+ stream.WriteByte(b);
+ return;
+ }
+
+ byte[] data = outCipher.ProcessByte(b);
+ if (data != null)
+ {
+ stream.Write(data, 0, data.Length);
+ }
+ }
+
+ public override bool CanRead
+ {
+ get { return stream.CanRead && (inCipher != null); }
+ }
+
+ public override bool CanWrite
+ {
+ get { return stream.CanWrite && (outCipher != null); }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public sealed override long Length
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public sealed override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (outCipher != null)
+ {
+ byte[] data = outCipher.DoFinal();
+ stream.Write(data, 0, data.Length);
+ stream.Flush();
+ }
+ stream.Dispose();
+ }
+ }
+
+ public override void Flush()
+ {
+ // Note: outCipher.DoFinal is only called during Close()
+ stream.Flush();
+ }
+
+ public sealed override long Seek(
+ long offset,
+ SeekOrigin origin)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override void SetLength(
+ long length)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
|