// // System.Security.Cryptography HashAlgorithm Class implementation // // Authors: // Matthew S. Ford (Matthew.S.Ford@Rose-Hulman.Edu) // Sebastien Pouliot (spouliot@motus.com) // // Copyright 2001 by Matthew S. Ford. // Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com) // using System.IO; namespace System.Security.Cryptography { public abstract class HashAlgorithm : ICryptoTransform { protected byte[] HashValue; // Caches the hash after it is calculated. Accessed through the Hash property. protected int HashSizeValue; // The size of the hash in bits. protected int State; // nonzero when in use; zero when not in use private bool disposed; /// /// Called from constructor of derived class. /// protected HashAlgorithm () { disposed = false; } /// /// Get whether or not the hash can transform multiple blocks at a time. /// Note: MUST be overriden if descendant can transform multiple block /// on a single call! /// public virtual bool CanTransformMultipleBlocks { get { return true; } } public virtual bool CanReuseTransform { get { return true; } } public void Clear() { // same as System.IDisposable.Dispose() which is documented Dispose (true); } /// /// Computes the entire hash of all the bytes in the byte array. /// public byte[] ComputeHash (byte[] input) { return ComputeHash (input, 0, input.Length); } public byte[] ComputeHash (byte[] buffer, int offset, int count) { if (disposed) throw new ObjectDisposedException ("HashAlgorithm"); HashCore (buffer, offset, count); HashValue = HashFinal (); Initialize (); return HashValue; } public byte[] ComputeHash (Stream inputStream) { // don't read stream unless object is ready to use if (disposed) throw new ObjectDisposedException ("HashAlgorithm"); int l = (int) (inputStream.Length - inputStream.Position); byte[] buffer = new byte [l]; inputStream.Read (buffer, 0, l); return ComputeHash (buffer, 0, l); } /// /// Creates the default implementation of the default hash algorithm (SHA1). /// public static HashAlgorithm Create () { return Create ("System.Security.Cryptography.HashAlgorithm"); } /// /// Creates a specific implementation of the general hash idea. /// /// Specifies which derived class to create. public static HashAlgorithm Create (string hashName) { return (HashAlgorithm) CryptoConfig.CreateFromName (hashName); } /// /// Gets the previously computed hash. /// public virtual byte[] Hash { get { if (HashValue == null) throw new CryptographicUnexpectedOperationException (); return HashValue; } } /// /// When overridden in a derived class, drives the hashing function. /// /// /// /// protected abstract void HashCore (byte[] rgb, int start, int size); /// /// When overridden in a derived class, this pads and hashes whatever data might be left in the buffers and then returns the hash created. /// protected abstract byte[] HashFinal (); /// /// Returns the size in bits of the hash. /// public virtual int HashSize { get { return HashSizeValue; } } /// /// When overridden in a derived class, initializes the object to prepare for hashing. /// public abstract void Initialize (); protected virtual void Dispose (bool disposing) { disposed = true; } /// /// Must be overriden if not 1 /// public virtual int InputBlockSize { get { return 1; } } /// /// Must be overriden if not 1 /// public virtual int OutputBlockSize { get { return 1; } } void IDisposable.Dispose () { Dispose (true); GC.SuppressFinalize (this); // Finalization is now unnecessary } /// /// Used for stream chaining. Computes hash as data passes through it. /// /// The buffer from which to grab the data to be copied. /// The offset into the input buffer to start reading at. /// The number of bytes to be copied. /// The buffer to write the copied data to. /// At what point in the outputBuffer to write the data at. public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { Buffer.BlockCopy (inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount); HashCore (inputBuffer, inputOffset, inputCount); return inputCount; } /// /// Used for stream chaining. Computes hash as data passes through it. Finishes off the hash. /// /// The buffer from which to grab the data to be copied. /// The offset into the input buffer to start reading at. /// The number of bytes to be copied. public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount) { byte[] outputBuffer = new byte[inputCount]; Buffer.BlockCopy (inputBuffer, inputOffset, outputBuffer, 0, inputCount); HashCore (inputBuffer, inputOffset, inputCount); HashValue = HashFinal (); Initialize (); return outputBuffer; } } }