HashProviderBase
using System;
namespace SshNet.Security.Cryptography
{
    internal abstract class HashProviderBase : IHashProvider, IDisposable
    {
        private bool _disposed;
        private byte[] _hashValue;
        public byte[] Hash {
            get {
                if (_disposed)
                    throw new ObjectDisposedException(GetType().FullName);
                return (byte[])_hashValue.Clone();
            }
        }
        public abstract int HashSize { get; }
        public abstract int InputBlockSize { get; }
        public abstract int OutputBlockSize { get; }
        public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
        {
            if (_disposed)
                throw new ObjectDisposedException(GetType().FullName);
            if (inputBuffer == null)
                throw new ArgumentNullException("inputBuffer");
            if (inputOffset < 0)
                throw new ArgumentOutOfRangeException("inputOffset");
            if (inputCount < 0 || inputCount > inputBuffer.Length)
                throw new ArgumentException("XX");
            if (inputBuffer.Length - inputCount < inputOffset)
                throw new ArgumentException("xx");
            HashCore(inputBuffer, inputOffset, inputCount);
            Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
            return inputCount;
        }
        public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
        {
            if (_disposed)
                throw new ObjectDisposedException(GetType().FullName);
            if (inputBuffer == null)
                throw new ArgumentNullException("inputBuffer");
            if (inputOffset < 0)
                throw new ArgumentOutOfRangeException("inputOffset");
            if (inputCount < 0 || inputCount > inputBuffer.Length)
                throw new ArgumentException("XX");
            if (inputBuffer.Length - inputCount < inputOffset)
                throw new ArgumentException("xx");
            HashCore(inputBuffer, inputOffset, inputCount);
            _hashValue = HashFinal();
            byte[] array = new byte[inputCount];
            Buffer.BlockCopy(inputBuffer, inputOffset, array, 0, inputCount);
            return array;
        }
        public byte[] ComputeHash(byte[] buffer)
        {
            if (_disposed)
                throw new ObjectDisposedException(GetType().FullName);
            if (buffer == null)
                throw new ArgumentNullException("buffer");
            HashCore(buffer, 0, buffer.Length);
            _hashValue = HashFinal();
            Reset();
            return Hash;
        }
        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Dispose(true);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
                _hashValue = null;
            _disposed = true;
        }
        public abstract void Reset();
        public abstract void HashCore(byte[] array, int ibStart, int cbSize);
        public abstract byte[] HashFinal();
    }
}