Skip to content

Commit

Permalink
Avoid finalizable internal state for non-FIPS scenarios
Browse files Browse the repository at this point in the history
Fixes #67995
  • Loading branch information
sharwell committed Apr 27, 2023
1 parent 618b3b0 commit 48e9cc5
Showing 1 changed file with 31 additions and 15 deletions.
46 changes: 31 additions & 15 deletions src/Workspaces/Core/Portable/Workspace/Solution/Checksum_Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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<IncrementalHash> s_incrementalHashPool =
new(() => IncrementalHash.CreateHash(HashAlgorithmName.SHA256), size: 20);
#else
private static readonly ObjectPool<SHA256> 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
Expand Down Expand Up @@ -53,13 +57,15 @@ public static Checksum Create(IEnumerable<string> 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<byte>(), 0, 0);
return From(hash.Hash);
#endif
}

Expand All @@ -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<byte>(), 0, 0);
return From(hash.Hash);
#endif
}

Expand Down Expand Up @@ -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;
Expand All @@ -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<byte>(), 0, 0);
var bytes = hash.Hash;

// if bytes array is bigger than certain size, checksum
// will truncate it to predetermined size. for more detail,
Expand Down Expand Up @@ -174,31 +184,37 @@ 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<byte>(), 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();
checksum1.WriteTo(bytesSpan);
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<byte>(), 0, 0);
return From(hash.Object.Hash);
}

#else
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down

0 comments on commit 48e9cc5

Please sign in to comment.