225 lines
5.0 KiB
C#
225 lines
5.0 KiB
C#
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 pos = offset;
|
|
// int end = offset + count;
|
|
// try
|
|
// {
|
|
// while (pos < end)
|
|
// {
|
|
// if (mInPos >= mInBufEnd && !FillInBuf()) break;
|
|
//
|
|
// int len = System.Math.Min(end - pos, mInBufEnd - mInPos);
|
|
// Array.Copy(mInBuf, mInPos, buffer, pos, len);
|
|
// mInPos += len;
|
|
// pos += len;
|
|
// }
|
|
// }
|
|
// catch (IOException)
|
|
// {
|
|
// if (pos == offset) throw;
|
|
// }
|
|
// return pos - offset;
|
|
|
|
// TODO Optimise
|
|
int i = 0;
|
|
while (i < count)
|
|
{
|
|
int c = ReadByte();
|
|
|
|
if (c < 0) break;
|
|
|
|
buffer[offset + i++] = (byte) c;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
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 value)
|
|
{
|
|
if (outCipher == null)
|
|
{
|
|
stream.WriteByte(value);
|
|
return;
|
|
}
|
|
|
|
byte[] data = outCipher.ProcessByte(value);
|
|
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(); }
|
|
}
|
|
public override void Close()
|
|
{
|
|
if (outCipher != null)
|
|
{
|
|
byte[] data = outCipher.DoFinal();
|
|
stream.Write(data, 0, data.Length);
|
|
stream.Flush();
|
|
}
|
|
stream.Close();
|
|
}
|
|
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 value) { throw new NotSupportedException(); }
|
|
}
|
|
}
|