Skip to content

Try/catch blocks for ArrayPool in System.Security.Cryptography.HashAlgorithm  #71249

@qtoyam

Description

@qtoyam

All funcs in HashAlgorithm that use ArrayPool don't use try/catch blocks to ensure return array (and ZeroMemory).
For example:

private async Task<byte[]> ComputeHashAsyncCore(
Stream inputStream,
CancellationToken cancellationToken)
{
// Use ArrayPool.Shared instead of CryptoPool because the array is passed out.
byte[] rented = ArrayPool<byte>.Shared.Rent(4096);
Memory<byte> buffer = rented;
int clearLimit = 0;
int bytesRead;
while ((bytesRead = await inputStream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) > 0)
{
if (bytesRead > clearLimit)
{
clearLimit = bytesRead;
}
HashCore(rented, 0, bytesRead);
}
CryptographicOperations.ZeroMemory(rented.AsSpan(0, clearLimit));
ArrayPool<byte>.Shared.Return(rented, clearArray: false);
return CaptureHashCodeAndReinitialize();
}

Cancellation can be requested, so array will not be returned and memory will not be zero out.

I suggest fix:

Fix

        private async Task<byte[]> ComputeHashAsyncCore(
            Stream inputStream,
            CancellationToken cancellationToken)
        {
            // Use ArrayPool.Shared instead of CryptoPool because the array is passed out.
            byte[] rented = ArrayPool<byte>.Shared.Rent(4096);
            int clearLimit = 0;
            try
            {
                Memory<byte> buffer = rented;
                int bytesRead;

                while ((bytesRead = await inputStream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) > 0)
                {
                    if (bytesRead > clearLimit)
                    {
                        clearLimit = bytesRead;
                    }

                    HashCore(rented, 0, bytesRead);
                }

                return CaptureHashCodeAndReinitialize();
            }
            finally
            {
                CryptographicOperations.ZeroMemory(rented.AsSpan(0, clearLimit));
                ArrayPool<byte>.Shared.Return(rented, clearArray: false);
            }
        }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions