From 48e9cc5ee040382fb7152207f594f33313958ac6 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Thu, 27 Apr 2023 12:02:34 -0500 Subject: [PATCH] Avoid finalizable internal state for non-FIPS scenarios Fixes #67995 --- .../Workspace/Solution/Checksum_Factory.cs | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum_Factory.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum_Factory.cs index 019cdf401acbf..faa49769b3595 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum_Factory.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum_Factory.cs @@ -5,15 +5,14 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.IO; -using System.Security.Cryptography; using System.Runtime.InteropServices; +using System.Security.Cryptography; using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Serialization; using Roslyn.Utilities; -using System.Diagnostics; -using System.Runtime.CompilerServices; namespace Microsoft.CodeAnalysis { @@ -23,8 +22,13 @@ internal partial class Checksum // https://github.com/dotnet/runtime/blob/f2db6d6093c54e5eeb9db2d8dcbe15b2db92ad8c/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256.cs#L18-L19 private const int SHA256HashSizeBytes = 256 / 8; +#if NET5_0_OR_GREATER private static readonly ObjectPool s_incrementalHashPool = new(() => IncrementalHash.CreateHash(HashAlgorithmName.SHA256), size: 20); +#else + private static readonly ObjectPool s_incrementalHashPool = + new(SHA256.Create, size: 20); +#endif #if !NET5_0_OR_GREATER // Dedicated pools for the byte[]s we use to create checksums from two or three existing checksums. Sized to @@ -53,13 +57,15 @@ public static Checksum Create(IEnumerable values) using var pooledBuffer = SharedPools.ByteArray.GetPooledObject(); var hash = pooledHash.Object; + hash.Initialize(); foreach (var value in values) { AppendData(hash, pooledBuffer.Object, value); AppendData(hash, pooledBuffer.Object, "\0"); } - return From(hash.GetHashAndReset()); + hash.TransformFinalBlock(Array.Empty(), 0, 0); + return From(hash.Hash); #endif } @@ -73,10 +79,12 @@ public static Checksum Create(string value) using var pooledHash = s_incrementalHashPool.GetPooledObject(); using var pooledBuffer = SharedPools.ByteArray.GetPooledObject(); var hash = pooledHash.Object; + hash.Initialize(); AppendData(hash, pooledBuffer.Object, value); - return From(hash.GetHashAndReset()); + hash.TransformFinalBlock(Array.Empty(), 0, 0); + return From(hash.Hash); #endif } @@ -109,6 +117,7 @@ public static Checksum Create(Stream stream) using var pooledBuffer = SharedPools.ByteArray.GetPooledObject(); var hash = pooledHash.Object; + hash.Initialize(); var buffer = pooledBuffer.Object; var bufferLength = buffer.Length; @@ -118,12 +127,13 @@ public static Checksum Create(Stream stream) bytesRead = stream.Read(buffer, 0, bufferLength); if (bytesRead > 0) { - hash.AppendData(buffer, 0, bytesRead); + hash.TransformBlock(buffer, 0, bytesRead, null, 0); } } while (bytesRead > 0); - var bytes = hash.GetHashAndReset(); + hash.TransformFinalBlock(Array.Empty(), 0, 0); + var bytes = hash.Hash; // if bytes array is bigger than certain size, checksum // will truncate it to predetermined size. for more detail, @@ -174,21 +184,23 @@ public static Checksum Create(Checksum checksum1, Checksum checksum2, Checksum c private static Checksum CreateUsingByteArrays(Checksum checksum1, Checksum checksum2) { - using var hash = s_incrementalHashPool.GetPooledObject(); using var bytes = s_twoChecksumByteArrayPool.GetPooledObject(); var bytesSpan = bytes.Object.AsSpan(); checksum1.WriteTo(bytesSpan); checksum2.WriteTo(bytesSpan.Slice(HashSize)); - hash.Object.AppendData(bytes.Object); + using var hash = s_incrementalHashPool.GetPooledObject(); + hash.Object.Initialize(); + + hash.Object.TransformBlock(bytes.Object, 0, bytes.Object.Length, null, 0); - return From(hash.Object.GetHashAndReset()); + hash.Object.TransformFinalBlock(Array.Empty(), 0, 0); + return From(hash.Object.Hash); } private static Checksum CreateUsingByteArrays(Checksum checksum1, Checksum checksum2, Checksum checksum3) { - using var hash = s_incrementalHashPool.GetPooledObject(); using var bytes = s_threeChecksumByteArrayPool.GetPooledObject(); var bytesSpan = bytes.Object.AsSpan(); @@ -196,9 +208,13 @@ private static Checksum CreateUsingByteArrays(Checksum checksum1, Checksum check checksum2.WriteTo(bytesSpan.Slice(HashSize)); checksum3.WriteTo(bytesSpan.Slice(2 * HashSize)); - hash.Object.AppendData(bytes.Object); + using var hash = s_incrementalHashPool.GetPooledObject(); + hash.Object.Initialize(); + + hash.Object.TransformBlock(bytes.Object, 0, bytes.Object.Length, null, 0); - return From(hash.Object.GetHashAndReset()); + hash.Object.TransformFinalBlock(Array.Empty(), 0, 0); + return From(hash.Object.Hash); } #else @@ -283,7 +299,7 @@ public static Checksum Create(ParseOptions value, ISerializerService serializer) } #if !NET5_0_OR_GREATER - private static void AppendData(IncrementalHash hash, byte[] buffer, string value) + private static void AppendData(SHA256 hash, byte[] buffer, string value) { var stringBytes = MemoryMarshal.AsBytes(value.AsSpan()); Debug.Assert(stringBytes.Length == value.Length * 2); @@ -295,7 +311,7 @@ private static void AppendData(IncrementalHash hash, byte[] buffer, string value var toCopy = Math.Min(remaining, buffer.Length); stringBytes.Slice(index, toCopy).CopyTo(buffer); - hash.AppendData(buffer, 0, toCopy); + hash.TransformBlock(buffer, 0, toCopy, null, 0); index += toCopy; }