MD5HashProvider
namespace SshNet.Security.Cryptography
{
internal class MD5HashProvider : HashProviderBase
{
private readonly byte[] _buffer = new byte[4];
private int _bufferOffset;
private long _byteCount;
private int _h1;
private int _h2;
private int _h3;
private int _h4;
private readonly int[] _x = new int[16];
private int _offset;
private const int S11 = 7;
private const int S12 = 12;
private const int S13 = 17;
private const int S14 = 22;
private const int S21 = 5;
private const int S22 = 9;
private const int S23 = 14;
private const int S24 = 20;
private const int S31 = 4;
private const int S32 = 11;
private const int S33 = 16;
private const int S34 = 23;
private const int S41 = 6;
private const int S42 = 10;
private const int S43 = 15;
private const int S44 = 21;
public override int HashSize => 128;
public override int InputBlockSize => 64;
public override int OutputBlockSize => 64;
public MD5HashProvider()
{
InternalInitialize();
}
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()
{
long num = _byteCount << 3;
Update(128);
while (_bufferOffset != 0) {
Update(0);
}
if (_offset > 14)
ProcessBlock();
_x[14] = (int)(num & uint.MaxValue);
_x[15] = (int)((ulong)num >> 32);
ProcessBlock();
byte[] array = new byte[16];
UnpackWord(_h1, array, 0);
UnpackWord(_h2, array, 4);
UnpackWord(_h3, array, 8);
UnpackWord(_h4, array, 12);
Initialize();
return array;
}
public override void Initialize()
{
InternalInitialize();
}
private void InternalInitialize()
{
_byteCount = 0;
_bufferOffset = 0;
for (int i = 0; i < 4; i++) {
_buffer[i] = 0;
}
_h1 = 1732584193;
_h2 = -271733879;
_h3 = -1732584194;
_h4 = 271733878;
_offset = 0;
for (int j = 0; j != _x.Length; j++) {
_x[j] = 0;
}
}
private void Update(byte input)
{
_buffer[_bufferOffset++] = input;
if (_bufferOffset == _buffer.Length) {
ProcessWord(_buffer, 0);
_bufferOffset = 0;
}
_byteCount++;
}
private void ProcessWord(byte[] input, int inOff)
{
_x[_offset++] = ((input[inOff] & 255) | ((input[inOff + 1] & 255) << 8) | ((input[inOff + 2] & 255) << 16) | ((input[inOff + 3] & 255) << 24));
if (_offset == 16)
ProcessBlock();
}
private static void UnpackWord(int word, byte[] outBytes, int outOff)
{
outBytes[outOff] = (byte)word;
outBytes[outOff + 1] = (byte)((uint)word >> 8);
outBytes[outOff + 2] = (byte)((uint)word >> 16);
outBytes[outOff + 3] = (byte)((uint)word >> 24);
}
private static int RotateLeft(int x, int n)
{
return (x << n) | (int)((uint)x >> 32 - n);
}
private static int F(int u, int v, int w)
{
return (u & v) | (~u & w);
}
private static int G(int u, int v, int w)
{
return (u & w) | (v & ~w);
}
private static int H(int u, int v, int w)
{
return u ^ v ^ w;
}
private static int K(int u, int v, int w)
{
return v ^ (u | ~w);
}
private void ProcessBlock()
{
int h = _h1;
int h2 = _h2;
int h3 = _h3;
int h4 = _h4;
h = RotateLeft(h + F(h2, h3, h4) + _x[0] + -680876936, 7) + h2;
h4 = RotateLeft(h4 + F(h, h2, h3) + _x[1] + -389564586, 12) + h;
h3 = RotateLeft(h3 + F(h4, h, h2) + _x[2] + 606105819, 17) + h4;
h2 = RotateLeft(h2 + F(h3, h4, h) + _x[3] + -1044525330, 22) + h3;
h = RotateLeft(h + F(h2, h3, h4) + _x[4] + -176418897, 7) + h2;
h4 = RotateLeft(h4 + F(h, h2, h3) + _x[5] + 1200080426, 12) + h;
h3 = RotateLeft(h3 + F(h4, h, h2) + _x[6] + -1473231341, 17) + h4;
h2 = RotateLeft(h2 + F(h3, h4, h) + _x[7] + -45705983, 22) + h3;
h = RotateLeft(h + F(h2, h3, h4) + _x[8] + 1770035416, 7) + h2;
h4 = RotateLeft(h4 + F(h, h2, h3) + _x[9] + -1958414417, 12) + h;
h3 = RotateLeft(h3 + F(h4, h, h2) + _x[10] + -42063, 17) + h4;
h2 = RotateLeft(h2 + F(h3, h4, h) + _x[11] + -1990404162, 22) + h3;
h = RotateLeft(h + F(h2, h3, h4) + _x[12] + 1804603682, 7) + h2;
h4 = RotateLeft(h4 + F(h, h2, h3) + _x[13] + -40341101, 12) + h;
h3 = RotateLeft(h3 + F(h4, h, h2) + _x[14] + -1502002290, 17) + h4;
h2 = RotateLeft(h2 + F(h3, h4, h) + _x[15] + 1236535329, 22) + h3;
h = RotateLeft(h + G(h2, h3, h4) + _x[1] + -165796510, 5) + h2;
h4 = RotateLeft(h4 + G(h, h2, h3) + _x[6] + -1069501632, 9) + h;
h3 = RotateLeft(h3 + G(h4, h, h2) + _x[11] + 643717713, 14) + h4;
h2 = RotateLeft(h2 + G(h3, h4, h) + _x[0] + -373897302, 20) + h3;
h = RotateLeft(h + G(h2, h3, h4) + _x[5] + -701558691, 5) + h2;
h4 = RotateLeft(h4 + G(h, h2, h3) + _x[10] + 38016083, 9) + h;
h3 = RotateLeft(h3 + G(h4, h, h2) + _x[15] + -660478335, 14) + h4;
h2 = RotateLeft(h2 + G(h3, h4, h) + _x[4] + -405537848, 20) + h3;
h = RotateLeft(h + G(h2, h3, h4) + _x[9] + 568446438, 5) + h2;
h4 = RotateLeft(h4 + G(h, h2, h3) + _x[14] + -1019803690, 9) + h;
h3 = RotateLeft(h3 + G(h4, h, h2) + _x[3] + -187363961, 14) + h4;
h2 = RotateLeft(h2 + G(h3, h4, h) + _x[8] + 1163531501, 20) + h3;
h = RotateLeft(h + G(h2, h3, h4) + _x[13] + -1444681467, 5) + h2;
h4 = RotateLeft(h4 + G(h, h2, h3) + _x[2] + -51403784, 9) + h;
h3 = RotateLeft(h3 + G(h4, h, h2) + _x[7] + 1735328473, 14) + h4;
h2 = RotateLeft(h2 + G(h3, h4, h) + _x[12] + -1926607734, 20) + h3;
h = RotateLeft(h + H(h2, h3, h4) + _x[5] + -378558, 4) + h2;
h4 = RotateLeft(h4 + H(h, h2, h3) + _x[8] + -2022574463, 11) + h;
h3 = RotateLeft(h3 + H(h4, h, h2) + _x[11] + 1839030562, 16) + h4;
h2 = RotateLeft(h2 + H(h3, h4, h) + _x[14] + -35309556, 23) + h3;
h = RotateLeft(h + H(h2, h3, h4) + _x[1] + -1530992060, 4) + h2;
h4 = RotateLeft(h4 + H(h, h2, h3) + _x[4] + 1272893353, 11) + h;
h3 = RotateLeft(h3 + H(h4, h, h2) + _x[7] + -155497632, 16) + h4;
h2 = RotateLeft(h2 + H(h3, h4, h) + _x[10] + -1094730640, 23) + h3;
h = RotateLeft(h + H(h2, h3, h4) + _x[13] + 681279174, 4) + h2;
h4 = RotateLeft(h4 + H(h, h2, h3) + _x[0] + -358537222, 11) + h;
h3 = RotateLeft(h3 + H(h4, h, h2) + _x[3] + -722521979, 16) + h4;
h2 = RotateLeft(h2 + H(h3, h4, h) + _x[6] + 76029189, 23) + h3;
h = RotateLeft(h + H(h2, h3, h4) + _x[9] + -640364487, 4) + h2;
h4 = RotateLeft(h4 + H(h, h2, h3) + _x[12] + -421815835, 11) + h;
h3 = RotateLeft(h3 + H(h4, h, h2) + _x[15] + 530742520, 16) + h4;
h2 = RotateLeft(h2 + H(h3, h4, h) + _x[2] + -995338651, 23) + h3;
h = RotateLeft(h + K(h2, h3, h4) + _x[0] + -198630844, 6) + h2;
h4 = RotateLeft(h4 + K(h, h2, h3) + _x[7] + 1126891415, 10) + h;
h3 = RotateLeft(h3 + K(h4, h, h2) + _x[14] + -1416354905, 15) + h4;
h2 = RotateLeft(h2 + K(h3, h4, h) + _x[5] + -57434055, 21) + h3;
h = RotateLeft(h + K(h2, h3, h4) + _x[12] + 1700485571, 6) + h2;
h4 = RotateLeft(h4 + K(h, h2, h3) + _x[3] + -1894986606, 10) + h;
h3 = RotateLeft(h3 + K(h4, h, h2) + _x[10] + -1051523, 15) + h4;
h2 = RotateLeft(h2 + K(h3, h4, h) + _x[1] + -2054922799, 21) + h3;
h = RotateLeft(h + K(h2, h3, h4) + _x[8] + 1873313359, 6) + h2;
h4 = RotateLeft(h4 + K(h, h2, h3) + _x[15] + -30611744, 10) + h;
h3 = RotateLeft(h3 + K(h4, h, h2) + _x[6] + -1560198380, 15) + h4;
h2 = RotateLeft(h2 + K(h3, h4, h) + _x[13] + 1309151649, 21) + h3;
h = RotateLeft(h + K(h2, h3, h4) + _x[4] + -145523070, 6) + h2;
h4 = RotateLeft(h4 + K(h, h2, h3) + _x[11] + -1120210379, 10) + h;
h3 = RotateLeft(h3 + K(h4, h, h2) + _x[2] + 718787259, 15) + h4;
h2 = RotateLeft(h2 + K(h3, h4, h) + _x[9] + -343485551, 21) + h3;
_h1 += h;
_h2 += h2;
_h3 += h3;
_h4 += h4;
_offset = 0;
for (int i = 0; i != _x.Length; i++) {
_x[i] = 0;
}
}
}
}