diff --git a/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs b/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs index 77da6517345136..fa42ba627247e4 100644 --- a/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs +++ b/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs @@ -1,6 +1,8 @@ // 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.Numerics; namespace System @@ -17,20 +19,77 @@ internal struct Sha1ForNonSecretPurposes private uint[] _w; // Workspace private int _pos; // Length of current chunk in bytes + /// + /// Computes the SHA1 hash of the provided data. + /// + /// The data to hash. + /// The buffer to receive the hash value. + public static void HashData(ReadOnlySpan source, Span destination) + { + Debug.Assert(destination.Length == 20); + + Span w = stackalloc uint[85]; + + Start(w); + + int originalLength = source.Length; + + while (source.Length >= 64) + { + for (int i = 0; i < 16; i++) + { + w[i] = BinaryPrimitives.ReadUInt32BigEndian(source); + source = source.Slice(4); + } + Drain(w); + } + + Span tail = stackalloc byte[2 * 64]; + source.CopyTo(tail); + int pos = source.Length; + tail[pos++] = 0x80; + while ((pos & 63) != 56) + { + tail[pos++] = 0x00; + } + BinaryPrimitives.WriteUInt64BigEndian(tail.Slice(pos), (ulong)originalLength * 8); + tail = tail.Slice(0, pos + 8); + + while (tail.Length > 0) + { + for (int i = 0; i < 16; i++) + { + w[i] = BinaryPrimitives.ReadUInt32BigEndian(tail); + tail = tail.Slice(4); + } + Drain(w); + } + + for (int i = 80; i < w.Length; i++) + { + BinaryPrimitives.WriteUInt32BigEndian(destination, w[i]); + destination = destination.Slice(4); + } + } + /// /// Call Start() to initialize the hash object. /// public void Start() { - _w ??= new uint[85]; + Start(_w ??= new uint[85]); _length = 0; _pos = 0; - _w[80] = 0x67452301; - _w[81] = 0xEFCDAB89; - _w[82] = 0x98BADCFE; - _w[83] = 0x10325476; - _w[84] = 0xC3D2E1F0; + } + + private static void Start(Span w) + { + w[80] = 0x67452301; + w[81] = 0xEFCDAB89; + w[82] = 0x98BADCFE; + w[83] = 0x10325476; + w[84] = 0xC3D2E1F0; } /// @@ -77,6 +136,8 @@ public void Append(ReadOnlySpan input) /// public void Finish(Span output) { + Debug.Assert(output.Length == 20); + long l = _length + 8 * _pos; Append(0x80); while (_pos != 56) @@ -93,12 +154,10 @@ public void Finish(Span output) Append((byte)(l >> 8)); Append((byte)l); - int end = output.Length < 20 ? output.Length : 20; - for (int i = 0; i != end; i++) + for (int i = 80; i < _w.Length; i++) { - uint temp = _w[80 + i / 4]; - output[i] = (byte)(temp >> 24); - _w[80 + i / 4] = temp << 8; + BinaryPrimitives.WriteUInt32BigEndian(output, _w[i]); + output = output.Slice(4); } } @@ -107,53 +166,59 @@ public void Finish(Span output) /// private void Drain() { - for (int i = 16; i != 80; i++) + Drain(_w); + _length += 512; // 64 bytes == 512 bits + _pos = 0; + } + + private static void Drain(Span w) + { + var _ = w[84]; // Hint to eliminate bounds checks + + for (int i = 16; i < 80; i++) { - _w[i] = BitOperations.RotateLeft(_w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16], 1); + w[i] = BitOperations.RotateLeft(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); } - uint a = _w[80]; - uint b = _w[81]; - uint c = _w[82]; - uint d = _w[83]; - uint e = _w[84]; + uint a = w[80]; + uint b = w[81]; + uint c = w[82]; + uint d = w[83]; + uint e = w[84]; - for (int i = 0; i != 20; i++) + for (int i = 0; i < 20; i++) { const uint k = 0x5A827999; uint f = (b & c) | ((~b) & d); - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; } - for (int i = 20; i != 40; i++) + for (int i = 20; i < 40; i++) { uint f = b ^ c ^ d; const uint k = 0x6ED9EBA1; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; } - for (int i = 40; i != 60; i++) + for (int i = 40; i < 60; i++) { uint f = (b & c) | (b & d) | (c & d); const uint k = 0x8F1BBCDC; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; } - for (int i = 60; i != 80; i++) + for (int i = 60; i < 80; i++) { uint f = b ^ c ^ d; const uint k = 0xCA62C1D6; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; } - _w[80] += a; - _w[81] += b; - _w[82] += c; - _w[83] += d; - _w[84] += e; - - _length += 512; // 64 bytes == 512 bits - _pos = 0; + w[80] += a; + w[81] += b; + w[82] += c; + w[83] += d; + w[84] += e; } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index 91a6aed35d0d05..50c72800319882 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -1764,16 +1764,18 @@ private static Guid GenerateGuidFromName(string name) 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB, ]; - byte[] bytes = Encoding.BigEndianUnicode.GetBytes(name); - Sha1ForNonSecretPurposes hash = default; - hash.Start(); - hash.Append(namespaceBytes); - hash.Append(bytes); - Array.Resize(ref bytes, 16); - hash.Finish(bytes); + int nameByteCount = Encoding.BigEndianUnicode.GetByteCount(name); + int totalLength = namespaceBytes.Length + nameByteCount; + Span source = totalLength <= 256 ? stackalloc byte[totalLength] : new byte[totalLength]; + + namespaceBytes.CopyTo(source); + Encoding.BigEndianUnicode.GetBytes(name, source.Slice(namespaceBytes.Length)); + + Span bytes = stackalloc byte[20]; + Sha1ForNonSecretPurposes.HashData(source, bytes); bytes[7] = unchecked((byte)((bytes[7] & 0x0F) | 0x50)); // Set high 4 bits of octet 7 to 5, as per RFC 4122 - return new Guid(bytes); + return new Guid(bytes.Slice(0, 16)); } private static unsafe void DecodeObjects(object?[] decodedObjects, Type[] parameterTypes, EventData* data) diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs index 7fb7a668159566..d3e78dfabcb3ec 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs @@ -20,11 +20,7 @@ internal static partial class AssemblyNameHelpers throw new SecurityException(SR.Security_InvalidAssemblyPublicKey); Span hash = stackalloc byte[20]; - - Sha1ForNonSecretPurposes sha1 = default; - sha1.Start(); - sha1.Append(publicKey); - sha1.Finish(hash); + Sha1ForNonSecretPurposes.HashData(publicKey, hash); byte[] publicKeyToken = new byte[PublicKeyTokenLength]; for (int i = 0; i < publicKeyToken.Length; i++)