| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 | using System.Security.Cryptography;using System;namespace Renci.SshNet.Security.Cryptography{	/// <summary>	/// SHA1 algorithm implementation	/// </summary>	public class SHA1Hash : HashAlgorithm	{		private const int DIGEST_SIZE = 20;		private const uint Y1 = 0x5a827999;		private const uint Y2 = 0x6ed9eba1;		private const uint Y3 = 0x8f1bbcdc;		private const uint Y4 = 0xca62c1d6;		private uint H1, H2, H3, H4, H5;				private uint[] _hashValue = new uint[80];				private int _offset;		private byte[] _buffer;		private int _bufferOffset;		private long _byteCount;		/// <summary>		/// Gets the size, in bits, of the computed hash code.		/// </summary>		/// <returns>The size, in bits, of the computed hash code.</returns>		public override int HashSize		{			get			{				return DIGEST_SIZE * 8;			}		}		/// <summary>		/// Gets the input block size.		/// </summary>		/// <returns>The input block size.</returns>		public override int InputBlockSize		{			get			{				return 64;			}		}		/// <summary>		/// Gets the output block size.		/// </summary>		/// <returns>The output block size.</returns>		public override int OutputBlockSize		{			get			{				return 64;			}		}		/// <summary>		/// Gets a value indicating whether the current transform can be reused.		/// </summary>		/// <returns>Always true.</returns>		public override bool CanReuseTransform		{			get			{				return true;			}		}		/// <summary>		/// Gets a value indicating whether multiple blocks can be transformed.		/// </summary>		/// <returns>true if multiple blocks can be transformed; otherwise, false.</returns>		public override bool CanTransformMultipleBlocks		{			get			{				return true;			}		}		/// <summary>		/// Initializes a new instance of the <see cref="SHA1Hash"/> class.		/// </summary>		public SHA1Hash()		{			this._buffer = new byte[4];			this.Initialize();		}		/// <summary>		/// Routes data written to the object into the hash algorithm for computing the hash.		/// </summary>		/// <param name="array">The input to compute the hash code for.</param>		/// <param name="ibStart">The offset into the byte array from which to begin using data.</param>		/// <param name="cbSize">The number of bytes in the byte array to use as data.</param>		protected override void HashCore(byte[] array, int ibStart, int cbSize)		{			//  Fill the current word			while ((this._bufferOffset != 0) && (cbSize > 0))			{				this.Update(array[ibStart]);				ibStart++;				cbSize--;			}			//  Process whole words.			while (cbSize > this._buffer.Length)			{				this.ProcessWord(array, ibStart);				ibStart += this._buffer.Length;				cbSize -= this._buffer.Length;				this._byteCount += this._buffer.Length;			}			//  Load in the remainder.			while (cbSize > 0)			{				this.Update(array[ibStart]);				ibStart++;				cbSize--;			}		}		/// <summary>		/// Finalizes the hash computation after the last data is processed by the cryptographic stream object.		/// </summary>		/// <returns>		/// The computed hash code.		/// </returns>		protected override byte[] HashFinal()		{			var output = new byte[DIGEST_SIZE];			long bitLength = (this._byteCount << 3);			//			// add the pad bytes.			//			this.Update((byte)128);			while (this._bufferOffset != 0) 				this.Update((byte)0);			if (this._offset > 14)			{				this.ProcessBlock();			}			_hashValue[14] = (uint)((ulong)bitLength >> 32);			_hashValue[15] = (uint)((ulong)bitLength);			this.ProcessBlock();			UInt32_To__BE(H1, output, 0);			UInt32_To__BE(H2, output, 0 + 4);			UInt32_To__BE(H3, output, 0 + 8);			UInt32_To__BE(H4, output, 0 + 12);			UInt32_To__BE(H5, output, 0 + 16);            this.Initialize();			return output;		}		/// <summary>		/// Initializes an implementation of the <see cref="T:System.Security.Cryptography.HashAlgorithm"/> class.		/// </summary>		public override void Initialize()		{			this._byteCount = 0;			this._bufferOffset = 0;			Array.Clear(this._buffer, 0, this._buffer.Length);			H1 = 0x67452301;			H2 = 0xefcdab89;			H3 = 0x98badcfe;			H4 = 0x10325476;			H5 = 0xc3d2e1f0;			this._offset = 0;			Array.Clear(_hashValue, 0, _hashValue.Length);		}		private void Update(byte input)		{			this._buffer[this._bufferOffset++] = input;			if (this._bufferOffset == this._buffer.Length)			{				this.ProcessWord(this._buffer, 0);				this._bufferOffset = 0;			}			this._byteCount++;		}		private void ProcessWord(byte[] input, int inOff)		{			_hashValue[this._offset] = BE_To__UInt32(input, inOff);			if (++this._offset == 16)			{				this.ProcessBlock();			}		}		private static uint F(uint u, uint v, uint w)		{			return (u & v) | (~u & w);		}		private static uint H(uint u, uint v, uint w)		{			return u ^ v ^ w;		}		private static uint G(uint u, uint v, uint w)		{			return (u & v) | (u & w) | (v & w);		}		private void ProcessBlock()		{			//			// expand 16 word block into 80 word block.			//			for (int i = 16; i < 80; i++)			{				uint t = _hashValue[i - 3] ^ _hashValue[i - 8] ^ _hashValue[i - 14] ^ _hashValue[i - 16];				_hashValue[i] = t << 1 | t >> 31;			}			//			// set up working variables.			//			uint A = H1;			uint B = H2;			uint C = H3;			uint D = H4;			uint E = H5;			//			// round 1			//			int idx = 0;			for (int j = 0; j < 4; j++)			{				// E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1				// B = rotateLeft(B, 30)				E += (A << 5 | (A >> 27)) + F(B, C, D) + _hashValue[idx++] + Y1;				B = B << 30 | (B >> 2);				D += (E << 5 | (E >> 27)) + F(A, B, C) + _hashValue[idx++] + Y1;				A = A << 30 | (A >> 2);				C += (D << 5 | (D >> 27)) + F(E, A, B) + _hashValue[idx++] + Y1;				E = E << 30 | (E >> 2);				B += (C << 5 | (C >> 27)) + F(D, E, A) + _hashValue[idx++] + Y1;				D = D << 30 | (D >> 2);				A += (B << 5 | (B >> 27)) + F(C, D, E) + _hashValue[idx++] + Y1;				C = C << 30 | (C >> 2);			}			//			// round 2			//			for (int j = 0; j < 4; j++)			{				// E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2				// B = rotateLeft(B, 30)				E += (A << 5 | (A >> 27)) + H(B, C, D) + _hashValue[idx++] + Y2;				B = B << 30 | (B >> 2);				D += (E << 5 | (E >> 27)) + H(A, B, C) + _hashValue[idx++] + Y2;				A = A << 30 | (A >> 2);				C += (D << 5 | (D >> 27)) + H(E, A, B) + _hashValue[idx++] + Y2;				E = E << 30 | (E >> 2);				B += (C << 5 | (C >> 27)) + H(D, E, A) + _hashValue[idx++] + Y2;				D = D << 30 | (D >> 2);				A += (B << 5 | (B >> 27)) + H(C, D, E) + _hashValue[idx++] + Y2;				C = C << 30 | (C >> 2);			}			//			// round 3			//			for (int j = 0; j < 4; j++)			{				// E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3				// B = rotateLeft(B, 30)				E += (A << 5 | (A >> 27)) + G(B, C, D) + _hashValue[idx++] + Y3;				B = B << 30 | (B >> 2);				D += (E << 5 | (E >> 27)) + G(A, B, C) + _hashValue[idx++] + Y3;				A = A << 30 | (A >> 2);				C += (D << 5 | (D >> 27)) + G(E, A, B) + _hashValue[idx++] + Y3;				E = E << 30 | (E >> 2);				B += (C << 5 | (C >> 27)) + G(D, E, A) + _hashValue[idx++] + Y3;				D = D << 30 | (D >> 2);				A += (B << 5 | (B >> 27)) + G(C, D, E) + _hashValue[idx++] + Y3;				C = C << 30 | (C >> 2);			}			//			// round 4			//			for (int j = 0; j < 4; j++)			{				// E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y4				// B = rotateLeft(B, 30)				E += (A << 5 | (A >> 27)) + H(B, C, D) + _hashValue[idx++] + Y4;				B = B << 30 | (B >> 2);				D += (E << 5 | (E >> 27)) + H(A, B, C) + _hashValue[idx++] + Y4;				A = A << 30 | (A >> 2);				C += (D << 5 | (D >> 27)) + H(E, A, B) + _hashValue[idx++] + Y4;				E = E << 30 | (E >> 2);				B += (C << 5 | (C >> 27)) + H(D, E, A) + _hashValue[idx++] + Y4;				D = D << 30 | (D >> 2);				A += (B << 5 | (B >> 27)) + H(C, D, E) + _hashValue[idx++] + Y4;				C = C << 30 | (C >> 2);			}			H1 += A;			H2 += B;			H3 += C;			H4 += D;			H5 += E;			//			// reset start of the buffer.			//			this._offset = 0;			Array.Clear(_hashValue, 0, 16);		}		private static uint BE_To__UInt32(byte[] bs, int off)		{			uint n = (uint)bs[off] << 24;			n |= (uint)bs[++off] << 16;			n |= (uint)bs[++off] << 8;			n |= (uint)bs[++off];			return n;		}		private static void UInt32_To__BE			(uint n, byte[] bs, int off)		{			bs[off] = (byte)(n >> 24);			bs[++off] = (byte)(n >> 16);			bs[++off] = (byte)(n >> 8);			bs[++off] = (byte)(n);		}	}}
 |