SHA2HashProviderBase
namespace SshNet.Security.Cryptography
{
internal abstract class SHA2HashProviderBase : HashProviderBase
{
protected ulong H1;
protected ulong H2;
protected ulong H3;
protected ulong H4;
protected ulong H5;
protected ulong H6;
protected ulong H7;
protected ulong H8;
private readonly ulong[] _x;
private int _offset;
private readonly byte[] _buffer;
private int _bufferOffset;
private long _byteCount1;
private long _byteCount2;
private static readonly ulong[] K = new ulong[80] {
4794697086780616226,
8158064640168781261,
13096744586834688815,
16840607885511220156,
4131703408338449720,
6480981068601479193,
10538285296894168987,
12329834152419229976,
15566598209576043074,
1334009975649890238,
2608012711638119052,
6128411473006802146,
8268148722764581231,
9286055187155687089,
11230858885718282805,
13951009754708518548,
16472876342353939154,
17275323862435702243,
1135362057144423861,
2597628984639134821,
3308224258029322869,
5365058923640841347,
6679025012923562964,
8573033837759648693,
10970295158949994411,
12119686244451234320,
12683024718118986047,
13788192230050041572,
14330467153632333762,
15395433587784984357,
489312712824947311,
1452737877330783856,
2861767655752347644,
3322285676063803686,
5560940570517711597,
5996557281743188959,
7280758554555802590,
8532644243296465576,
9350256976987008742,
10552545826968843579,
11727347734174303076,
12113106623233404929,
14000437183269869457,
14369950271660146224,
15101387698204529176,
15463397548674623760,
17586052441742319658,
1182934255886127544,
1847814050463011016,
2177327727835720531,
2830643537854262169,
3796741975233480872,
4115178125766777443,
5681478168544905931,
6601373596472566643,
7507060721942968483,
8399075790359081724,
8693463985226723168,
9568029438360202098,
10144078919501101548,
10430055236837252648,
11840083180663258601,
13761210420658862357,
14299343276471374635,
14566680578165727644,
15097957966210449927,
16922976911328602910,
17689382322260857208,
500013540394364858,
748580250866718886,
1242879168328830382,
1977374033974150939,
2944078676154940804,
3659926193048069267,
4368137639120453308,
4836135668995329356,
5532061633213252278,
6448918945643986474,
6902733635092675308,
7801388544844847127
};
protected SHA2HashProviderBase()
{
_x = new ulong[80];
_buffer = new byte[8];
}
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;
_byteCount1 += _buffer.Length;
}
while (cbSize > 0) {
Update(array[ibStart]);
ibStart++;
cbSize--;
}
}
public override void Reset()
{
_byteCount1 = 0;
_byteCount2 = 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;
}
}
protected void Finish()
{
AdjustByteCounts();
long lowW = _byteCount1 << 3;
long byteCount = _byteCount2;
Update(128);
while (_bufferOffset != 0) {
Update(0);
}
ProcessLength(lowW, byteCount);
ProcessBlock();
}
private void Update(byte input)
{
_buffer[_bufferOffset++] = input;
if (_bufferOffset == _buffer.Length) {
ProcessWord(_buffer, 0);
_bufferOffset = 0;
}
_byteCount1++;
}
private void ProcessWord(byte[] input, int inOff)
{
_x[_offset] = BE_To_UInt64(input, inOff);
if (++_offset == 16)
ProcessBlock();
}
internal void ProcessLength(long lowW, long hiW)
{
if (_offset > 14)
ProcessBlock();
_x[14] = (ulong)hiW;
_x[15] = (ulong)lowW;
}
private void ProcessBlock()
{
AdjustByteCounts();
for (int i = 16; i <= 79; i++) {
_x[i] = Sigma1(_x[i - 2]) + _x[i - 7] + Sigma0(_x[i - 15]) + _x[i - 16];
}
ulong num = H1;
ulong num2 = H2;
ulong num3 = H3;
ulong num4 = H4;
ulong num5 = H5;
ulong num6 = H6;
ulong num7 = H7;
ulong num8 = H8;
int num9 = 0;
for (int j = 0; j < 10; j++) {
num8 += Sum1(num5) + Ch(num5, num6, num7) + K[num9] + _x[num9++];
num4 += num8;
num8 += Sum0(num) + Maj(num, num2, num3);
num7 += Sum1(num4) + Ch(num4, num5, num6) + K[num9] + _x[num9++];
num3 += num7;
num7 += Sum0(num8) + Maj(num8, num, num2);
num6 += Sum1(num3) + Ch(num3, num4, num5) + K[num9] + _x[num9++];
num2 += num6;
num6 += Sum0(num7) + Maj(num7, num8, num);
num5 += Sum1(num2) + Ch(num2, num3, num4) + K[num9] + _x[num9++];
num += num5;
num5 += Sum0(num6) + Maj(num6, num7, num8);
num4 += Sum1(num) + Ch(num, num2, num3) + K[num9] + _x[num9++];
num8 += num4;
num4 += Sum0(num5) + Maj(num5, num6, num7);
num3 += Sum1(num8) + Ch(num8, num, num2) + K[num9] + _x[num9++];
num7 += num3;
num3 += Sum0(num4) + Maj(num4, num5, num6);
num2 += Sum1(num7) + Ch(num7, num8, num) + K[num9] + _x[num9++];
num6 += num2;
num2 += Sum0(num3) + Maj(num3, num4, num5);
num += Sum1(num6) + Ch(num6, num7, num8) + K[num9] + _x[num9++];
num5 += num;
num += Sum0(num2) + Maj(num2, num3, num4);
}
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 void AdjustByteCounts()
{
if (_byteCount1 > 2305843009213693951) {
_byteCount2 += (long)((ulong)_byteCount1 >> 61);
_byteCount1 &= 2305843009213693951;
}
}
private static ulong Ch(ulong x, ulong y, ulong z)
{
return (x & y) ^ (~x & z);
}
private static ulong Maj(ulong x, ulong y, ulong z)
{
return (x & y) ^ (x & z) ^ (y & z);
}
private static ulong Sum0(ulong x)
{
return ((x << 36) | (x >> 28)) ^ ((x << 30) | (x >> 34)) ^ ((x << 25) | (x >> 39));
}
private static ulong Sum1(ulong x)
{
return ((x << 50) | (x >> 14)) ^ ((x << 46) | (x >> 18)) ^ ((x << 23) | (x >> 41));
}
private static ulong Sigma0(ulong x)
{
return ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7);
}
private static ulong Sigma1(ulong x)
{
return ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6);
}
private static void UInt32_To_BE(uint n, byte[] bs, int offset)
{
bs[offset] = (byte)(n >> 24);
bs[++offset] = (byte)(n >> 16);
bs[++offset] = (byte)(n >> 8);
bs[++offset] = (byte)n;
}
protected static void UInt64_To_BE(ulong n, byte[] bs, int offset)
{
UInt32_To_BE((uint)(n >> 32), bs, offset);
UInt32_To_BE((uint)n, bs, offset + 4);
}
private static ulong BE_To_UInt64(byte[] bs, int offset)
{
uint num = BE_To_UInt32(bs, offset);
uint num2 = BE_To_UInt32(bs, offset + 4);
return ((ulong)num << 32) | num2;
}
private static uint BE_To_UInt32(byte[] bs, int offset)
{
return (uint)((bs[offset] << 24) | (bs[++offset] << 16) | (bs[++offset] << 8) | bs[++offset]);
}
}
}