File: System\Security\Cryptography\LiteHashProvider.Xof.cs
Web Access
Project: src\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
 
namespace System.Security.Cryptography
{
    internal static partial class LiteHashProvider
    {
        internal static void XofStream(string hashAlgorithmId, Stream source, Span<byte> destination)
        {
            LiteXof hash = CreateXof(hashAlgorithmId);
            int written = ProcessStream(hash, source, destination);
            Debug.Assert(written == destination.Length);
        }
 
        internal static byte[] XofStream(string hashAlgorithmId, int outputLength, Stream source)
        {
            byte[] result = new byte[outputLength];
            LiteXof hash = CreateXof(hashAlgorithmId);
            int written = ProcessStream(hash, source, result);
            Debug.Assert(written == outputLength);
            return result;
        }
 
        internal static void KmacStream(
            string hashAlgorithmId,
            ReadOnlySpan<byte> key,
            ReadOnlySpan<byte> customizationString,
            Stream source,
            bool xof,
            Span<byte> destination)
        {
            LiteKmac hash = CreateKmac(hashAlgorithmId, key, customizationString, xof);
            int written = ProcessStream(hash, source, destination);
            Debug.Assert(written == destination.Length);
        }
 
        internal static byte[] KmacStream(
            string hashAlgorithmId,
            ReadOnlySpan<byte> key,
            ReadOnlySpan<byte> customizationString,
            int outputLength,
            Stream source,
            bool xof)
        {
            byte[] result = new byte[outputLength];
            LiteKmac hash = CreateKmac(hashAlgorithmId, key, customizationString, xof);
            int written = ProcessStream(hash, source, result);
            Debug.Assert(written == outputLength);
            return result;
        }
 
        internal static ValueTask XofStreamAsync(
            string hashAlgorithmId,
            Stream source,
            Memory<byte> destination,
            CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return ValueTask.FromCanceled(cancellationToken);
            }
 
            LiteXof hash = CreateXof(hashAlgorithmId);
            return ProcessStreamIndefiniteAsync(hash, source, destination, cancellationToken);
        }
 
        internal static ValueTask<byte[]> XofStreamAsync(
            string hashAlgorithmId,
            int outputLength,
            Stream source,
            CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return ValueTask.FromCanceled<byte[]>(cancellationToken);
            }
 
            LiteXof hash = CreateXof(hashAlgorithmId);
            return ProcessStreamAsync(hash, outputLength, source, cancellationToken);
        }
 
        internal static ValueTask KmacStreamAsync(
            string hashAlgorithmId,
            ReadOnlySpan<byte> key,
            Stream source,
            bool xof,
            Memory<byte> destination,
            ReadOnlySpan<byte> customizationString,
            CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return ValueTask.FromCanceled(cancellationToken);
            }
 
            LiteKmac hash = CreateKmac(hashAlgorithmId, key, customizationString, xof);
            return ProcessStreamIndefiniteAsync(hash, source, destination, cancellationToken);
        }
 
        internal static ValueTask<byte[]> KmacStreamAsync(
            string hashAlgorithmId,
            ReadOnlySpan<byte> key,
            Stream source,
            bool xof,
            int outputLength,
            ReadOnlySpan<byte> customizationString,
            CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return ValueTask.FromCanceled<byte[]>(cancellationToken);
            }
 
            LiteKmac hash = CreateKmac(hashAlgorithmId, key, customizationString, xof);
            return ProcessStreamAsync(hash, outputLength, source, cancellationToken);
        }
 
        // This takes ownership of the hash parameter and disposes of it when done.
        private static async ValueTask ProcessStreamIndefiniteAsync<T>(
            T hash,
            Stream source,
            Memory<byte> destination,
            CancellationToken cancellationToken) where T : ILiteHash
        {
            using (hash)
            {
                byte[] rented = CryptoPool.Rent(4096);
 
                int maxRead = 0;
                int read;
 
                try
                {
                    while ((read = await source.ReadAsync(rented, cancellationToken).ConfigureAwait(false)) > 0)
                    {
                        maxRead = Math.Max(maxRead, read);
                        hash.Append(rented.AsSpan(0, read));
                    }
 
                    hash.Finalize(destination.Span);
                }
                finally
                {
                    CryptoPool.Return(rented, clearSize: maxRead);
                }
            }
        }
    }
}