2023-06-21 12:46:23 -04:00

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(); }
}
}