<PackageReference Include="SshNet.Security.Cryptography" Version="1.3.0" />

SHA256HashProvider

namespace SshNet.Security.Cryptography { internal class SHA256HashProvider : HashProviderBase { private const int DigestSize = 32; private uint _h1; private uint _h2; private uint _h3; private uint _h4; private uint _h5; private uint _h6; private uint _h7; private uint _h8; private readonly uint[] _x; private int _offset; private readonly byte[] _buffer; private int _bufferOffset; private long _byteCount; private static readonly uint[] K = new uint[64] { 1116352408, 1899447441, 3049323471, 3921009573, 961987163, 1508970993, 2453635748, 2870763221, 3624381080, 310598401, 607225278, 1426881987, 1925078388, 2162078206, 2614888103, 3248222580, 3835390401, 4022224774, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, 2554220882, 2821834349, 2952996808, 3210313671, 3336571891, 3584528711, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, 2177026350, 2456956037, 2730485921, 2820302411, 3259730800, 3345764771, 3516065817, 3600352804, 4094571909, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, 2227730452, 2361852424, 2428436474, 2756734187, 3204031479, 3329325298 }; public override int HashSize => 256; public override int InputBlockSize => 64; public override int OutputBlockSize => 64; public SHA256HashProvider() { _buffer = new byte[4]; _x = new uint[64]; InitializeHashValue(); } public override void HashCore(byte[] array, int ibStart, int cbSize) { while (_bufferOffset != 0 && cbSize > 0) { Update(array[ibStart]); ibStart++; cbSize--; } while (cbSize > _buffer.Length) { ProcessWord(array, ibStart); ibStart += _buffer.Length; cbSize -= _buffer.Length; _byteCount += _buffer.Length; } while (cbSize > 0) { Update(array[ibStart]); ibStart++; cbSize--; } } public override byte[] HashFinal() { byte[] array = new byte[32]; long num = _byteCount << 3; Update(128); while (_bufferOffset != 0) { Update(0); } if (_offset > 14) ProcessBlock(); _x[14] = (uint)((ulong)num >> 32); _x[15] = (uint)num; ProcessBlock(); UInt32_To_BE(_h1, array, 0); UInt32_To_BE(_h2, array, 4); UInt32_To_BE(_h3, array, 8); UInt32_To_BE(_h4, array, 12); UInt32_To_BE(_h5, array, 16); UInt32_To_BE(_h6, array, 20); UInt32_To_BE(_h7, array, 24); UInt32_To_BE(_h8, array, 28); return array; } public override void Reset() { InitializeHashValue(); _byteCount = 0; _bufferOffset = 0; for (int i = 0; i < _buffer.Length; i++) { _buffer[i] = 0; } _offset = 0; for (int j = 0; j < _x.Length; j++) { _x[j] = 0; } } private void InitializeHashValue() { _h1 = 1779033703; _h2 = 3144134277; _h3 = 1013904242; _h4 = 2773480762; _h5 = 1359893119; _h6 = 2600822924; _h7 = 528734635; _h8 = 1541459225; } private void Update(byte input) { _buffer[_bufferOffset++] = input; if (_bufferOffset == _buffer.Length) { ProcessWord(_buffer, 0); _bufferOffset = 0; } _byteCount++; } private static uint BE_To_UInt32(byte[] bs, int off) { return (uint)((bs[off] << 24) | (bs[++off] << 16) | (bs[++off] << 8) | bs[++off]); } 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; } private void ProcessWord(byte[] input, int inOff) { _x[_offset] = BE_To_UInt32(input, inOff); if (++_offset == 16) ProcessBlock(); } private void ProcessBlock() { for (int i = 16; i <= 63; i++) { _x[i] = Theta1(_x[i - 2]) + _x[i - 7] + Theta0(_x[i - 15]) + _x[i - 16]; } uint num = _h1; uint num2 = _h2; uint num3 = _h3; uint num4 = _h4; uint num5 = _h5; uint num6 = _h6; uint num7 = _h7; uint num8 = _h8; int num9 = 0; for (int j = 0; j < 8; j++) { num8 += Sum1Ch(num5, num6, num7) + K[num9] + _x[num9]; num4 += num8; num8 += Sum0Maj(num, num2, num3); num9++; num7 += Sum1Ch(num4, num5, num6) + K[num9] + _x[num9]; num3 += num7; num7 += Sum0Maj(num8, num, num2); num9++; num6 += Sum1Ch(num3, num4, num5) + K[num9] + _x[num9]; num2 += num6; num6 += Sum0Maj(num7, num8, num); num9++; num5 += Sum1Ch(num2, num3, num4) + K[num9] + _x[num9]; num += num5; num5 += Sum0Maj(num6, num7, num8); num9++; num4 += Sum1Ch(num, num2, num3) + K[num9] + _x[num9]; num8 += num4; num4 += Sum0Maj(num5, num6, num7); num9++; num3 += Sum1Ch(num8, num, num2) + K[num9] + _x[num9]; num7 += num3; num3 += Sum0Maj(num4, num5, num6); num9++; num2 += Sum1Ch(num7, num8, num) + K[num9] + _x[num9]; num6 += num2; num2 += Sum0Maj(num3, num4, num5); num9++; num += Sum1Ch(num6, num7, num8) + K[num9] + _x[num9]; num5 += num; num += Sum0Maj(num2, num3, num4); num9++; } _h1 += num; _h2 += num2; _h3 += num3; _h4 += num4; _h5 += num5; _h6 += num6; _h7 += num7; _h8 += num8; _offset = 0; for (int k = 0; k < _x.Length; k++) { _x[k] = 0; } } private static uint Sum1Ch(uint x, uint y, uint z) { return (((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7))) + ((x & y) ^ (~x & z)); } private static uint Sum0Maj(uint x, uint y, uint z) { return (((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10))) + ((x & y) ^ (x & z) ^ (y & z)); } private static uint Theta0(uint x) { return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3); } private static uint Theta1(uint x) { return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10); } } }