From 3fae34d74c96cf0b91a8151a7d2a5d4a2cd7f540 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 26 Nov 2021 13:29:35 +0300 Subject: [PATCH 01/40] Port MD4 managed implementation from mono/mono --- .../src/System.Security.Cryptography.csproj | 1 + .../src/System/Security/Cryptography/MD4.cs | 273 ++++++++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD4.cs diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index 9a268d9a83d9a0..d305d7b85c9539 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -279,6 +279,7 @@ + diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD4.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD4.cs new file mode 100644 index 00000000000000..f341e289adddde --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD4.cs @@ -0,0 +1,273 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Internal.Cryptography; + +namespace System.Security.Cryptography +{ + internal abstract class MD4 : HashAlgorithm + { + private const int HashSizeBits = 128; + protected MD4() + { + HashSizeValue = HashSizeBits; + } + + public static new MD4 Create() => new Implementation(); + + [RequiresUnreferencedCode(CryptoConfig.CreateFromNameUnreferencedCodeMessage)] + public static new MD4? Create(string algName) => (MD4?)CryptoConfig.CreateFromName(algName); + + private sealed class Implementation : MD4 + { + private uint[] state; + private byte[] buffer; + private uint[] count; + private uint[] x; + + private const int S11 = 3; + private const int S12 = 7; + private const int S13 = 11; + private const int S14 = 19; + private const int S21 = 3; + private const int S22 = 5; + private const int S23 = 9; + private const int S24 = 13; + private const int S31 = 3; + private const int S32 = 9; + private const int S33 = 11; + private const int S34 = 15; + + private byte[] digest; + + public Implementation() + { + // we allocate the context memory + state = new uint[4]; + count = new uint[2]; + buffer = new byte[64]; + digest = new byte[16]; + // temporary buffer in MD4Transform that we don't want to keep allocate on each iteration + x = new uint[16]; + // the initialize our context + Initialize(); + } + + public sealed override void Initialize() + { + count[0] = 0; + count[1] = 0; + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + // Zeroize sensitive information + Array.Clear(buffer, 0, 64); + Array.Clear(x, 0, 16); + } + + protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) + { + /* Compute number of bytes mod 64 */ + int index = (int)((count[0] >> 3) & 0x3F); + /* Update number of bits */ + count[0] += (uint)(cbSize << 3); + if (count[0] < (cbSize << 3)) + count[1]++; + count[1] += (uint)(cbSize >> 29); + + int partLen = 64 - index; + int i = 0; + /* Transform as many times as possible. */ + if (cbSize >= partLen) + { + Buffer.BlockCopy(array, ibStart, buffer, index, partLen); + MD4Transform(state, buffer, 0); + + for (i = partLen; i + 63 < cbSize; i += 64) + { + MD4Transform(state, array, ibStart + i); + } + + index = 0; + } + + /* Buffer remaining input */ + Buffer.BlockCopy(array, ibStart + i, buffer, index, (cbSize-i)); + } + + protected sealed override void HashCore(ReadOnlySpan source) => throw new NotImplementedException(); + + protected sealed override byte[] HashFinal() + { + /* Save number of bits */ + byte[] bits = new byte[8]; + Encode(bits, count); + + /* Pad out to 56 mod 64. */ + uint index = ((count [0] >> 3) & 0x3f); + int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); + HashCore(Padding(padLen), 0, padLen); + + /* Append length (before padding) */ + HashCore(bits, 0, 8); + + /* Store state in digest */ + Encode(digest, state); + + // Zeroize sensitive information. + Initialize(); + + return digest; + } + + protected sealed override bool TryHashFinal(Span destination, out int bytesWritten) => throw new NotImplementedException(); + + + protected sealed override void Dispose(bool disposing) + { + base.Dispose(disposing); + } + + //--- private methods --------------------------------------------------- + + private byte[] Padding(int nLength) + { + byte[] padding = new byte[nLength]; + padding[0] = 0x80; + return padding; + } + + /* F, G and H are basic MD4 functions. */ + private uint F(uint x, uint y, uint z) + { + return (uint)(((x) & (y)) | ((~x) & (z))); + } + + private uint G(uint x, uint y, uint z) + { + return (uint)(((x) & (y)) | ((x) & (z)) | ((y) & (z))); + } + + private uint H(uint x, uint y, uint z) + { + return (uint)((x) ^ (y) ^ (z)); + } + + /* ROTATE_LEFT rotates x left n bits. */ + private uint ROL(uint x, byte n) + { + return (uint)(((x) << (n)) | ((x) >> (32-(n)))); + } + + /* FF, GG and HH are transformations for rounds 1, 2 and 3 */ + /* Rotation is separate from addition to prevent recomputation */ + private void FF(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += F(b, c, d) + x; + a = ROL(a, s); + } + + private void GG(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += G(b, c, d) + x + 0x5a827999; + a = ROL(a, s); + } + + private void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += H(b, c, d) + x + 0x6ed9eba1; + a = ROL(a, s); + } + + private void Encode(byte[] output, uint[] input) + { + for (int i = 0, j = 0; j < output.Length; i++, j += 4) + { + output[j] = (byte)(input[i]); + output[j+1] = (byte)(input[i] >> 8); + output[j+2] = (byte)(input[i] >> 16); + output[j+3] = (byte)(input[i] >> 24); + } + } + + private void Decode(uint[] output, byte[] input, int index) + { + for (int i = 0, j = index; i < output.Length; i++, j += 4) + { + output [i] = (uint)((input [j]) | (input[j+1] << 8) | (input[j+2] << 16) | (input[j+3] << 24)); + } + } + + private void MD4Transform(uint[] state, byte[] block, int index) + { + uint a = state[0]; + uint b = state[1]; + uint c = state[2]; + uint d = state[3]; + + Decode(x, block, index); + + /* Round 1 */ + FF(ref a, b, c, d, x[ 0], S11); /* 1 */ + FF(ref d, a, b, c, x[ 1], S12); /* 2 */ + FF(ref c, d, a, b, x[ 2], S13); /* 3 */ + FF(ref b, c, d, a, x[ 3], S14); /* 4 */ + FF(ref a, b, c, d, x[ 4], S11); /* 5 */ + FF(ref d, a, b, c, x[ 5], S12); /* 6 */ + FF(ref c, d, a, b, x[ 6], S13); /* 7 */ + FF(ref b, c, d, a, x[ 7], S14); /* 8 */ + FF(ref a, b, c, d, x[ 8], S11); /* 9 */ + FF(ref d, a, b, c, x[ 9], S12); /* 10 */ + FF(ref c, d, a, b, x[10], S13); /* 11 */ + FF(ref b, c, d, a, x[11], S14); /* 12 */ + FF(ref a, b, c, d, x[12], S11); /* 13 */ + FF(ref d, a, b, c, x[13], S12); /* 14 */ + FF(ref c, d, a, b, x[14], S13); /* 15 */ + FF(ref b, c, d, a, x[15], S14); /* 16 */ + + /* Round 2 */ + GG(ref a, b, c, d, x[ 0], S21); /* 17 */ + GG(ref d, a, b, c, x[ 4], S22); /* 18 */ + GG(ref c, d, a, b, x[ 8], S23); /* 19 */ + GG(ref b, c, d, a, x[12], S24); /* 20 */ + GG(ref a, b, c, d, x[ 1], S21); /* 21 */ + GG(ref d, a, b, c, x[ 5], S22); /* 22 */ + GG(ref c, d, a, b, x[ 9], S23); /* 23 */ + GG(ref b, c, d, a, x[13], S24); /* 24 */ + GG(ref a, b, c, d, x[ 2], S21); /* 25 */ + GG(ref d, a, b, c, x[ 6], S22); /* 26 */ + GG(ref c, d, a, b, x[10], S23); /* 27 */ + GG(ref b, c, d, a, x[14], S24); /* 28 */ + GG(ref a, b, c, d, x[ 3], S21); /* 29 */ + GG(ref d, a, b, c, x[ 7], S22); /* 30 */ + GG(ref c, d, a, b, x[11], S23); /* 31 */ + GG(ref b, c, d, a, x[15], S24); /* 32 */ + + HH(ref a, b, c, d, x[ 0], S31); /* 33 */ + HH(ref d, a, b, c, x[ 8], S32); /* 34 */ + HH(ref c, d, a, b, x[ 4], S33); /* 35 */ + HH(ref b, c, d, a, x[12], S34); /* 36 */ + HH(ref a, b, c, d, x[ 2], S31); /* 37 */ + HH(ref d, a, b, c, x[10], S32); /* 38 */ + HH(ref c, d, a, b, x[ 6], S33); /* 39 */ + HH(ref b, c, d, a, x[14], S34); /* 40 */ + HH(ref a, b, c, d, x[ 1], S31); /* 41 */ + HH(ref d, a, b, c, x[ 9], S32); /* 42 */ + HH(ref c, d, a, b, x[ 5], S33); /* 43 */ + HH(ref b, c, d, a, x[13], S34); /* 44 */ + HH(ref a, b, c, d, x[ 3], S31); /* 45 */ + HH(ref d, a, b, c, x[11], S32); /* 46 */ + HH(ref c, d, a, b, x[ 7], S33); /* 47 */ + HH(ref b, c, d, a, x[15], S34); /* 48 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + } + } + } +} From ae9cad695017c74355923bdc07909de0d27985af Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 6 Dec 2021 13:32:44 +0300 Subject: [PATCH 02/40] Move MD4 impl to System.Net.Security --- .../src/System.Net.Security.csproj | 1 + .../src/System/Net/Security/MD4.cs | 271 +++++++++++++++++ .../src/System.Security.Cryptography.csproj | 1 - .../src/System/Security/Cryptography/MD4.cs | 273 ------------------ 4 files changed, 272 insertions(+), 274 deletions(-) create mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs delete mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD4.cs diff --git a/src/libraries/System.Net.Security/src/System.Net.Security.csproj b/src/libraries/System.Net.Security/src/System.Net.Security.csproj index 9f90dbd3951f05..9d0b8da1fc0aa1 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -18,6 +18,7 @@ $(DefineConstants);SYSNETSECURITY_NO_OPENSSL + diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs new file mode 100644 index 00000000000000..f507213037f886 --- /dev/null +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -0,0 +1,271 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace System.Security.Cryptography +{ + internal sealed class MD4 + { + private const int HashSizeBits = 128; + private const int HashSizeBytes = HashSizeBits / 8; + private byte[]? HashValue; + private uint[] state; + private byte[] buffer; + private uint[] count; + private uint[] x; + + private const int S11 = 3; + private const int S12 = 7; + private const int S13 = 11; + private const int S14 = 19; + private const int S21 = 3; + private const int S22 = 5; + private const int S23 = 9; + private const int S24 = 13; + private const int S31 = 3; + private const int S32 = 9; + private const int S33 = 11; + private const int S34 = 15; + + private byte[] digest; + + public MD4() + { + // we allocate the context memory + state = new uint[4]; + count = new uint[2]; + buffer = new byte[64]; + digest = new byte[16]; + // temporary buffer in MD4Transform that we don't want to keep allocate on each iteration + x = new uint[16]; + // the initialize our context + Initialize(); + } + + public int HashData(ReadOnlySpan source, Span destination) + { + if (destination.Length < HashSizeBytes) + { + throw new ArgumentException("Destination is too short.", nameof(destination)); + } + + destination = ComputeHash(source.ToArray(), 0, source.Length); + return destination.Length; + } + + private void Initialize() + { + count[0] = 0; + count[1] = 0; + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + // Zeroize sensitive information + Array.Clear(buffer, 0, 64); + Array.Clear(x, 0, 16); + } + + private byte[] ComputeHash(byte[] buffer, int offset, int count) + { + HashCore(buffer, offset, count); + HashValue = HashFinal(); + byte[] result = (byte[]) HashValue.Clone(); + Initialize(); + return result; + } + + private void HashCore(byte[] array, int ibStart, int cbSize) + { + /* Compute number of bytes mod 64 */ + int index = (int)((count[0] >> 3) & 0x3F); + /* Update number of bits */ + count[0] += (uint)(cbSize << 3); + if (count[0] < (cbSize << 3)) + count[1]++; + count[1] += (uint)(cbSize >> 29); + + int partLen = 64 - index; + int i = 0; + /* Transform as many times as possible. */ + if (cbSize >= partLen) + { + Buffer.BlockCopy(array, ibStart, buffer, index, partLen); + MD4Transform(state, buffer, 0); + + for (i = partLen; i + 63 < cbSize; i += 64) + { + MD4Transform(state, array, ibStart + i); + } + + index = 0; + } + + /* Buffer remaining input */ + Buffer.BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); + } + + private byte[] HashFinal() + { + /* Save number of bits */ + byte[] bits = new byte[8]; + Encode(bits, count); + + /* Pad out to 56 mod 64. */ + uint index = ((count[0] >> 3) & 0x3f); + int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); + HashCore(Padding(padLen), 0, padLen); + + /* Append length (before padding) */ + HashCore(bits, 0, 8); + + /* Store state in digest */ + Encode(digest, state); + + // Zeroize sensitive information. + Initialize(); + + return digest; + } + + //--- private methods --------------------------------------------------- + + private byte[] Padding(int nLength) + { + byte[] padding = new byte[nLength]; + padding[0] = 0x80; + return padding; + } + + /* F, G and H are basic MD4 functions. */ + private uint F(uint x, uint y, uint z) + { + return (uint)(((x) & (y)) | ((~x) & (z))); + } + + private uint G(uint x, uint y, uint z) + { + return (uint)(((x) & (y)) | ((x) & (z)) | ((y) & (z))); + } + + private uint H(uint x, uint y, uint z) + { + return (uint)((x) ^ (y) ^ (z)); + } + + /* ROTATE_LEFT rotates x left n bits. */ + private uint ROL(uint x, byte n) + { + return (uint)(((x) << (n)) | ((x) >> (32 - (n)))); + } + + /* FF, GG and HH are transformations for rounds 1, 2 and 3 */ + /* Rotation is separate from addition to prevent recomputation */ + private void FF(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += F(b, c, d) + x; + a = ROL(a, s); + } + + private void GG(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += G(b, c, d) + x + 0x5a827999; + a = ROL(a, s); + } + + private void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += H(b, c, d) + x + 0x6ed9eba1; + a = ROL(a, s); + } + + private void Encode(byte[] output, uint[] input) + { + for (int i = 0, j = 0; j < output.Length; i++, j += 4) + { + output[j] = (byte)(input[i]); + output[j + 1] = (byte)(input[i] >> 8); + output[j + 2] = (byte)(input[i] >> 16); + output[j + 3] = (byte)(input[i] >> 24); + } + } + + private void Decode(uint[] output, byte[] input, int index) + { + for (int i = 0, j = index; i < output.Length; i++, j += 4) + { + output[i] = (uint)((input[j]) | (input[j + 1] << 8) | (input[j + 2] << 16) | (input[j + 3] << 24)); + } + } + + private void MD4Transform(uint[] state, byte[] block, int index) + { + uint a = state[0]; + uint b = state[1]; + uint c = state[2]; + uint d = state[3]; + + Decode(x, block, index); + + /* Round 1 */ + FF(ref a, b, c, d, x[0], S11); /* 1 */ + FF(ref d, a, b, c, x[1], S12); /* 2 */ + FF(ref c, d, a, b, x[2], S13); /* 3 */ + FF(ref b, c, d, a, x[3], S14); /* 4 */ + FF(ref a, b, c, d, x[4], S11); /* 5 */ + FF(ref d, a, b, c, x[5], S12); /* 6 */ + FF(ref c, d, a, b, x[6], S13); /* 7 */ + FF(ref b, c, d, a, x[7], S14); /* 8 */ + FF(ref a, b, c, d, x[8], S11); /* 9 */ + FF(ref d, a, b, c, x[9], S12); /* 10 */ + FF(ref c, d, a, b, x[10], S13); /* 11 */ + FF(ref b, c, d, a, x[11], S14); /* 12 */ + FF(ref a, b, c, d, x[12], S11); /* 13 */ + FF(ref d, a, b, c, x[13], S12); /* 14 */ + FF(ref c, d, a, b, x[14], S13); /* 15 */ + FF(ref b, c, d, a, x[15], S14); /* 16 */ + + /* Round 2 */ + GG(ref a, b, c, d, x[0], S21); /* 17 */ + GG(ref d, a, b, c, x[4], S22); /* 18 */ + GG(ref c, d, a, b, x[8], S23); /* 19 */ + GG(ref b, c, d, a, x[12], S24); /* 20 */ + GG(ref a, b, c, d, x[1], S21); /* 21 */ + GG(ref d, a, b, c, x[5], S22); /* 22 */ + GG(ref c, d, a, b, x[9], S23); /* 23 */ + GG(ref b, c, d, a, x[13], S24); /* 24 */ + GG(ref a, b, c, d, x[2], S21); /* 25 */ + GG(ref d, a, b, c, x[6], S22); /* 26 */ + GG(ref c, d, a, b, x[10], S23); /* 27 */ + GG(ref b, c, d, a, x[14], S24); /* 28 */ + GG(ref a, b, c, d, x[3], S21); /* 29 */ + GG(ref d, a, b, c, x[7], S22); /* 30 */ + GG(ref c, d, a, b, x[11], S23); /* 31 */ + GG(ref b, c, d, a, x[15], S24); /* 32 */ + + HH(ref a, b, c, d, x[0], S31); /* 33 */ + HH(ref d, a, b, c, x[8], S32); /* 34 */ + HH(ref c, d, a, b, x[4], S33); /* 35 */ + HH(ref b, c, d, a, x[12], S34); /* 36 */ + HH(ref a, b, c, d, x[2], S31); /* 37 */ + HH(ref d, a, b, c, x[10], S32); /* 38 */ + HH(ref c, d, a, b, x[6], S33); /* 39 */ + HH(ref b, c, d, a, x[14], S34); /* 40 */ + HH(ref a, b, c, d, x[1], S31); /* 41 */ + HH(ref d, a, b, c, x[9], S32); /* 42 */ + HH(ref c, d, a, b, x[5], S33); /* 43 */ + HH(ref b, c, d, a, x[13], S34); /* 44 */ + HH(ref a, b, c, d, x[3], S31); /* 45 */ + HH(ref d, a, b, c, x[11], S32); /* 46 */ + HH(ref c, d, a, b, x[7], S33); /* 47 */ + HH(ref b, c, d, a, x[15], S34); /* 48 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + } + } +} diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index d305d7b85c9539..9a268d9a83d9a0 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -279,7 +279,6 @@ - diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD4.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD4.cs deleted file mode 100644 index f341e289adddde..00000000000000 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD4.cs +++ /dev/null @@ -1,273 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using Internal.Cryptography; - -namespace System.Security.Cryptography -{ - internal abstract class MD4 : HashAlgorithm - { - private const int HashSizeBits = 128; - protected MD4() - { - HashSizeValue = HashSizeBits; - } - - public static new MD4 Create() => new Implementation(); - - [RequiresUnreferencedCode(CryptoConfig.CreateFromNameUnreferencedCodeMessage)] - public static new MD4? Create(string algName) => (MD4?)CryptoConfig.CreateFromName(algName); - - private sealed class Implementation : MD4 - { - private uint[] state; - private byte[] buffer; - private uint[] count; - private uint[] x; - - private const int S11 = 3; - private const int S12 = 7; - private const int S13 = 11; - private const int S14 = 19; - private const int S21 = 3; - private const int S22 = 5; - private const int S23 = 9; - private const int S24 = 13; - private const int S31 = 3; - private const int S32 = 9; - private const int S33 = 11; - private const int S34 = 15; - - private byte[] digest; - - public Implementation() - { - // we allocate the context memory - state = new uint[4]; - count = new uint[2]; - buffer = new byte[64]; - digest = new byte[16]; - // temporary buffer in MD4Transform that we don't want to keep allocate on each iteration - x = new uint[16]; - // the initialize our context - Initialize(); - } - - public sealed override void Initialize() - { - count[0] = 0; - count[1] = 0; - state[0] = 0x67452301; - state[1] = 0xefcdab89; - state[2] = 0x98badcfe; - state[3] = 0x10325476; - // Zeroize sensitive information - Array.Clear(buffer, 0, 64); - Array.Clear(x, 0, 16); - } - - protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) - { - /* Compute number of bytes mod 64 */ - int index = (int)((count[0] >> 3) & 0x3F); - /* Update number of bits */ - count[0] += (uint)(cbSize << 3); - if (count[0] < (cbSize << 3)) - count[1]++; - count[1] += (uint)(cbSize >> 29); - - int partLen = 64 - index; - int i = 0; - /* Transform as many times as possible. */ - if (cbSize >= partLen) - { - Buffer.BlockCopy(array, ibStart, buffer, index, partLen); - MD4Transform(state, buffer, 0); - - for (i = partLen; i + 63 < cbSize; i += 64) - { - MD4Transform(state, array, ibStart + i); - } - - index = 0; - } - - /* Buffer remaining input */ - Buffer.BlockCopy(array, ibStart + i, buffer, index, (cbSize-i)); - } - - protected sealed override void HashCore(ReadOnlySpan source) => throw new NotImplementedException(); - - protected sealed override byte[] HashFinal() - { - /* Save number of bits */ - byte[] bits = new byte[8]; - Encode(bits, count); - - /* Pad out to 56 mod 64. */ - uint index = ((count [0] >> 3) & 0x3f); - int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); - HashCore(Padding(padLen), 0, padLen); - - /* Append length (before padding) */ - HashCore(bits, 0, 8); - - /* Store state in digest */ - Encode(digest, state); - - // Zeroize sensitive information. - Initialize(); - - return digest; - } - - protected sealed override bool TryHashFinal(Span destination, out int bytesWritten) => throw new NotImplementedException(); - - - protected sealed override void Dispose(bool disposing) - { - base.Dispose(disposing); - } - - //--- private methods --------------------------------------------------- - - private byte[] Padding(int nLength) - { - byte[] padding = new byte[nLength]; - padding[0] = 0x80; - return padding; - } - - /* F, G and H are basic MD4 functions. */ - private uint F(uint x, uint y, uint z) - { - return (uint)(((x) & (y)) | ((~x) & (z))); - } - - private uint G(uint x, uint y, uint z) - { - return (uint)(((x) & (y)) | ((x) & (z)) | ((y) & (z))); - } - - private uint H(uint x, uint y, uint z) - { - return (uint)((x) ^ (y) ^ (z)); - } - - /* ROTATE_LEFT rotates x left n bits. */ - private uint ROL(uint x, byte n) - { - return (uint)(((x) << (n)) | ((x) >> (32-(n)))); - } - - /* FF, GG and HH are transformations for rounds 1, 2 and 3 */ - /* Rotation is separate from addition to prevent recomputation */ - private void FF(ref uint a, uint b, uint c, uint d, uint x, byte s) - { - a += F(b, c, d) + x; - a = ROL(a, s); - } - - private void GG(ref uint a, uint b, uint c, uint d, uint x, byte s) - { - a += G(b, c, d) + x + 0x5a827999; - a = ROL(a, s); - } - - private void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) - { - a += H(b, c, d) + x + 0x6ed9eba1; - a = ROL(a, s); - } - - private void Encode(byte[] output, uint[] input) - { - for (int i = 0, j = 0; j < output.Length; i++, j += 4) - { - output[j] = (byte)(input[i]); - output[j+1] = (byte)(input[i] >> 8); - output[j+2] = (byte)(input[i] >> 16); - output[j+3] = (byte)(input[i] >> 24); - } - } - - private void Decode(uint[] output, byte[] input, int index) - { - for (int i = 0, j = index; i < output.Length; i++, j += 4) - { - output [i] = (uint)((input [j]) | (input[j+1] << 8) | (input[j+2] << 16) | (input[j+3] << 24)); - } - } - - private void MD4Transform(uint[] state, byte[] block, int index) - { - uint a = state[0]; - uint b = state[1]; - uint c = state[2]; - uint d = state[3]; - - Decode(x, block, index); - - /* Round 1 */ - FF(ref a, b, c, d, x[ 0], S11); /* 1 */ - FF(ref d, a, b, c, x[ 1], S12); /* 2 */ - FF(ref c, d, a, b, x[ 2], S13); /* 3 */ - FF(ref b, c, d, a, x[ 3], S14); /* 4 */ - FF(ref a, b, c, d, x[ 4], S11); /* 5 */ - FF(ref d, a, b, c, x[ 5], S12); /* 6 */ - FF(ref c, d, a, b, x[ 6], S13); /* 7 */ - FF(ref b, c, d, a, x[ 7], S14); /* 8 */ - FF(ref a, b, c, d, x[ 8], S11); /* 9 */ - FF(ref d, a, b, c, x[ 9], S12); /* 10 */ - FF(ref c, d, a, b, x[10], S13); /* 11 */ - FF(ref b, c, d, a, x[11], S14); /* 12 */ - FF(ref a, b, c, d, x[12], S11); /* 13 */ - FF(ref d, a, b, c, x[13], S12); /* 14 */ - FF(ref c, d, a, b, x[14], S13); /* 15 */ - FF(ref b, c, d, a, x[15], S14); /* 16 */ - - /* Round 2 */ - GG(ref a, b, c, d, x[ 0], S21); /* 17 */ - GG(ref d, a, b, c, x[ 4], S22); /* 18 */ - GG(ref c, d, a, b, x[ 8], S23); /* 19 */ - GG(ref b, c, d, a, x[12], S24); /* 20 */ - GG(ref a, b, c, d, x[ 1], S21); /* 21 */ - GG(ref d, a, b, c, x[ 5], S22); /* 22 */ - GG(ref c, d, a, b, x[ 9], S23); /* 23 */ - GG(ref b, c, d, a, x[13], S24); /* 24 */ - GG(ref a, b, c, d, x[ 2], S21); /* 25 */ - GG(ref d, a, b, c, x[ 6], S22); /* 26 */ - GG(ref c, d, a, b, x[10], S23); /* 27 */ - GG(ref b, c, d, a, x[14], S24); /* 28 */ - GG(ref a, b, c, d, x[ 3], S21); /* 29 */ - GG(ref d, a, b, c, x[ 7], S22); /* 30 */ - GG(ref c, d, a, b, x[11], S23); /* 31 */ - GG(ref b, c, d, a, x[15], S24); /* 32 */ - - HH(ref a, b, c, d, x[ 0], S31); /* 33 */ - HH(ref d, a, b, c, x[ 8], S32); /* 34 */ - HH(ref c, d, a, b, x[ 4], S33); /* 35 */ - HH(ref b, c, d, a, x[12], S34); /* 36 */ - HH(ref a, b, c, d, x[ 2], S31); /* 37 */ - HH(ref d, a, b, c, x[10], S32); /* 38 */ - HH(ref c, d, a, b, x[ 6], S33); /* 39 */ - HH(ref b, c, d, a, x[14], S34); /* 40 */ - HH(ref a, b, c, d, x[ 1], S31); /* 41 */ - HH(ref d, a, b, c, x[ 9], S32); /* 42 */ - HH(ref c, d, a, b, x[ 5], S33); /* 43 */ - HH(ref b, c, d, a, x[13], S34); /* 44 */ - HH(ref a, b, c, d, x[ 3], S31); /* 45 */ - HH(ref d, a, b, c, x[11], S32); /* 46 */ - HH(ref c, d, a, b, x[ 7], S33); /* 47 */ - HH(ref b, c, d, a, x[15], S34); /* 48 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - } - } - } -} From 32d479d2a4314d5f7bb72efc5ccfe17a3182e5be Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 6 Dec 2021 14:51:47 +0300 Subject: [PATCH 03/40] Fix the namespace --- .../System.Net.Security/src/System/Net/Security/MD4.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index f507213037f886..31a2ddf83d8531 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -namespace System.Security.Cryptography +namespace System.Net.Security { internal sealed class MD4 { From fa5e3a528d881292c0dd029763b0c98fd4d499be Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 6 Dec 2021 16:00:30 +0300 Subject: [PATCH 04/40] Make some methods static --- .../src/System/Net/Security/MD4.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 31a2ddf83d8531..bd3e8c1082e447 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -132,7 +132,7 @@ private byte[] HashFinal() //--- private methods --------------------------------------------------- - private byte[] Padding(int nLength) + private static byte[] Padding(int nLength) { byte[] padding = new byte[nLength]; padding[0] = 0x80; @@ -140,48 +140,48 @@ private byte[] Padding(int nLength) } /* F, G and H are basic MD4 functions. */ - private uint F(uint x, uint y, uint z) + private static uint F(uint x, uint y, uint z) { return (uint)(((x) & (y)) | ((~x) & (z))); } - private uint G(uint x, uint y, uint z) + private static uint G(uint x, uint y, uint z) { return (uint)(((x) & (y)) | ((x) & (z)) | ((y) & (z))); } - private uint H(uint x, uint y, uint z) + private static uint H(uint x, uint y, uint z) { return (uint)((x) ^ (y) ^ (z)); } /* ROTATE_LEFT rotates x left n bits. */ - private uint ROL(uint x, byte n) + private static uint ROL(uint x, byte n) { return (uint)(((x) << (n)) | ((x) >> (32 - (n)))); } /* FF, GG and HH are transformations for rounds 1, 2 and 3 */ /* Rotation is separate from addition to prevent recomputation */ - private void FF(ref uint a, uint b, uint c, uint d, uint x, byte s) + private static void FF(ref uint a, uint b, uint c, uint d, uint x, byte s) { a += F(b, c, d) + x; a = ROL(a, s); } - private void GG(ref uint a, uint b, uint c, uint d, uint x, byte s) + private static void GG(ref uint a, uint b, uint c, uint d, uint x, byte s) { a += G(b, c, d) + x + 0x5a827999; a = ROL(a, s); } - private void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) + private static void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) { a += H(b, c, d) + x + 0x6ed9eba1; a = ROL(a, s); } - private void Encode(byte[] output, uint[] input) + private static void Encode(byte[] output, uint[] input) { for (int i = 0, j = 0; j < output.Length; i++, j += 4) { @@ -192,7 +192,7 @@ private void Encode(byte[] output, uint[] input) } } - private void Decode(uint[] output, byte[] input, int index) + private static void Decode(uint[] output, byte[] input, int index) { for (int i = 0, j = index; i < output.Length; i++, j += 4) { From 5c7c417452095f9cdf50f39eaa5d86f21d93a9b2 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Wed, 8 Dec 2021 14:21:31 +0300 Subject: [PATCH 05/40] Port some portion of MD4 tests --- .../src/System/Net/Security/MD4.cs | 10 +- .../tests/FunctionalTests/MD4Tests.cs | 97 +++++++++++++++++++ .../System.Net.Security.Tests.csproj | 2 + 3 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index bd3e8c1082e447..28c9fe93e1078f 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -8,8 +8,6 @@ namespace System.Net.Security { internal sealed class MD4 { - private const int HashSizeBits = 128; - private const int HashSizeBytes = HashSizeBits / 8; private byte[]? HashValue; private uint[] state; private byte[] buffer; @@ -30,6 +28,8 @@ internal sealed class MD4 private const int S34 = 15; private byte[] digest; + public int HashSize => 128; + public int HashSizeBytes => HashSize / 8; public MD4() { @@ -51,7 +51,7 @@ public int HashData(ReadOnlySpan source, Span destination) throw new ArgumentException("Destination is too short.", nameof(destination)); } - destination = ComputeHash(source.ToArray(), 0, source.Length); + ComputeHash(source.ToArray(), 0, source.Length).CopyTo(destination); return destination.Length; } @@ -68,9 +68,9 @@ private void Initialize() Array.Clear(x, 0, 16); } - private byte[] ComputeHash(byte[] buffer, int offset, int count) + private byte[] ComputeHash(byte[] array, int offset, int count) { - HashCore(buffer, offset, count); + HashCore(array, offset, count); HashValue = HashFinal(); byte[] result = (byte[]) HashValue.Clone(); Initialize(); diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs new file mode 100644 index 00000000000000..306105ad86a0c0 --- /dev/null +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.IO.Tests; +using System.Net.Security; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace System.Net.Security.Tests +{ + public class MD4Tests + { + // MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0 + [Fact] + public void RFC1320_Test1() + { + MD4 hash = new MD4(); + byte[] input = new byte[0]; + byte[] expected = { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 }; + Verify(hash, input, expected); + } + + private void Verify(MD4 hash, byte[] input, byte[] expected) + { + // Span outputSpan = stackalloc byte[expected.Length]; + byte[] outputSpan = new byte[expected.Length]; + int bytesWritten = hash.HashData(input, outputSpan); + Assert.Equal(hash.HashSizeBytes, bytesWritten); + // Assert.Equal(expected, outputSpan.ToArray()); + Assert.Equal(expected, outputSpan); + } + + // // MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24 + [Fact] + public void RFC1320_Test2 () + { + MD4 hash = new MD4(); + byte[] expected = { 0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24 }; + byte[] input = Encoding.Default.GetBytes ("a"); + Verify(hash, input, expected); + } + + // MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d + [Fact] + public void RFC1320_Test3 () + { + MD4 hash = new MD4(); + byte[] expected = { 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d }; + byte[] input = Encoding.Default.GetBytes ("abc"); + Verify(hash, input, expected); + } + + // MD4 ("message digest") = d9130a8164549fe818874806e1c7014b + [Fact] + public void RFC1320_Test4 () + { + MD4 hash = new MD4(); + byte[] expected = { 0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b }; + byte[] input = Encoding.Default.GetBytes ("message digest"); + Verify(hash, input, expected); + } + + // MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9 + [Fact] + public void RFC1320_Test5 () + { + MD4 hash = new MD4(); + byte[] expected = { 0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9 }; + byte[] input = Encoding.Default.GetBytes ("abcdefghijklmnopqrstuvwxyz"); + Verify(hash, input, expected); + } + + // MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = + // 043f8582f241db351ce627e153e7f0e4 + [Fact] + public void RFC1320_Test6 () + { + MD4 hash = new MD4(); + byte[] expected = { 0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4 }; + byte[] input = Encoding.Default.GetBytes ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + Verify(hash, input, expected); + } + + // MD4 ("123456789012345678901234567890123456789012345678901234567890123456 + // 78901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536 + [Fact] + public void RFC1320_Test7 () + { + MD4 hash = new MD4(); + byte[] expected = { 0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36 }; + byte[] input = Encoding.Default.GetBytes ("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); + Verify(hash, input, expected); + } + } +} diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index a6a21cc91e155b..997b6d6dd5f8b1 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -12,6 +12,8 @@ + + From daad017c03ec4c6e38d5cdfbaa069f5209362fbb Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 10 Dec 2021 09:33:00 +0300 Subject: [PATCH 06/40] Feedback --- .../System.Net.Security/src/System.Net.Security.csproj | 2 +- .../System.Net.Security/src/System/Net/Security/MD4.cs | 6 ++++++ .../System.Net.Security/tests/FunctionalTests/MD4Tests.cs | 2 -- .../tests/FunctionalTests/System.Net.Security.Tests.csproj | 6 ++++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System.Net.Security.csproj b/src/libraries/System.Net.Security/src/System.Net.Security.csproj index 9d0b8da1fc0aa1..047cbdcc98aea9 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -18,7 +18,6 @@ $(DefineConstants);SYSNETSECURITY_NO_OPENSSL - @@ -364,6 +363,7 @@ + diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 28c9fe93e1078f..e01097b8a2c010 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -4,6 +4,12 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +// +// This class is a port of the Mono managed implementation of the MD4 algorithm +// and required to support NTLM in Android only. +// It's an implementation detail and is not intended to be a public API. +// Assuming that NTLM would be System.Net.Security, it makes sense to put MD4 here as well. +// namespace System.Net.Security { internal sealed class MD4 diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs index 306105ad86a0c0..1b0404d269cae5 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs @@ -24,11 +24,9 @@ public void RFC1320_Test1() private void Verify(MD4 hash, byte[] input, byte[] expected) { - // Span outputSpan = stackalloc byte[expected.Length]; byte[] outputSpan = new byte[expected.Length]; int bytesWritten = hash.HashData(input, outputSpan); Assert.Equal(hash.HashSizeBytes, bytesWritten); - // Assert.Equal(expected, outputSpan.ToArray()); Assert.Equal(expected, outputSpan); } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index 997b6d6dd5f8b1..259a88044f7488 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -12,8 +12,6 @@ - - @@ -126,6 +124,10 @@ + + + + From b40203e7af39bb162c17582ba46bd87eab5a208c Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 10 Dec 2021 13:20:49 +0300 Subject: [PATCH 07/40] Add Android as a target framework to build S.N.Security tests --- .../tests/FunctionalTests/System.Net.Security.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index 259a88044f7488..89e72ea92f6ee3 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -2,7 +2,7 @@ true true - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-Android annotations true true From 187f80afa4c93e235f4825259a3605a04968fd48 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 10 Dec 2021 18:03:24 +0300 Subject: [PATCH 08/40] Extract the MD4 tests to a separate test suite to not depend on System.Net.Security test suites disabled for CI due to timeout issue --- .../FunctionalTests/System.Net.Security.Tests.csproj | 4 ---- .../{FunctionalTests => InternalUnitTests}/MD4Tests.cs | 1 - .../System.Net.Security.InternalUnit.Tests.csproj | 9 +++++++++ 3 files changed, 9 insertions(+), 5 deletions(-) rename src/libraries/System.Net.Security/tests/{FunctionalTests => InternalUnitTests}/MD4Tests.cs (99%) create mode 100644 src/libraries/System.Net.Security/tests/InternalUnitTests/System.Net.Security.InternalUnit.Tests.csproj diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index 89e72ea92f6ee3..0a67a21757a52b 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -124,10 +124,6 @@ - - - - diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs similarity index 99% rename from src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs rename to src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs index 1b0404d269cae5..20008dffc049d1 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/MD4Tests.cs +++ b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; -using System.IO.Tests; using System.Net.Security; using System.Text; using System.Threading.Tasks; diff --git a/src/libraries/System.Net.Security/tests/InternalUnitTests/System.Net.Security.InternalUnit.Tests.csproj b/src/libraries/System.Net.Security/tests/InternalUnitTests/System.Net.Security.InternalUnit.Tests.csproj new file mode 100644 index 00000000000000..07b426375b59e1 --- /dev/null +++ b/src/libraries/System.Net.Security/tests/InternalUnitTests/System.Net.Security.InternalUnit.Tests.csproj @@ -0,0 +1,9 @@ + + + $(NetCoreAppCurrent)-Android + + + + + + From 43f231c02a44095b728913f9fd3473341b02f5f5 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Sat, 11 Dec 2021 17:12:44 +0300 Subject: [PATCH 09/40] Add MD4 tests to the smoke tests item group to avoid running all the library test suites cycle --- src/libraries/tests.proj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 750aa3db75561d..177302f7d45881 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -354,6 +354,9 @@ + + + Date: Mon, 13 Dec 2021 12:50:22 +0300 Subject: [PATCH 10/40] Feedback --- .../tests/InternalUnitTests/MD4Tests.cs | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs index 20008dffc049d1..f34cef0f16aafc 100644 --- a/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs +++ b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs @@ -11,9 +11,9 @@ namespace System.Net.Security.Tests { public class MD4Tests { - // MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0 + // MD4("") = 31d6cfe0d16ae931b73c59d7e0c089c0 [Fact] - public void RFC1320_Test1() + public void TryEncrypt_Empty() { MD4 hash = new MD4(); byte[] input = new byte[0]; @@ -21,74 +21,72 @@ public void RFC1320_Test1() Verify(hash, input, expected); } - private void Verify(MD4 hash, byte[] input, byte[] expected) - { - byte[] outputSpan = new byte[expected.Length]; - int bytesWritten = hash.HashData(input, outputSpan); - Assert.Equal(hash.HashSizeBytes, bytesWritten); - Assert.Equal(expected, outputSpan); - } - - // // MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24 + // // MD4("a") = bde52cb31de33e46245e05fbdbd6fb24 [Fact] - public void RFC1320_Test2 () + public void TryEncrypt_SingleLetter() { MD4 hash = new MD4(); byte[] expected = { 0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24 }; - byte[] input = Encoding.Default.GetBytes ("a"); + byte[] input = Encoding.Default.GetBytes("a"); Verify(hash, input, expected); } - // MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d + // MD4("abc") = a448017aaf21d8525fc10ae87aa6729d [Fact] - public void RFC1320_Test3 () + public void TryEncrypt_ThreeLetters() { MD4 hash = new MD4(); byte[] expected = { 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d }; - byte[] input = Encoding.Default.GetBytes ("abc"); + byte[] input = Encoding.Default.GetBytes("abc"); Verify(hash, input, expected); } - // MD4 ("message digest") = d9130a8164549fe818874806e1c7014b + // MD4("message digest") = d9130a8164549fe818874806e1c7014b [Fact] - public void RFC1320_Test4 () + public void TryEncrypt_Phrase() { MD4 hash = new MD4(); byte[] expected = { 0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b }; - byte[] input = Encoding.Default.GetBytes ("message digest"); + byte[] input = Encoding.Default.GetBytes("message digest"); Verify(hash, input, expected); } - // MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9 + // MD4("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9 [Fact] - public void RFC1320_Test5 () + public void TryEncrypt_AlphabetInLowercase() { MD4 hash = new MD4(); byte[] expected = { 0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9 }; - byte[] input = Encoding.Default.GetBytes ("abcdefghijklmnopqrstuvwxyz"); + byte[] input = Encoding.Default.GetBytes("abcdefghijklmnopqrstuvwxyz"); Verify(hash, input, expected); } - // MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = - // 043f8582f241db351ce627e153e7f0e4 + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = 043f8582f241db351ce627e153e7f0e4 [Fact] - public void RFC1320_Test6 () + public void TryEncrypt_AlphabetInUpperLowerCasesAndNumbers() { MD4 hash = new MD4(); byte[] expected = { 0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4 }; - byte[] input = Encoding.Default.GetBytes ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + byte[] input = Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); Verify(hash, input, expected); } - // MD4 ("123456789012345678901234567890123456789012345678901234567890123456 - // 78901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536 + // MD4("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536 [Fact] - public void RFC1320_Test7 () + public void TryEncrypt_RepeatedSequenceOfNumbers() { MD4 hash = new MD4(); byte[] expected = { 0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36 }; - byte[] input = Encoding.Default.GetBytes ("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); + byte[] input = Encoding.Default.GetBytes("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); Verify(hash, input, expected); } + + private void Verify(MD4 hash, byte[] input, byte[] expected) + { + byte[] outputSpan = new byte[expected.Length]; + int bytesWritten = hash.HashData(input, outputSpan); + Assert.Equal(hash.HashSizeBytes, bytesWritten); + Assert.Equal(expected, outputSpan); + } } } From c4a4c5e4d2b4a24e422fdfa6859ddbeadaf65bbe Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Tue, 11 Jan 2022 16:09:02 +0300 Subject: [PATCH 11/40] Transient move from the instance methods to static ones. --- .../src/System/Net/Security/MD4.cs | 88 ++++++------------- .../tests/InternalUnitTests/MD4Tests.cs | 3 +- 2 files changed, 30 insertions(+), 61 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index e01097b8a2c010..5a7fe8502748e0 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -14,55 +14,12 @@ namespace System.Net.Security { internal sealed class MD4 { - private byte[]? HashValue; - private uint[] state; - private byte[] buffer; - private uint[] count; - private uint[] x; - - private const int S11 = 3; - private const int S12 = 7; - private const int S13 = 11; - private const int S14 = 19; - private const int S21 = 3; - private const int S22 = 5; - private const int S23 = 9; - private const int S24 = 13; - private const int S31 = 3; - private const int S32 = 9; - private const int S33 = 11; - private const int S34 = 15; - - private byte[] digest; - public int HashSize => 128; - public int HashSizeBytes => HashSize / 8; - - public MD4() - { - // we allocate the context memory - state = new uint[4]; - count = new uint[2]; - buffer = new byte[64]; - digest = new byte[16]; - // temporary buffer in MD4Transform that we don't want to keep allocate on each iteration - x = new uint[16]; - // the initialize our context - Initialize(); - } - - public int HashData(ReadOnlySpan source, Span destination) + internal static void HashData(ReadOnlySpan source, Span destination) { - if (destination.Length < HashSizeBytes) - { - throw new ArgumentException("Destination is too short.", nameof(destination)); - } + // Debug.Assert(destination.Length == 128 >> 3); + // Span buffer = stackalloc byte[64]; - ComputeHash(source.ToArray(), 0, source.Length).CopyTo(destination); - return destination.Length; - } - - private void Initialize() - { + // the initialize our context count[0] = 0; count[1] = 0; state[0] = 0x67452301; @@ -72,18 +29,34 @@ private void Initialize() // Zeroize sensitive information Array.Clear(buffer, 0, 64); Array.Clear(x, 0, 16); - } - private byte[] ComputeHash(byte[] array, int offset, int count) - { - HashCore(array, offset, count); + HashCore(source.ToArray(), 0, source.Length); HashValue = HashFinal(); byte[] result = (byte[]) HashValue.Clone(); - Initialize(); - return result; + result.CopyTo(destination); } - private void HashCore(byte[] array, int ibStart, int cbSize) + private static byte[]? HashValue; + private static uint[] state = new uint[4]; + private static byte[] buffer = new byte[64]; + private static uint[] count = new uint[2]; + private static uint[] x = new uint[16]; + + private const int S11 = 3; + private const int S12 = 7; + private const int S13 = 11; + private const int S14 = 19; + private const int S21 = 3; + private const int S22 = 5; + private const int S23 = 9; + private const int S24 = 13; + private const int S31 = 3; + private const int S32 = 9; + private const int S33 = 11; + private const int S34 = 15; + + private static byte[] digest = new byte[16]; + private static void HashCore(byte[] array, int ibStart, int cbSize) { /* Compute number of bytes mod 64 */ int index = (int)((count[0] >> 3) & 0x3F); @@ -113,7 +86,7 @@ private void HashCore(byte[] array, int ibStart, int cbSize) Buffer.BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); } - private byte[] HashFinal() + private static byte[] HashFinal() { /* Save number of bits */ byte[] bits = new byte[8]; @@ -130,9 +103,6 @@ private byte[] HashFinal() /* Store state in digest */ Encode(digest, state); - // Zeroize sensitive information. - Initialize(); - return digest; } @@ -206,7 +176,7 @@ private static void Decode(uint[] output, byte[] input, int index) } } - private void MD4Transform(uint[] state, byte[] block, int index) + private static void MD4Transform(uint[] state, byte[] block, int index) { uint a = state[0]; uint b = state[1]; diff --git a/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs index f34cef0f16aafc..8e0ff390f12c43 100644 --- a/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs +++ b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs @@ -84,8 +84,7 @@ public void TryEncrypt_RepeatedSequenceOfNumbers() private void Verify(MD4 hash, byte[] input, byte[] expected) { byte[] outputSpan = new byte[expected.Length]; - int bytesWritten = hash.HashData(input, outputSpan); - Assert.Equal(hash.HashSizeBytes, bytesWritten); + MD4.HashData(input, outputSpan); Assert.Equal(expected, outputSpan); } } From 40ae0392dca09f2f2b7a89f381ecfd75c982c496 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Thu, 13 Jan 2022 14:10:50 +0300 Subject: [PATCH 12/40] Add the "little-endian" case when encoding --- .../src/System/Net/Security/MD4.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 5a7fe8502748e0..59906d074a2120 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -161,10 +162,17 @@ private static void Encode(byte[] output, uint[] input) { for (int i = 0, j = 0; j < output.Length; i++, j += 4) { - output[j] = (byte)(input[i]); - output[j + 1] = (byte)(input[i] >> 8); - output[j + 2] = (byte)(input[i] >> 16); - output[j + 3] = (byte)(input[i] >> 24); + if (BitConverter.IsLittleEndian) + { + BinaryPrimitives.WriteUInt32LittleEndian(output.AsSpan(j), input[i]); + } + else + { + output[j] = (byte)(input[i]); + output[j + 1] = (byte)(input[i] >> 8); + output[j + 2] = (byte)(input[i] >> 16); + output[j + 3] = (byte)(input[i] >> 24); + } } } From 6d1fd3c31d5aee925d4823feb02c03d9da260edc Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Thu, 13 Jan 2022 15:24:49 +0300 Subject: [PATCH 13/40] Transforming static fields to local variables --- .../src/System/Net/Security/MD4.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 59906d074a2120..e153678f5bd466 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -17,8 +17,9 @@ internal sealed class MD4 { internal static void HashData(ReadOnlySpan source, Span destination) { - // Debug.Assert(destination.Length == 128 >> 3); + Debug.Assert(destination.Length == 128 >> 3); // Span buffer = stackalloc byte[64]; + Span state = stackalloc uint[4]; // the initialize our context count[0] = 0; @@ -31,14 +32,13 @@ internal static void HashData(ReadOnlySpan source, Span destination) Array.Clear(buffer, 0, 64); Array.Clear(x, 0, 16); - HashCore(source.ToArray(), 0, source.Length); - HashValue = HashFinal(); + HashCore(source.ToArray(), 0, source.Length, state); + HashValue = HashFinal(state); byte[] result = (byte[]) HashValue.Clone(); result.CopyTo(destination); } private static byte[]? HashValue; - private static uint[] state = new uint[4]; private static byte[] buffer = new byte[64]; private static uint[] count = new uint[2]; private static uint[] x = new uint[16]; @@ -57,7 +57,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) private const int S34 = 15; private static byte[] digest = new byte[16]; - private static void HashCore(byte[] array, int ibStart, int cbSize) + private static void HashCore(byte[] array, int ibStart, int cbSize, Span state) { /* Compute number of bytes mod 64 */ int index = (int)((count[0] >> 3) & 0x3F); @@ -87,7 +87,7 @@ private static void HashCore(byte[] array, int ibStart, int cbSize) Buffer.BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); } - private static byte[] HashFinal() + private static byte[] HashFinal(Span state) { /* Save number of bits */ byte[] bits = new byte[8]; @@ -96,10 +96,10 @@ private static byte[] HashFinal() /* Pad out to 56 mod 64. */ uint index = ((count[0] >> 3) & 0x3f); int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); - HashCore(Padding(padLen), 0, padLen); + HashCore(Padding(padLen), 0, padLen, state); /* Append length (before padding) */ - HashCore(bits, 0, 8); + HashCore(bits, 0, 8, state); /* Store state in digest */ Encode(digest, state); @@ -158,7 +158,7 @@ private static void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) a = ROL(a, s); } - private static void Encode(byte[] output, uint[] input) + private static void Encode(byte[] output, Span input) { for (int i = 0, j = 0; j < output.Length; i++, j += 4) { @@ -184,7 +184,7 @@ private static void Decode(uint[] output, byte[] input, int index) } } - private static void MD4Transform(uint[] state, byte[] block, int index) + private static void MD4Transform(Span state, byte[] block, int index) { uint a = state[0]; uint b = state[1]; From 7800933dcb7abdc9e606969aced46aeb5257deea Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 14 Jan 2022 11:23:07 +0300 Subject: [PATCH 14/40] feedback --- .../src/System/Net/Security/MD4.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index e153678f5bd466..0fb5029060d95e 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -162,17 +162,7 @@ private static void Encode(byte[] output, Span input) { for (int i = 0, j = 0; j < output.Length; i++, j += 4) { - if (BitConverter.IsLittleEndian) - { - BinaryPrimitives.WriteUInt32LittleEndian(output.AsSpan(j), input[i]); - } - else - { - output[j] = (byte)(input[i]); - output[j + 1] = (byte)(input[i] >> 8); - output[j + 2] = (byte)(input[i] >> 16); - output[j + 3] = (byte)(input[i] >> 24); - } + BinaryPrimitives.WriteUInt32LittleEndian(output.AsSpan(j), input[i]); } } From 66b7e68e3621fea24671ee94ae03e350cada5fb5 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 14 Jan 2022 13:58:21 +0300 Subject: [PATCH 15/40] Transforming static fields to local variables --- .../src/System/Net/Security/MD4.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 0fb5029060d95e..0d25b90f74e2e3 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -20,6 +20,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) Debug.Assert(destination.Length == 128 >> 3); // Span buffer = stackalloc byte[64]; Span state = stackalloc uint[4]; + Span count = stackalloc uint[2]; // the initialize our context count[0] = 0; @@ -32,15 +33,14 @@ internal static void HashData(ReadOnlySpan source, Span destination) Array.Clear(buffer, 0, 64); Array.Clear(x, 0, 16); - HashCore(source.ToArray(), 0, source.Length, state); - HashValue = HashFinal(state); + HashCore(source.ToArray(), 0, source.Length, state, count); + HashValue = HashFinal(state, count); byte[] result = (byte[]) HashValue.Clone(); result.CopyTo(destination); } private static byte[]? HashValue; private static byte[] buffer = new byte[64]; - private static uint[] count = new uint[2]; private static uint[] x = new uint[16]; private const int S11 = 3; @@ -57,7 +57,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) private const int S34 = 15; private static byte[] digest = new byte[16]; - private static void HashCore(byte[] array, int ibStart, int cbSize, Span state) + private static void HashCore(byte[] array, int ibStart, int cbSize, Span state, Span count) { /* Compute number of bytes mod 64 */ int index = (int)((count[0] >> 3) & 0x3F); @@ -87,7 +87,7 @@ private static void HashCore(byte[] array, int ibStart, int cbSize, Span s Buffer.BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); } - private static byte[] HashFinal(Span state) + private static byte[] HashFinal(Span state, Span count) { /* Save number of bits */ byte[] bits = new byte[8]; @@ -96,10 +96,10 @@ private static byte[] HashFinal(Span state) /* Pad out to 56 mod 64. */ uint index = ((count[0] >> 3) & 0x3f); int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); - HashCore(Padding(padLen), 0, padLen, state); + HashCore(Padding(padLen), 0, padLen, state, count); /* Append length (before padding) */ - HashCore(bits, 0, 8, state); + HashCore(bits, 0, 8, state, count); /* Store state in digest */ Encode(digest, state); From 2af7ceb925896bb0e33407d0273cf452e5f31da5 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 10:56:48 +0300 Subject: [PATCH 16/40] Get rid of HashValue static field --- .../System.Net.Security/src/System/Net/Security/MD4.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 0d25b90f74e2e3..ead87528671846 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -34,12 +34,9 @@ internal static void HashData(ReadOnlySpan source, Span destination) Array.Clear(x, 0, 16); HashCore(source.ToArray(), 0, source.Length, state, count); - HashValue = HashFinal(state, count); - byte[] result = (byte[]) HashValue.Clone(); - result.CopyTo(destination); + HashFinal(state, count).CopyTo(destination); } - private static byte[]? HashValue; private static byte[] buffer = new byte[64]; private static uint[] x = new uint[16]; From 98a1f3d1e38b50cf2451f1e29ec2ad1e1deeae6d Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 11:10:01 +0300 Subject: [PATCH 17/40] Make HashFinal write to destination directly --- .../src/System/Net/Security/MD4.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index ead87528671846..c14d3a06d0342a 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -34,7 +34,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) Array.Clear(x, 0, 16); HashCore(source.ToArray(), 0, source.Length, state, count); - HashFinal(state, count).CopyTo(destination); + HashFinal(state, count, destination); } private static byte[] buffer = new byte[64]; @@ -53,7 +53,6 @@ internal static void HashData(ReadOnlySpan source, Span destination) private const int S33 = 11; private const int S34 = 15; - private static byte[] digest = new byte[16]; private static void HashCore(byte[] array, int ibStart, int cbSize, Span state, Span count) { /* Compute number of bytes mod 64 */ @@ -84,7 +83,7 @@ private static void HashCore(byte[] array, int ibStart, int cbSize, Span s Buffer.BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); } - private static byte[] HashFinal(Span state, Span count) + private static void HashFinal(Span state, Span count, Span destination) { /* Save number of bits */ byte[] bits = new byte[8]; @@ -99,9 +98,7 @@ private static byte[] HashFinal(Span state, Span count) HashCore(bits, 0, 8, state, count); /* Store state in digest */ - Encode(digest, state); - - return digest; + Encode(destination, state); } //--- private methods --------------------------------------------------- @@ -155,11 +152,11 @@ private static void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) a = ROL(a, s); } - private static void Encode(byte[] output, Span input) + private static void Encode(Span output, Span input) { for (int i = 0, j = 0; j < output.Length; i++, j += 4) { - BinaryPrimitives.WriteUInt32LittleEndian(output.AsSpan(j), input[i]); + BinaryPrimitives.WriteUInt32LittleEndian(output.Slice(j), input[i]); } } From 99cd7d6471b122485f8f5c9c3bfea08665bc0782 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 12:14:35 +0300 Subject: [PATCH 18/40] Eliminate redundant arrays usage --- .../src/System/Net/Security/MD4.cs | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index c14d3a06d0342a..e30604c6f6cdd9 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -20,7 +20,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) Debug.Assert(destination.Length == 128 >> 3); // Span buffer = stackalloc byte[64]; Span state = stackalloc uint[4]; - Span count = stackalloc uint[2]; + Span count = stackalloc uint[2]; // the initialize our context count[0] = 0; @@ -33,7 +33,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) Array.Clear(buffer, 0, 64); Array.Clear(x, 0, 16); - HashCore(source.ToArray(), 0, source.Length, state, count); + HashCore(source, 0, source.Length, state, count); HashFinal(state, count, destination); } @@ -53,7 +53,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) private const int S33 = 11; private const int S34 = 15; - private static void HashCore(byte[] array, int ibStart, int cbSize, Span state, Span count) + private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, Span state, Span count) { /* Compute number of bytes mod 64 */ int index = (int)((count[0] >> 3) & 0x3F); @@ -68,7 +68,7 @@ private static void HashCore(byte[] array, int ibStart, int cbSize, Span s /* Transform as many times as possible. */ if (cbSize >= partLen) { - Buffer.BlockCopy(array, ibStart, buffer, index, partLen); + BlockCopy(array, ibStart, buffer, index, partLen); MD4Transform(state, buffer, 0); for (i = partLen; i + 63 < cbSize; i += 64) @@ -80,19 +80,21 @@ private static void HashCore(byte[] array, int ibStart, int cbSize, Span s } /* Buffer remaining input */ - Buffer.BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); + BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); } private static void HashFinal(Span state, Span count, Span destination) { /* Save number of bits */ - byte[] bits = new byte[8]; + Span bits = stackalloc byte[8]; Encode(bits, count); /* Pad out to 56 mod 64. */ uint index = ((count[0] >> 3) & 0x3f); int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); - HashCore(Padding(padLen), 0, padLen, state, count); + Span padding = stackalloc byte[padLen]; + padding[0] = 0x80; + HashCore(padding, 0, padLen, state, count); /* Append length (before padding) */ HashCore(bits, 0, 8, state, count); @@ -103,11 +105,12 @@ private static void HashFinal(Span state, Span count, Span des //--- private methods --------------------------------------------------- - private static byte[] Padding(int nLength) + private static void BlockCopy(ReadOnlySpan source, int srcOffset, Span destination, int dstOffset, int count) { - byte[] padding = new byte[nLength]; - padding[0] = 0x80; - return padding; + for (int srcIndex = srcOffset, dstIndex = dstOffset; srcIndex < srcOffset + count; srcIndex++, dstIndex++) + { + destination[dstIndex] = source[srcIndex]; + } } /* F, G and H are basic MD4 functions. */ @@ -160,7 +163,7 @@ private static void Encode(Span output, Span input) } } - private static void Decode(uint[] output, byte[] input, int index) + private static void Decode(uint[] output, ReadOnlySpan input, int index) { for (int i = 0, j = index; i < output.Length; i++, j += 4) { @@ -168,7 +171,7 @@ private static void Decode(uint[] output, byte[] input, int index) } } - private static void MD4Transform(Span state, byte[] block, int index) + private static void MD4Transform(Span state, ReadOnlySpan block, int index) { uint a = state[0]; uint b = state[1]; From 1809d0f40381bec635a24d97978ebfe659e5fdb6 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 12:32:42 +0300 Subject: [PATCH 19/40] static field -> local --- .../src/System/Net/Security/MD4.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index e30604c6f6cdd9..5bcabba981c715 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -18,7 +18,7 @@ internal sealed class MD4 internal static void HashData(ReadOnlySpan source, Span destination) { Debug.Assert(destination.Length == 128 >> 3); - // Span buffer = stackalloc byte[64]; + Span buffer = stackalloc byte[64]; Span state = stackalloc uint[4]; Span count = stackalloc uint[2]; @@ -30,14 +30,13 @@ internal static void HashData(ReadOnlySpan source, Span destination) state[2] = 0x98badcfe; state[3] = 0x10325476; // Zeroize sensitive information - Array.Clear(buffer, 0, 64); + buffer.Fill(0); Array.Clear(x, 0, 16); - HashCore(source, 0, source.Length, state, count); - HashFinal(state, count, destination); + HashCore(source, 0, source.Length, state, count, buffer); + HashFinal(state, count, destination, buffer); } - private static byte[] buffer = new byte[64]; private static uint[] x = new uint[16]; private const int S11 = 3; @@ -53,7 +52,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) private const int S33 = 11; private const int S34 = 15; - private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, Span state, Span count) + private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, Span state, Span count, Span buffer) { /* Compute number of bytes mod 64 */ int index = (int)((count[0] >> 3) & 0x3F); @@ -83,7 +82,7 @@ private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); } - private static void HashFinal(Span state, Span count, Span destination) + private static void HashFinal(Span state, Span count, Span destination, Span buffer) { /* Save number of bits */ Span bits = stackalloc byte[8]; @@ -94,10 +93,10 @@ private static void HashFinal(Span state, Span count, Span des int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); Span padding = stackalloc byte[padLen]; padding[0] = 0x80; - HashCore(padding, 0, padLen, state, count); + HashCore(padding, 0, padLen, state, count, buffer); /* Append length (before padding) */ - HashCore(bits, 0, 8, state, count); + HashCore(bits, 0, 8, state, count, buffer); /* Store state in digest */ Encode(destination, state); From 913a8d6d569bb79575447886918006fecddc09bd Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 13:40:10 +0300 Subject: [PATCH 20/40] static field -> local --- .../src/System/Net/Security/MD4.cs | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 5bcabba981c715..aa5231fcf7a55b 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -21,6 +21,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) Span buffer = stackalloc byte[64]; Span state = stackalloc uint[4]; Span count = stackalloc uint[2]; + Span x = stackalloc uint[16]; // the initialize our context count[0] = 0; @@ -31,14 +32,12 @@ internal static void HashData(ReadOnlySpan source, Span destination) state[3] = 0x10325476; // Zeroize sensitive information buffer.Fill(0); - Array.Clear(x, 0, 16); + x.Fill(0); - HashCore(source, 0, source.Length, state, count, buffer); - HashFinal(state, count, destination, buffer); + HashCore(source, 0, source.Length, state, count, buffer, x); + HashFinal(state, count, destination, buffer, x); } - private static uint[] x = new uint[16]; - private const int S11 = 3; private const int S12 = 7; private const int S13 = 11; @@ -52,7 +51,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) private const int S33 = 11; private const int S34 = 15; - private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, Span state, Span count, Span buffer) + private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, Span state, Span count, Span buffer, Span x) { /* Compute number of bytes mod 64 */ int index = (int)((count[0] >> 3) & 0x3F); @@ -68,11 +67,11 @@ private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, if (cbSize >= partLen) { BlockCopy(array, ibStart, buffer, index, partLen); - MD4Transform(state, buffer, 0); + MD4Transform(state, buffer, 0, x); for (i = partLen; i + 63 < cbSize; i += 64) { - MD4Transform(state, array, ibStart + i); + MD4Transform(state, array, ibStart + i, x); } index = 0; @@ -82,7 +81,7 @@ private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); } - private static void HashFinal(Span state, Span count, Span destination, Span buffer) + private static void HashFinal(Span state, Span count, Span destination, Span buffer, Span x) { /* Save number of bits */ Span bits = stackalloc byte[8]; @@ -93,10 +92,10 @@ private static void HashFinal(Span state, Span count, Span des int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); Span padding = stackalloc byte[padLen]; padding[0] = 0x80; - HashCore(padding, 0, padLen, state, count, buffer); + HashCore(padding, 0, padLen, state, count, buffer, x); /* Append length (before padding) */ - HashCore(bits, 0, 8, state, count, buffer); + HashCore(bits, 0, 8, state, count, buffer, x); /* Store state in digest */ Encode(destination, state); @@ -162,7 +161,7 @@ private static void Encode(Span output, Span input) } } - private static void Decode(uint[] output, ReadOnlySpan input, int index) + private static void Decode(Span output, ReadOnlySpan input, int index) { for (int i = 0, j = index; i < output.Length; i++, j += 4) { @@ -170,7 +169,7 @@ private static void Decode(uint[] output, ReadOnlySpan input, int index) } } - private static void MD4Transform(Span state, ReadOnlySpan block, int index) + private static void MD4Transform(Span state, ReadOnlySpan block, int index, Span x) { uint a = state[0]; uint b = state[1]; From cf90c3358fcb428999e95386c6b5de8218c029c6 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 13:43:20 +0300 Subject: [PATCH 21/40] Move up constants --- .../src/System/Net/Security/MD4.cs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index aa5231fcf7a55b..c7ba79033ca1fb 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -15,6 +15,19 @@ namespace System.Net.Security { internal sealed class MD4 { + private const int S11 = 3; + private const int S12 = 7; + private const int S13 = 11; + private const int S14 = 19; + private const int S21 = 3; + private const int S22 = 5; + private const int S23 = 9; + private const int S24 = 13; + private const int S31 = 3; + private const int S32 = 9; + private const int S33 = 11; + private const int S34 = 15; + internal static void HashData(ReadOnlySpan source, Span destination) { Debug.Assert(destination.Length == 128 >> 3); @@ -37,20 +50,6 @@ internal static void HashData(ReadOnlySpan source, Span destination) HashCore(source, 0, source.Length, state, count, buffer, x); HashFinal(state, count, destination, buffer, x); } - - private const int S11 = 3; - private const int S12 = 7; - private const int S13 = 11; - private const int S14 = 19; - private const int S21 = 3; - private const int S22 = 5; - private const int S23 = 9; - private const int S24 = 13; - private const int S31 = 3; - private const int S32 = 9; - private const int S33 = 11; - private const int S34 = 15; - private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, Span state, Span count, Span buffer, Span x) { /* Compute number of bytes mod 64 */ From 2cebfdf8fe029ad3fc42f8d5a90e0290e901d5d0 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 13:44:59 +0300 Subject: [PATCH 22/40] Rename input param --- .../System.Net.Security/src/System/Net/Security/MD4.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index c7ba79033ca1fb..d77f88623f6b0f 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -50,7 +50,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) HashCore(source, 0, source.Length, state, count, buffer, x); HashFinal(state, count, destination, buffer, x); } - private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, Span state, Span count, Span buffer, Span x) + private static void HashCore(ReadOnlySpan input, int ibStart, int cbSize, Span state, Span count, Span buffer, Span x) { /* Compute number of bytes mod 64 */ int index = (int)((count[0] >> 3) & 0x3F); @@ -65,19 +65,19 @@ private static void HashCore(ReadOnlySpan array, int ibStart, int cbSize, /* Transform as many times as possible. */ if (cbSize >= partLen) { - BlockCopy(array, ibStart, buffer, index, partLen); + BlockCopy(input, ibStart, buffer, index, partLen); MD4Transform(state, buffer, 0, x); for (i = partLen; i + 63 < cbSize; i += 64) { - MD4Transform(state, array, ibStart + i, x); + MD4Transform(state, input, ibStart + i, x); } index = 0; } /* Buffer remaining input */ - BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); + BlockCopy(input, ibStart + i, buffer, index, (cbSize - i)); } private static void HashFinal(Span state, Span count, Span destination, Span buffer, Span x) From 40f136c24bdff6f849c696397a7e09c5b391524a Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 14:23:15 +0300 Subject: [PATCH 23/40] Put a local variable in place where it's neded --- .../src/System/Net/Security/MD4.cs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index d77f88623f6b0f..f38b8f71bf6e23 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -34,7 +34,6 @@ internal static void HashData(ReadOnlySpan source, Span destination) Span buffer = stackalloc byte[64]; Span state = stackalloc uint[4]; Span count = stackalloc uint[2]; - Span x = stackalloc uint[16]; // the initialize our context count[0] = 0; @@ -45,12 +44,11 @@ internal static void HashData(ReadOnlySpan source, Span destination) state[3] = 0x10325476; // Zeroize sensitive information buffer.Fill(0); - x.Fill(0); - HashCore(source, 0, source.Length, state, count, buffer, x); - HashFinal(state, count, destination, buffer, x); + HashCore(source, 0, source.Length, state, count, buffer); + HashFinal(state, count, destination, buffer); } - private static void HashCore(ReadOnlySpan input, int ibStart, int cbSize, Span state, Span count, Span buffer, Span x) + private static void HashCore(ReadOnlySpan input, int ibStart, int cbSize, Span state, Span count, Span buffer) { /* Compute number of bytes mod 64 */ int index = (int)((count[0] >> 3) & 0x3F); @@ -66,11 +64,11 @@ private static void HashCore(ReadOnlySpan input, int ibStart, int cbSize, if (cbSize >= partLen) { BlockCopy(input, ibStart, buffer, index, partLen); - MD4Transform(state, buffer, 0, x); + MD4Transform(state, buffer, 0); for (i = partLen; i + 63 < cbSize; i += 64) { - MD4Transform(state, input, ibStart + i, x); + MD4Transform(state, input, ibStart + i); } index = 0; @@ -80,7 +78,7 @@ private static void HashCore(ReadOnlySpan input, int ibStart, int cbSize, BlockCopy(input, ibStart + i, buffer, index, (cbSize - i)); } - private static void HashFinal(Span state, Span count, Span destination, Span buffer, Span x) + private static void HashFinal(Span state, Span count, Span destination, Span buffer) { /* Save number of bits */ Span bits = stackalloc byte[8]; @@ -91,10 +89,10 @@ private static void HashFinal(Span state, Span count, Span des int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); Span padding = stackalloc byte[padLen]; padding[0] = 0x80; - HashCore(padding, 0, padLen, state, count, buffer, x); + HashCore(padding, 0, padLen, state, count, buffer); /* Append length (before padding) */ - HashCore(bits, 0, 8, state, count, buffer, x); + HashCore(bits, 0, 8, state, count, buffer); /* Store state in digest */ Encode(destination, state); @@ -168,12 +166,13 @@ private static void Decode(Span output, ReadOnlySpan input, int inde } } - private static void MD4Transform(Span state, ReadOnlySpan block, int index, Span x) + private static void MD4Transform(Span state, ReadOnlySpan block, int index) { uint a = state[0]; uint b = state[1]; uint c = state[2]; uint d = state[3]; + Span x = stackalloc uint[16]; Decode(x, block, index); From 956f8ddf11280d9b3eca5f65f443df0bdd7775da Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 16:09:18 +0300 Subject: [PATCH 24/40] Move the HashFinal logic to the HashData method --- .../src/System/Net/Security/MD4.cs | 57 ++++++++++++------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index f38b8f71bf6e23..cb83092dff630e 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -46,8 +46,25 @@ internal static void HashData(ReadOnlySpan source, Span destination) buffer.Fill(0); HashCore(source, 0, source.Length, state, count, buffer); - HashFinal(state, count, destination, buffer); + + /* Save number of bits */ + Span bits = stackalloc byte[8]; + Encode(bits, count); + + /* Pad out to 56 mod 64. */ + uint index = ((count[0] >> 3) & 0x3f); + int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); + Span padding = stackalloc byte[padLen]; + padding[0] = 0x80; + HashCore(padding, 0, padLen, state, count, buffer); + + /* Append length (before padding) */ + HashCore(bits, 0, 8, state, count, buffer); + + /* Write state to destination */ + Encode(destination, state); } + private static void HashCore(ReadOnlySpan input, int ibStart, int cbSize, Span state, Span count, Span buffer) { /* Compute number of bytes mod 64 */ @@ -78,25 +95,25 @@ private static void HashCore(ReadOnlySpan input, int ibStart, int cbSize, BlockCopy(input, ibStart + i, buffer, index, (cbSize - i)); } - private static void HashFinal(Span state, Span count, Span destination, Span buffer) - { - /* Save number of bits */ - Span bits = stackalloc byte[8]; - Encode(bits, count); - - /* Pad out to 56 mod 64. */ - uint index = ((count[0] >> 3) & 0x3f); - int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); - Span padding = stackalloc byte[padLen]; - padding[0] = 0x80; - HashCore(padding, 0, padLen, state, count, buffer); - - /* Append length (before padding) */ - HashCore(bits, 0, 8, state, count, buffer); - - /* Store state in digest */ - Encode(destination, state); - } + // private static void HashFinal(Span state, Span count, Span destination, Span buffer) + // { + // /* Save number of bits */ + // Span bits = stackalloc byte[8]; + // Encode(bits, count); + + // /* Pad out to 56 mod 64. */ + // uint index = ((count[0] >> 3) & 0x3f); + // int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); + // Span padding = stackalloc byte[padLen]; + // padding[0] = 0x80; + // HashCore(padding, 0, padLen, state, count, buffer); + + // /* Append length (before padding) */ + // HashCore(bits, 0, 8, state, count, buffer); + + // /* Store state in digest */ + // Encode(destination, state); + // } //--- private methods --------------------------------------------------- From 64628857186cba61771a9a76580153de3e8fa28d Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 16:15:30 +0300 Subject: [PATCH 25/40] Clean up --- .../src/System/Net/Security/MD4.cs | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index cb83092dff630e..95921eab3128ea 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -95,26 +95,6 @@ private static void HashCore(ReadOnlySpan input, int ibStart, int cbSize, BlockCopy(input, ibStart + i, buffer, index, (cbSize - i)); } - // private static void HashFinal(Span state, Span count, Span destination, Span buffer) - // { - // /* Save number of bits */ - // Span bits = stackalloc byte[8]; - // Encode(bits, count); - - // /* Pad out to 56 mod 64. */ - // uint index = ((count[0] >> 3) & 0x3f); - // int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); - // Span padding = stackalloc byte[padLen]; - // padding[0] = 0x80; - // HashCore(padding, 0, padLen, state, count, buffer); - - // /* Append length (before padding) */ - // HashCore(bits, 0, 8, state, count, buffer); - - // /* Store state in digest */ - // Encode(destination, state); - // } - //--- private methods --------------------------------------------------- private static void BlockCopy(ReadOnlySpan source, int srcOffset, Span destination, int dstOffset, int count) From 002fdd08ccd6b6a501ae72301564b9700c8e2e1f Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 17 Jan 2022 16:58:48 +0300 Subject: [PATCH 26/40] Update the tests --- .../tests/InternalUnitTests/MD4Tests.cs | 71 +++++++++---------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs index 8e0ff390f12c43..645c4d3cad7805 100644 --- a/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs +++ b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs @@ -13,79 +13,72 @@ public class MD4Tests { // MD4("") = 31d6cfe0d16ae931b73c59d7e0c089c0 [Fact] - public void TryEncrypt_Empty() + public void TryEncrypt_Empty() { - MD4 hash = new MD4(); - byte[] input = new byte[0]; - byte[] expected = { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 }; - Verify(hash, input, expected); + ReadOnlySpan input = new byte[0]; + ReadOnlySpan expected = new byte[] { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 }; + Verify(input, expected); } // // MD4("a") = bde52cb31de33e46245e05fbdbd6fb24 [Fact] - public void TryEncrypt_SingleLetter() + public void TryEncrypt_SingleLetter() { - MD4 hash = new MD4(); - byte[] expected = { 0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24 }; - byte[] input = Encoding.Default.GetBytes("a"); - Verify(hash, input, expected); + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("a")); + ReadOnlySpan expected = new byte[] { 0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24 }; + Verify(input, expected); } // MD4("abc") = a448017aaf21d8525fc10ae87aa6729d [Fact] - public void TryEncrypt_ThreeLetters() + public void TryEncrypt_ThreeLetters() { - MD4 hash = new MD4(); - byte[] expected = { 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d }; - byte[] input = Encoding.Default.GetBytes("abc"); - Verify(hash, input, expected); + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("abc")); + ReadOnlySpan expected = new byte[] { 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d }; + Verify(input, expected); } // MD4("message digest") = d9130a8164549fe818874806e1c7014b [Fact] - public void TryEncrypt_Phrase() + public void TryEncrypt_Phrase() { - MD4 hash = new MD4(); - byte[] expected = { 0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b }; - byte[] input = Encoding.Default.GetBytes("message digest"); - Verify(hash, input, expected); + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("message digest")); + ReadOnlySpan expected = new byte[] { 0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b }; + Verify(input, expected); } // MD4("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9 [Fact] - public void TryEncrypt_AlphabetInLowercase() + public void TryEncrypt_AlphabetInLowercase() { - MD4 hash = new MD4(); - byte[] expected = { 0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9 }; - byte[] input = Encoding.Default.GetBytes("abcdefghijklmnopqrstuvwxyz"); - Verify(hash, input, expected); + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("abcdefghijklmnopqrstuvwxyz")); + ReadOnlySpan expected = new byte[] { 0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9 }; + Verify(input, expected); } // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = 043f8582f241db351ce627e153e7f0e4 [Fact] - public void TryEncrypt_AlphabetInUpperLowerCasesAndNumbers() + public void TryEncrypt_AlphabetInUpperLowerCasesAndNumbers() { - MD4 hash = new MD4(); - byte[] expected = { 0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4 }; - byte[] input = Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); - Verify(hash, input, expected); + ReadOnlySpan input = new ReadOnlySpan((Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"))); + ReadOnlySpan expected = new byte[] { 0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4 }; + Verify(input, expected); } // MD4("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536 [Fact] - public void TryEncrypt_RepeatedSequenceOfNumbers() + public void TryEncrypt_RepeatedSequenceOfNumbers() { - MD4 hash = new MD4(); - byte[] expected = { 0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36 }; - byte[] input = Encoding.Default.GetBytes("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); - Verify(hash, input, expected); + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("12345678901234567890123456789012345678901234567890123456789012345678901234567890")); + ReadOnlySpan expected = new byte[] { 0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36 }; + Verify(input, expected); } - private void Verify(MD4 hash, byte[] input, byte[] expected) + private void Verify(ReadOnlySpan input, ReadOnlySpan expected) { - byte[] outputSpan = new byte[expected.Length]; - MD4.HashData(input, outputSpan); - Assert.Equal(expected, outputSpan); + Span output = stackalloc byte[expected.Length]; + MD4.HashData(input, output); + Assert.Equal(expected.ToArray(), output.ToArray()); } } } From 1d166b8f066b204c9f872a13e45c2c5b56617a48 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Wed, 19 Jan 2022 11:53:16 +0300 Subject: [PATCH 27/40] Remove redundant parameters --- .../src/System/Net/Security/MD4.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 95921eab3128ea..1293caf69a8753 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -45,7 +45,7 @@ internal static void HashData(ReadOnlySpan source, Span destination) // Zeroize sensitive information buffer.Fill(0); - HashCore(source, 0, source.Length, state, count, buffer); + HashCore(source, state, count, buffer); /* Save number of bits */ Span bits = stackalloc byte[8]; @@ -56,43 +56,43 @@ internal static void HashData(ReadOnlySpan source, Span destination) int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); Span padding = stackalloc byte[padLen]; padding[0] = 0x80; - HashCore(padding, 0, padLen, state, count, buffer); + HashCore(padding, state, count, buffer); /* Append length (before padding) */ - HashCore(bits, 0, 8, state, count, buffer); + HashCore(bits, state, count, buffer); /* Write state to destination */ Encode(destination, state); } - private static void HashCore(ReadOnlySpan input, int ibStart, int cbSize, Span state, Span count, Span buffer) + private static void HashCore(ReadOnlySpan input, Span state, Span count, Span buffer) { /* Compute number of bytes mod 64 */ int index = (int)((count[0] >> 3) & 0x3F); /* Update number of bits */ - count[0] += (uint)(cbSize << 3); - if (count[0] < (cbSize << 3)) + count[0] += (uint)(input.Length << 3); + if (count[0] < (input.Length << 3)) count[1]++; - count[1] += (uint)(cbSize >> 29); + count[1] += (uint)(input.Length >> 29); int partLen = 64 - index; int i = 0; /* Transform as many times as possible. */ - if (cbSize >= partLen) + if (input.Length >= partLen) { - BlockCopy(input, ibStart, buffer, index, partLen); + BlockCopy(input, 0, buffer, index, partLen); MD4Transform(state, buffer, 0); - for (i = partLen; i + 63 < cbSize; i += 64) + for (i = partLen; i + 63 < input.Length; i += 64) { - MD4Transform(state, input, ibStart + i); + MD4Transform(state, input, i); } index = 0; } /* Buffer remaining input */ - BlockCopy(input, ibStart + i, buffer, index, (cbSize - i)); + BlockCopy(input, i, buffer, index, (input.Length - i)); } //--- private methods --------------------------------------------------- From 980272d9c370f440810926817c8ac5024ded4c28 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Wed, 19 Jan 2022 12:05:56 +0300 Subject: [PATCH 28/40] Use Span's Slice+CopyTo methods --- .../System.Net.Security/src/System/Net/Security/MD4.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 1293caf69a8753..9b17b351d1adb8 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -92,7 +92,7 @@ private static void HashCore(ReadOnlySpan input, Span state, Span Date: Wed, 19 Jan 2022 13:13:43 +0300 Subject: [PATCH 29/40] Use BinaryPrimitives.ReadUInt32LittleEndian when decoding --- .../System.Net.Security/src/System/Net/Security/MD4.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 9b17b351d1adb8..52c3a12b494ada 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -159,7 +159,7 @@ private static void Decode(Span output, ReadOnlySpan input, int inde { for (int i = 0, j = index; i < output.Length; i++, j += 4) { - output[i] = (uint)((input[j]) | (input[j + 1] << 8) | (input[j + 2] << 16) | (input[j + 3] << 24)); + output[i] = BinaryPrimitives.ReadUInt32LittleEndian(input.Slice(j)); } } From 9b993fb1b79b2b646949c89fea25dafc8ca8e0fe Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Wed, 19 Jan 2022 13:22:24 +0300 Subject: [PATCH 30/40] Use BitOperations.RotateLeft instead of a custom method --- .../src/System/Net/Security/MD4.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 52c3a12b494ada..3b5074218a80f2 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -4,6 +4,7 @@ using System.Buffers.Binary; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Numerics; // // This class is a port of the Mono managed implementation of the MD4 algorithm @@ -121,30 +122,24 @@ private static uint H(uint x, uint y, uint z) return (uint)((x) ^ (y) ^ (z)); } - /* ROTATE_LEFT rotates x left n bits. */ - private static uint ROL(uint x, byte n) - { - return (uint)(((x) << (n)) | ((x) >> (32 - (n)))); - } - /* FF, GG and HH are transformations for rounds 1, 2 and 3 */ /* Rotation is separate from addition to prevent recomputation */ private static void FF(ref uint a, uint b, uint c, uint d, uint x, byte s) { a += F(b, c, d) + x; - a = ROL(a, s); + a = BitOperations.RotateLeft(a, s); } private static void GG(ref uint a, uint b, uint c, uint d, uint x, byte s) { a += G(b, c, d) + x + 0x5a827999; - a = ROL(a, s); + a = BitOperations.RotateLeft(a, s); } private static void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) { a += H(b, c, d) + x + 0x6ed9eba1; - a = ROL(a, s); + a = BitOperations.RotateLeft(a, s); } private static void Encode(Span output, Span input) From 31cc0b53ebef4e8980904b96ed3dc654b0bf432e Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Wed, 19 Jan 2022 13:37:38 +0300 Subject: [PATCH 31/40] Remove redundant parameter --- .../src/System/Net/Security/MD4.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 3b5074218a80f2..ccb0d45e977c0a 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -82,11 +82,11 @@ private static void HashCore(ReadOnlySpan input, Span state, Span= partLen) { BlockCopy(input, 0, buffer, index, partLen); - MD4Transform(state, buffer, 0); + MD4Transform(state, buffer); for (i = partLen; i + 63 < input.Length; i += 64) { - MD4Transform(state, input, i); + MD4Transform(state, input.Slice(i)); } index = 0; @@ -150,15 +150,15 @@ private static void Encode(Span output, Span input) } } - private static void Decode(Span output, ReadOnlySpan input, int index) + private static void Decode(Span output, ReadOnlySpan input) { - for (int i = 0, j = index; i < output.Length; i++, j += 4) + for (int i = 0, j = 0; i < output.Length; i++, j += 4) { output[i] = BinaryPrimitives.ReadUInt32LittleEndian(input.Slice(j)); } } - private static void MD4Transform(Span state, ReadOnlySpan block, int index) + private static void MD4Transform(Span state, ReadOnlySpan block) { uint a = state[0]; uint b = state[1]; @@ -166,7 +166,7 @@ private static void MD4Transform(Span state, ReadOnlySpan block, int uint d = state[3]; Span x = stackalloc uint[16]; - Decode(x, block, index); + Decode(x, block); /* Round 1 */ FF(ref a, b, c, d, x[0], S11); /* 1 */ From e1071c87e427d05d9d602a2af391af13a91adfc7 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 21 Jan 2022 11:52:13 +0300 Subject: [PATCH 32/40] Add more test cases --- .../tests/InternalUnitTests/MD4Tests.cs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs index 645c4d3cad7805..a3667ebb896e54 100644 --- a/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs +++ b/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs @@ -74,6 +74,80 @@ public void TryEncrypt_RepeatedSequenceOfNumbers() Verify(input, expected); } + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012") = 14fdf2056bf88b3491c385d8ac4f48e6 + // 55 bytes (padLen == 56 - 55 => 1) + [Fact] + public void TryEncrypt_55bytes_HitsEdgeCaseForPaddingLength() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012")); + ReadOnlySpan expected = new byte[] { 0x14, 0xfd, 0xf2, 0x05, 0x6b, 0xf8, 0x8b, 0x34, 0x91, 0xc3, 0x85, 0xd8, 0xac, 0x4f, 0x48, 0xe6 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123") = db837dbb6098a50a2d3974bc1cc76133 + // 56 bytes (padLen == 120 - 56 => 64) + [Fact] + public void TryEncrypt_56bytes_HitsEdgeCaseForPaddingLength() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123")); + ReadOnlySpan expected = new byte[] { 0xdb, 0x83, 0x7d, 0xbb, 0x60, 0x98, 0xa5, 0x0a, 0x2d, 0x39, 0x74, 0xbc, 0x1c, 0xc7, 0x61, 0x33 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890") = ce64c40ecfbe896462f3c1a925884624 + [Fact] + public void TryEncrypt_63bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890")); + ReadOnlySpan expected = new byte[] { 0xce, 0x64, 0xc4, 0x0e, 0xcf, 0xbe, 0x89, 0x64, 0x62, 0xf3, 0xc1, 0xa9, 0x25, 0x88, 0x46, 0x24 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901") = 4b0e77758d2ede1eb21d267d492ae70b + [Fact] + public void TryEncrypt_64bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901")); + ReadOnlySpan expected = new byte[] { 0x4b, 0x0e, 0x77, 0x75, 0x8d, 0x2e, 0xde, 0x1e, 0xb2, 0x1d, 0x26, 0x7d, 0x49, 0x2a, 0xe7, 0x0b }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789012") = 3b46ad159b3fd800d254e3c4cc71fe36 + [Fact] + public void TryEncrypt_65bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789012")); + ReadOnlySpan expected = new byte[] { 0x3b, 0x46, 0xad, 0x15, 0x9b, 0x3f, 0xd8, 0x00, 0xd2, 0x54, 0xe3, 0xc4, 0xcc, 0x71, 0xfe, 0x36 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890") = a3e23048e4ade47a0f00fa8aed2a0248 + [Fact] + public void TryEncrypt_127bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890")); + ReadOnlySpan expected = new byte[] { 0xa3, 0xe2, 0x30, 0x48, 0xe4, 0xad, 0xe4, 0x7a, 0x0f, 0x00, 0xfa, 0x8a, 0xed, 0x2a, 0x02, 0x48 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901") = de49da96c105be37b242f2bee86c4759 + [Fact] + public void TryEncrypt_128bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901")); + ReadOnlySpan expected = new byte[] { 0xde, 0x49, 0xda, 0x96, 0xc1, 0x05, 0xbe, 0x37, 0xb2, 0x42, 0xf2, 0xbe, 0xe8, 0x6c, 0x47, 0x59 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789012") = a6c10c320f8827d08248a2d8b124b040 + [Fact] + public void TryEncrypt_129bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789012")); + ReadOnlySpan expected = new byte[] { 0xa6, 0xc1, 0x0c, 0x32, 0x0f, 0x88, 0x27, 0xd0, 0x82, 0x48, 0xa2, 0xd8, 0xb1, 0x24, 0xb0, 0x40 }; + Verify(input, expected); + } + private void Verify(ReadOnlySpan input, ReadOnlySpan expected) { Span output = stackalloc byte[expected.Length]; From 42afb5bbbe96e73e6ebf78b65c47c737422586f1 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 21 Jan 2022 12:10:55 +0300 Subject: [PATCH 33/40] Inline/remove the BlockCopy method --- .../System.Net.Security/src/System/Net/Security/MD4.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index ccb0d45e977c0a..2e8b85628b7918 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -81,7 +81,7 @@ private static void HashCore(ReadOnlySpan input, Span state, Span= partLen) { - BlockCopy(input, 0, buffer, index, partLen); + input.Slice(0, partLen).CopyTo(buffer.Slice(index)); MD4Transform(state, buffer); for (i = partLen; i + 63 < input.Length; i += 64) @@ -98,14 +98,6 @@ private static void HashCore(ReadOnlySpan input, Span state, Span source, int srcOffset, Span destination, int dstOffset, int count) - { - for (int srcIndex = srcOffset, dstIndex = dstOffset; srcIndex < srcOffset + count; srcIndex++, dstIndex++) - { - destination[dstIndex] = source[srcIndex]; - } - } - /* F, G and H are basic MD4 functions. */ private static uint F(uint x, uint y, uint z) { From 133f71d6884989856c0e14ee6ed4721e31fff4e6 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 21 Jan 2022 13:57:46 +0300 Subject: [PATCH 34/40] Preserve the license header from Mono implementation --- .../src/System/Net/Security/MD4.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 2e8b85628b7918..d4253b2223f02a 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -1,6 +1,37 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// +// MD4.cs - Message Digest 4 Abstract class +// +// Author: +// Sebastien Pouliot (sebastien@xamarin.com) +// +// (C) 2003 Motus Technologies Inc. (http://www.motus.com) +// Copyright 2013 Xamarin Inc. (http://www.xamarin.com) +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + using System.Buffers.Binary; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; From a42224b3e91ec1e29cff729e10b7beaadb0d9d79 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 21 Jan 2022 14:51:38 +0300 Subject: [PATCH 35/40] Fix spaces issue --- .../System.Net.Security/src/System/Net/Security/MD4.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index d4253b2223f02a..305e2efe164df8 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -5,7 +5,7 @@ // MD4.cs - Message Digest 4 Abstract class // // Author: -// Sebastien Pouliot (sebastien@xamarin.com) +// Sebastien Pouliot (sebastien@xamarin.com) // // (C) 2003 Motus Technologies Inc. (http://www.motus.com) // Copyright 2013 Xamarin Inc. (http://www.xamarin.com) @@ -19,10 +19,10 @@ // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND From 4723c99aaab8cdfb5adf4ba4a10fe5f819dbd22d Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 21 Jan 2022 14:53:49 +0300 Subject: [PATCH 36/40] Skip the block copying when it's unnecessary --- .../src/System/Net/Security/MD4.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index 305e2efe164df8..d64f1652b0c050 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -112,15 +112,21 @@ private static void HashCore(ReadOnlySpan input, Span state, Span= partLen) { - input.Slice(0, partLen).CopyTo(buffer.Slice(index)); - MD4Transform(state, buffer); + if (index != 0) + { + input.Slice(0, partLen).CopyTo(buffer.Slice(index)); + MD4Transform(state, buffer); + index = 0; + } + else + { + partLen = 0; + } for (i = partLen; i + 63 < input.Length; i += 64) { MD4Transform(state, input.Slice(i)); } - - index = 0; } /* Buffer remaining input */ From 0f0b8ecfdf0aa7331b5d0b4c21ecf5b2c294dde4 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 21 Jan 2022 15:16:25 +0300 Subject: [PATCH 37/40] Move the MD4 tests over to System.Net.Security.Unit.Tests project --- .../System.Net.Security.InternalUnit.Tests.csproj | 9 --------- .../tests/{InternalUnitTests => UnitTests}/MD4Tests.cs | 0 .../UnitTests/System.Net.Security.Unit.Tests.csproj | 6 +++++- 3 files changed, 5 insertions(+), 10 deletions(-) delete mode 100644 src/libraries/System.Net.Security/tests/InternalUnitTests/System.Net.Security.InternalUnit.Tests.csproj rename src/libraries/System.Net.Security/tests/{InternalUnitTests => UnitTests}/MD4Tests.cs (100%) diff --git a/src/libraries/System.Net.Security/tests/InternalUnitTests/System.Net.Security.InternalUnit.Tests.csproj b/src/libraries/System.Net.Security/tests/InternalUnitTests/System.Net.Security.InternalUnit.Tests.csproj deleted file mode 100644 index 07b426375b59e1..00000000000000 --- a/src/libraries/System.Net.Security/tests/InternalUnitTests/System.Net.Security.InternalUnit.Tests.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - $(NetCoreAppCurrent)-Android - - - - - - diff --git a/src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs b/src/libraries/System.Net.Security/tests/UnitTests/MD4Tests.cs similarity index 100% rename from src/libraries/System.Net.Security/tests/InternalUnitTests/MD4Tests.cs rename to src/libraries/System.Net.Security/tests/UnitTests/MD4Tests.cs diff --git a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj index da4dde4e192b90..28b3f81b02b3d7 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj @@ -10,13 +10,17 @@ 436 $(NoWarn);3021 - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-Android annotations true + + + + From 589d3edd306131ef1fb34bdd016b62e31b5d1fdc Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 21 Jan 2022 15:19:13 +0300 Subject: [PATCH 38/40] Revert redundant change --- .../tests/FunctionalTests/System.Net.Security.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index 0a67a21757a52b..a6a21cc91e155b 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -2,7 +2,7 @@ true true - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-Android + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS annotations true true From 2bfb2b6ab783c1769bb6fbc9e5a7288c3f100cad Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Fri, 21 Jan 2022 15:21:26 +0300 Subject: [PATCH 39/40] Revert adding a temp test suite to the smoke tests section --- src/libraries/tests.proj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 12de84677116a3..8d6a97b157d41a 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -356,9 +356,6 @@ Roslyn4.0.Tests.csproj" /> - - - Date: Sun, 23 Jan 2022 10:08:21 +0300 Subject: [PATCH 40/40] Address Stephen's feedback --- .../src/System/Net/Security/MD4.cs | 143 +++++++++--------- 1 file changed, 70 insertions(+), 73 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs index d64f1652b0c050..bdf3547912c911 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -63,53 +63,50 @@ internal sealed class MD4 internal static void HashData(ReadOnlySpan source, Span destination) { Debug.Assert(destination.Length == 128 >> 3); - Span buffer = stackalloc byte[64]; - Span state = stackalloc uint[4]; - Span count = stackalloc uint[2]; - // the initialize our context - count[0] = 0; - count[1] = 0; - state[0] = 0x67452301; - state[1] = 0xefcdab89; - state[2] = 0x98badcfe; - state[3] = 0x10325476; - // Zeroize sensitive information - buffer.Fill(0); + Span buffer = stackalloc byte[64]; + buffer.Clear(); + // Initialize the context + Span state = stackalloc uint[4] { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + Span count = stackalloc uint[2] { 0, 0 }; HashCore(source, state, count, buffer); - /* Save number of bits */ + // Save number of bits Span bits = stackalloc byte[8]; Encode(bits, count); - /* Pad out to 56 mod 64. */ + // Pad out to 56 mod 64 uint index = ((count[0] >> 3) & 0x3f); int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); Span padding = stackalloc byte[padLen]; + padding.Clear(); padding[0] = 0x80; HashCore(padding, state, count, buffer); - /* Append length (before padding) */ + // Append length (before padding) HashCore(bits, state, count, buffer); - /* Write state to destination */ + // Write state to destination Encode(destination, state); } private static void HashCore(ReadOnlySpan input, Span state, Span count, Span buffer) { - /* Compute number of bytes mod 64 */ + // Compute number of bytes mod 64 int index = (int)((count[0] >> 3) & 0x3F); - /* Update number of bits */ + // Update number of bits count[0] += (uint)(input.Length << 3); if (count[0] < (input.Length << 3)) + { count[1]++; + } + count[1] += (uint)(input.Length >> 29); int partLen = 64 - index; int i = 0; - /* Transform as many times as possible. */ + // Transform as many times as possible. if (input.Length >= partLen) { if (index != 0) @@ -129,13 +126,13 @@ private static void HashCore(ReadOnlySpan input, Span state, Span state, ReadOnlySpan block) Decode(x, block); - /* Round 1 */ - FF(ref a, b, c, d, x[0], S11); /* 1 */ - FF(ref d, a, b, c, x[1], S12); /* 2 */ - FF(ref c, d, a, b, x[2], S13); /* 3 */ - FF(ref b, c, d, a, x[3], S14); /* 4 */ - FF(ref a, b, c, d, x[4], S11); /* 5 */ - FF(ref d, a, b, c, x[5], S12); /* 6 */ - FF(ref c, d, a, b, x[6], S13); /* 7 */ - FF(ref b, c, d, a, x[7], S14); /* 8 */ - FF(ref a, b, c, d, x[8], S11); /* 9 */ - FF(ref d, a, b, c, x[9], S12); /* 10 */ - FF(ref c, d, a, b, x[10], S13); /* 11 */ - FF(ref b, c, d, a, x[11], S14); /* 12 */ - FF(ref a, b, c, d, x[12], S11); /* 13 */ - FF(ref d, a, b, c, x[13], S12); /* 14 */ - FF(ref c, d, a, b, x[14], S13); /* 15 */ - FF(ref b, c, d, a, x[15], S14); /* 16 */ + // Round 1 + FF(ref a, b, c, d, x[0], S11); // 1 + FF(ref d, a, b, c, x[1], S12); // 2 + FF(ref c, d, a, b, x[2], S13); // 3 + FF(ref b, c, d, a, x[3], S14); // 4 + FF(ref a, b, c, d, x[4], S11); // 5 + FF(ref d, a, b, c, x[5], S12); // 6 + FF(ref c, d, a, b, x[6], S13); // 7 + FF(ref b, c, d, a, x[7], S14); // 8 + FF(ref a, b, c, d, x[8], S11); // 9 + FF(ref d, a, b, c, x[9], S12); // 10 + FF(ref c, d, a, b, x[10], S13); // 11 + FF(ref b, c, d, a, x[11], S14); // 12 + FF(ref a, b, c, d, x[12], S11); // 13 + FF(ref d, a, b, c, x[13], S12); // 14 + FF(ref c, d, a, b, x[14], S13); // 15 + FF(ref b, c, d, a, x[15], S14); // 16 - /* Round 2 */ - GG(ref a, b, c, d, x[0], S21); /* 17 */ - GG(ref d, a, b, c, x[4], S22); /* 18 */ - GG(ref c, d, a, b, x[8], S23); /* 19 */ - GG(ref b, c, d, a, x[12], S24); /* 20 */ - GG(ref a, b, c, d, x[1], S21); /* 21 */ - GG(ref d, a, b, c, x[5], S22); /* 22 */ - GG(ref c, d, a, b, x[9], S23); /* 23 */ - GG(ref b, c, d, a, x[13], S24); /* 24 */ - GG(ref a, b, c, d, x[2], S21); /* 25 */ - GG(ref d, a, b, c, x[6], S22); /* 26 */ - GG(ref c, d, a, b, x[10], S23); /* 27 */ - GG(ref b, c, d, a, x[14], S24); /* 28 */ - GG(ref a, b, c, d, x[3], S21); /* 29 */ - GG(ref d, a, b, c, x[7], S22); /* 30 */ - GG(ref c, d, a, b, x[11], S23); /* 31 */ - GG(ref b, c, d, a, x[15], S24); /* 32 */ + // Round 2 + GG(ref a, b, c, d, x[0], S21); // 17 + GG(ref d, a, b, c, x[4], S22); // 18 + GG(ref c, d, a, b, x[8], S23); // 19 + GG(ref b, c, d, a, x[12], S24); // 20 + GG(ref a, b, c, d, x[1], S21); // 21 + GG(ref d, a, b, c, x[5], S22); // 22 + GG(ref c, d, a, b, x[9], S23); // 23 + GG(ref b, c, d, a, x[13], S24); // 24 + GG(ref a, b, c, d, x[2], S21); // 25 + GG(ref d, a, b, c, x[6], S22); // 26 + GG(ref c, d, a, b, x[10], S23); // 27 + GG(ref b, c, d, a, x[14], S24); // 28 + GG(ref a, b, c, d, x[3], S21); // 29 + GG(ref d, a, b, c, x[7], S22); // 30 + GG(ref c, d, a, b, x[11], S23); // 31 + GG(ref b, c, d, a, x[15], S24); // 32 - HH(ref a, b, c, d, x[0], S31); /* 33 */ - HH(ref d, a, b, c, x[8], S32); /* 34 */ - HH(ref c, d, a, b, x[4], S33); /* 35 */ - HH(ref b, c, d, a, x[12], S34); /* 36 */ - HH(ref a, b, c, d, x[2], S31); /* 37 */ - HH(ref d, a, b, c, x[10], S32); /* 38 */ - HH(ref c, d, a, b, x[6], S33); /* 39 */ - HH(ref b, c, d, a, x[14], S34); /* 40 */ - HH(ref a, b, c, d, x[1], S31); /* 41 */ - HH(ref d, a, b, c, x[9], S32); /* 42 */ - HH(ref c, d, a, b, x[5], S33); /* 43 */ - HH(ref b, c, d, a, x[13], S34); /* 44 */ - HH(ref a, b, c, d, x[3], S31); /* 45 */ - HH(ref d, a, b, c, x[11], S32); /* 46 */ - HH(ref c, d, a, b, x[7], S33); /* 47 */ - HH(ref b, c, d, a, x[15], S34); /* 48 */ + HH(ref a, b, c, d, x[0], S31); // 33 + HH(ref d, a, b, c, x[8], S32); // 34 + HH(ref c, d, a, b, x[4], S33); // 35 + HH(ref b, c, d, a, x[12], S34); // 36 + HH(ref a, b, c, d, x[2], S31); // 37 + HH(ref d, a, b, c, x[10], S32); // 38 + HH(ref c, d, a, b, x[6], S33); // 39 + HH(ref b, c, d, a, x[14], S34); // 40 + HH(ref a, b, c, d, x[1], S31); // 41 + HH(ref d, a, b, c, x[9], S32); // 42 + HH(ref c, d, a, b, x[5], S33); // 43 + HH(ref b, c, d, a, x[13], S34); // 44 + HH(ref a, b, c, d, x[3], S31); // 45 + HH(ref d, a, b, c, x[11], S32); // 46 + HH(ref c, d, a, b, x[7], S33); // 47 + HH(ref b, c, d, a, x[15], S34); // 48 state[0] += a; state[1] += b;