diff --git a/src/Microsoft.TestPlatform.ObjectModel/Utilities/EqtHash.cs b/src/Microsoft.TestPlatform.ObjectModel/Utilities/EqtHash.cs index ef595cffb5..57f2bbb958 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Utilities/EqtHash.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Utilities/EqtHash.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Security.Cryptography; using Microsoft.VisualStudio.TestPlatform.CoreUtilities; @@ -27,7 +28,8 @@ public static Guid GuidFromString(string data) // Any algorithm or logic change must require a sign off from feature owners of above // Also, TPV2 and TPV1 must use same Algorithm until the time TPV1 is completely deleted to be on-par // If LUT or .Net core scenario uses TPV2 to discover, but if it uses TPV1 in Devenv, then there will be testcase matching issues - byte[] hash = Sha1Helper.ComputeSha1(System.Text.Encoding.Unicode.GetBytes(data)); + using HashAlgorithm provider = SHA1.Create(); + byte[] hash = provider.ComputeHash(System.Text.Encoding.Unicode.GetBytes(data)); // Guid is always 16 bytes TPDebug.Assert(Guid.Empty.ToByteArray().Length == 16, "Expected Guid to be 16 bytes"); diff --git a/src/Microsoft.TestPlatform.ObjectModel/Utilities/Sha1Helper.cs b/src/Microsoft.TestPlatform.ObjectModel/Utilities/Sha1Helper.cs deleted file mode 100644 index 7b2a249fa3..0000000000 --- a/src/Microsoft.TestPlatform.ObjectModel/Utilities/Sha1Helper.cs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Security.Cryptography; - -namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; - -/// -/// Used to calculate SHA1 hash. -/// -/// https://tools.ietf.org/html/rfc3174 -/// -internal static class Sha1Helper -{ - public static byte[] ComputeSha1(byte[] message) - { - using HashAlgorithm provider = SHA1.Create(); - byte[] hash = provider.ComputeHash(message); - - return hash; - } - - /// - /// SHA-1 Implementation as in https://tools.ietf.org/html/rfc3174 - /// - /// - /// This implementation only works with messages with a length - /// that is a multiple of the size of 8-bits. - /// - internal class Sha1Implementation - { - /* - * Many of the variable, function and parameter names in this code - * were used because those were the names used in the publication. - * - * For more information please refer to https://tools.ietf.org/html/rfc3174. - */ - - private const int BlockBits = 512; - private const int DigestBits = 160; - private const int BlockBytes = BlockBits / 8; - private const int DigestBytes = DigestBits / 8; - - /// - /// A sequence of logical functions to be used in SHA-1. - /// Each f(t), 0 <= t <= 79, operates on three 32-bit words B, C, D and produces a 32-bit word as output. - /// - /// Function index. 0 <= t <= 79 - /// Word B - /// Word C - /// Word D - /// - /// f(t;B,C,D) = (B AND C) OR ((NOT B) AND D) ( 0 <= t <= 19) - /// f(t;B,C,D) = B XOR C XOR D (20 <= t <= 39) - /// f(t;B,C,D) = (B AND C) OR (B AND D) OR (C AND D) (40 <= t <= 59) - /// f(t;B,C,D) = B XOR C XOR D (60 <= t <= 79) - /// - private static uint F(int t, uint b, uint c, uint d) - { - return t switch - { - >= 0 and <= 19 => b & c | ~b & d, - >= 20 and <= 39 or >= 60 and <= 79 => b ^ c ^ d, - _ => t is >= 40 and <= 59 - ? b & c | b & d | c & d - : throw new ArgumentException("Argument out of bounds! 0 <= t < 80", nameof(t)) - }; - } - - /// - /// Returns a constant word K(t) which is used in the SHA-1. - /// - /// Word index. - /// - /// K(t) = 0x5A827999 ( 0 <= t <= 19) - /// K(t) = 0x6ED9EBA1 (20 <= t <= 39) - /// K(t) = 0x8F1BBCDC (40 <= t <= 59) - /// K(t) = 0xCA62C1D6 (60 <= t <= 79) - /// - private static uint K(int t) - { - return t switch - { - >= 0 and <= 19 => 0x5A827999u, - >= 20 and <= 39 => 0x6ED9EBA1u, - >= 40 and <= 59 => 0x8F1BBCDCu, - _ => t is >= 60 and <= 79 - ? 0xCA62C1D6u - : throw new ArgumentException("Argument out of bounds! 0 <= t < 80", nameof(t)) - }; - } - - /// - /// The circular left shift operation. - /// - /// An uint word. - /// 0 <= n < 32 - /// S^n(X) = (X << n) OR (X >> 32-n) - private static uint S(uint x, byte n) - { - return n > 32 ? throw new ArgumentOutOfRangeException(nameof(n)) : (x << n) | (x >> (32 - n)); - } - - /// - /// Ensures that given bytes are in big endian notation. - /// - /// An array of bytes - private static void EnsureBigEndian(ref byte[] array) - { - ValidateArg.NotNull(array, nameof(array)); - - if (BitConverter.IsLittleEndian) - { - Array.Reverse(array); - } - } - - private readonly uint[] _h = new uint[5]; - - private void Reset() - { - // as defined in https://tools.ietf.org/html/rfc3174#section-6.1 - _h[0] = 0x67452301u; - _h[1] = 0xEFCDAB89u; - _h[2] = 0x98BADCFEu; - _h[3] = 0x10325476u; - _h[4] = 0xC3D2E1F0u; - } - - public byte[] ComputeHash(byte[] message) - { - ValidateArg.NotNull(message, nameof(message)); - - Reset(); - PadMessage(ref message); - - var messageCount = message.Length / BlockBytes; - for (var i = 0; i < messageCount; ++i) - { - ProcessBlock(message, i * BlockBytes, BlockBytes); - } - - var digest = new byte[DigestBytes]; - for (int t = 0; t < _h.Length; t++) - { - var hi = BitConverter.GetBytes(_h[t]); - EnsureBigEndian(ref hi); - - Buffer.BlockCopy(hi, 0, digest, t * hi.Length, hi.Length); - } - - return digest; - } - - private static void PadMessage(ref byte[] message) - { - var length = message.Length; - var paddingBytes = BlockBytes - (length % BlockBytes); - - // 64bit uint message size will be appended to end of the padding, making sure we have space for it. - if (paddingBytes <= 8) - paddingBytes += BlockBytes; - - var padding = new byte[paddingBytes]; - padding[0] = 0b10000000; - - var messageBits = (ulong)message.Length << 3; - var messageSize = BitConverter.GetBytes(messageBits); - EnsureBigEndian(ref messageSize); - - Buffer.BlockCopy(messageSize, 0, padding, padding.Length - messageSize.Length, messageSize.Length); - - Array.Resize(ref message, message.Length + padding.Length); - Buffer.BlockCopy(padding, 0, message, length, padding.Length); - } - - private void ProcessBlock(byte[] message, int start, int length) - { - if (start + length > message.Length) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } - if (length != BlockBytes) - { - throw new ArgumentException($"Invalid block size. Actual: {length}, Expected: {BlockBytes}", nameof(length)); - } - - var w = new uint[80]; - - // Get W(0) .. W(15) - for (int t = 0; t <= 15; t++) - { - var wordBytes = new byte[sizeof(uint)]; - Buffer.BlockCopy(message, start + (t * sizeof(uint)), wordBytes, 0, sizeof(uint)); - EnsureBigEndian(ref wordBytes); - - w[t] = BitConverter.ToUInt32(wordBytes, 0); - } - - // Calculate W(16) .. W(79) - for (int t = 16; t <= 79; t++) - { - w[t] = S(w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16], 1); - } - - uint a = _h[0], - b = _h[1], - c = _h[2], - d = _h[3], - e = _h[4]; - - for (int t = 0; t < 80; t++) - { - var temp = S(a, 5) + F(t, b, c, d) + e + w[t] + K(t); - e = d; - d = c; - c = S(b, 30); - b = a; - a = temp; - } - - _h[0] += a; - _h[1] += b; - _h[2] += c; - _h[3] += d; - _h[4] += e; - } - } -}