//
// 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;
}
}
}