Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 99 additions & 34 deletions src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -17,20 +19,77 @@ internal struct Sha1ForNonSecretPurposes
private uint[] _w; // Workspace
private int _pos; // Length of current chunk in bytes

/// <summary>
/// Computes the SHA1 hash of the provided data.
/// </summary>
/// <param name="source">The data to hash.</param>
/// <param name="destination">The buffer to receive the hash value.</param>
public static void HashData(ReadOnlySpan<byte> source, Span<byte> destination)
{
Debug.Assert(destination.Length == 20);

Span<uint> 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<byte> 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);
}
}

/// <summary>
/// Call Start() to initialize the hash object.
/// </summary>
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<uint> w)
{
w[80] = 0x67452301;
w[81] = 0xEFCDAB89;
w[82] = 0x98BADCFE;
w[83] = 0x10325476;
w[84] = 0xC3D2E1F0;
}

/// <summary>
Expand Down Expand Up @@ -77,6 +136,8 @@ public void Append(ReadOnlySpan<byte> input)
/// </param>
public void Finish(Span<byte> output)
{
Debug.Assert(output.Length == 20);

long l = _length + 8 * _pos;
Append(0x80);
while (_pos != 56)
Expand All @@ -93,12 +154,10 @@ public void Finish(Span<byte> 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);
}
}

Expand All @@ -107,53 +166,59 @@ public void Finish(Span<byte> output)
/// </summary>
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<uint> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> source = totalLength <= 256 ? stackalloc byte[totalLength] : new byte[totalLength];

namespaceBytes.CopyTo(source);
Encoding.BigEndianUnicode.GetBytes(name, source.Slice(namespaceBytes.Length));

Span<byte> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ internal static partial class AssemblyNameHelpers
throw new SecurityException(SR.Security_InvalidAssemblyPublicKey);

Span<byte> 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++)
Expand Down
Loading