<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />

CipherStream

public sealed class CipherStream : Stream
using Org.BouncyCastle.Utilities.IO; using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Org.BouncyCastle.Crypto.IO { public sealed class CipherStream : Stream { private readonly Stream m_stream; private readonly IBufferedCipher m_readCipher; private readonly IBufferedCipher m_writeCipher; private byte[] m_readBuf; private int m_readBufPos; private bool m_readEnded; public IBufferedCipher ReadCipher => m_readCipher; public IBufferedCipher WriteCipher => m_writeCipher; public override bool CanRead => m_stream.CanRead; public override bool CanSeek => false; public override bool CanWrite => m_stream.CanWrite; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } private Stream ReadSource { get { if (m_readCipher != null) return this; return m_stream; } } public CipherStream(Stream stream, IBufferedCipher readCipher, IBufferedCipher writeCipher) { m_stream = stream; if (readCipher != null) { m_readCipher = readCipher; m_readBuf = null; } if (writeCipher != null) m_writeCipher = writeCipher; } public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) { return Streams.CopyToAsync(ReadSource, destination, bufferSize, cancellationToken); } public override void Flush() { m_stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { if (m_readCipher == null) return m_stream.Read(buffer, offset, count); Streams.ValidateBufferArguments(buffer, offset, count); int i; int num; for (i = 0; i < count; i += num) { if ((m_readBuf == null || m_readBufPos >= m_readBuf.Length) && !FillInBuf()) break; num = System.Math.Min(count - i, m_readBuf.Length - m_readBufPos); Array.Copy(m_readBuf, m_readBufPos, buffer, offset + i, num); m_readBufPos += num; } return i; } public override int ReadByte() { if (m_readCipher == null) return m_stream.ReadByte(); if ((m_readBuf == null || m_readBufPos >= m_readBuf.Length) && !FillInBuf()) return -1; return m_readBuf[m_readBufPos++]; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long length) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (m_writeCipher == null) m_stream.Write(buffer, offset, count); else { Streams.ValidateBufferArguments(buffer, offset, count); if (count > 0) { byte[] array = new byte[m_writeCipher.GetUpdateOutputSize(count)]; int num = m_writeCipher.ProcessBytes(buffer, offset, count, array, 0); if (num > 0) try { m_stream.Write(array, 0, num); } finally { Array.Clear(array, 0, array.Length); } } } } public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (m_writeCipher == null) return m_stream.WriteAsync(buffer, offset, count, cancellationToken); Streams.ValidateBufferArguments(buffer, offset, count); if (count > 0) { if (cancellationToken.IsCancellationRequested) return Task.FromCanceled(cancellationToken); byte[] array = new byte[m_writeCipher.GetUpdateOutputSize(count)]; int num = m_writeCipher.ProcessBytes(buffer, offset, count, array, 0); if (num > 0) return Streams.WriteAsyncCompletion(m_stream.WriteAsync(array, 0, num, cancellationToken), array); } return Task.CompletedTask; } public override void WriteByte(byte value) { if (m_writeCipher == null) m_stream.WriteByte(value); else { byte[] array = m_writeCipher.ProcessByte(value); if (array != null) try { m_stream.Write(array, 0, array.Length); } finally { Array.Clear(array, 0, array.Length); } } } protected override void Dispose(bool disposing) { if (disposing) { if (m_writeCipher != null) { byte[] array = new byte[m_writeCipher.GetOutputSize(0)]; int count = m_writeCipher.DoFinal(array, 0); m_stream.Write(array, 0, count); Array.Clear(array, 0, array.Length); } m_stream.Dispose(); } base.Dispose(disposing); } private bool FillInBuf() { if (m_readEnded) return false; m_readBufPos = 0; do { m_readBuf = ReadAndProcessBlock(); } while (!m_readEnded && m_readBuf == null); return m_readBuf != null; } private byte[] ReadAndProcessBlock() { int blockSize = m_readCipher.GetBlockSize(); byte[] array = new byte[(blockSize == 0) ? 256 : blockSize]; int num = 0; do { int num2 = m_stream.Read(array, num, array.Length - num); if (num2 < 1) { m_readEnded = true; break; } num += num2; } while (num < array.Length); byte[] array2 = m_readEnded ? m_readCipher.DoFinal(array, 0, num) : m_readCipher.ProcessBytes(array); if (array2 != null && array2.Length == 0) array2 = null; return array2; } } }