|
// 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.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Internal.Cryptography;
namespace System.Security.Cryptography
{
/// <summary>
/// Computes the KMACXOF128 MAC for the input data.
/// </summary>
/// <remarks>
/// This algorithm is specified by NIST SP 800-185.
/// </remarks>
public sealed class KmacXof128 : IDisposable
{
private sealed class KmacTrait : IKmacStatic
{
static string IKmacStatic.HashAlgorithmName => HashAlgorithmNames.KMAC128;
static bool IKmacStatic.IsSupported => IsSupported;
static bool IKmacStatic.IsXof => true;
}
private ConcurrentSafeKmac _kmacProvider;
private bool _disposed;
/// <summary>
/// Initializes a new instance of the <see cref="KmacXof128" /> class.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <exception cref="ArgumentNullException">
/// <paramref name="key"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred creating an instance of the algorithm.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public KmacXof128(byte[] key, byte[]? customizationString = null)
: this(Helpers.ArrayToSpanOrThrow(key), customizationString)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="KmacXof128" /> class.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <exception cref="CryptographicException">An error has occurred creating an instance of the algorithm.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public KmacXof128(ReadOnlySpan<byte> key, ReadOnlySpan<byte> customizationString = default)
{
CheckPlatformSupport();
_kmacProvider = new ConcurrentSafeKmac(HashAlgorithmNames.KMAC128, key, customizationString, xof: true);
}
private KmacXof128(ConcurrentSafeKmac kmacProvider)
{
_kmacProvider = kmacProvider;
}
/// <summary>
/// Gets a value that indicates whether the algorithm is supported on the current platform.
/// </summary>
/// <value>
/// <see langword="true" /> if the algorithm is supported; otherwise, <see langword="false" />.
/// </value>
public static bool IsSupported { get; } = HashProviderDispenser.KmacSupported(HashAlgorithmNames.KMAC128);
/// <summary>
/// Appends the specified data to the data already processed in the hash.
/// </summary>
/// <param name="data">The data to process.</param>
/// <exception cref="ArgumentNullException">
/// <paramref name="data" /> is <see langword="null" />.
/// </exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
public void AppendData(byte[] data) => AppendData(Helpers.ArrayToSpanOrThrow(data));
/// <summary>
/// Appends the specified data to the data already processed in the hash.
/// </summary>
/// <param name="data">The data to process.</param>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
public void AppendData(ReadOnlySpan<byte> data)
{
CheckDisposed();
_kmacProvider.Append(data);
}
/// <summary>
/// Retrieves the hash for the data accumulated from prior calls to the <c>AppendData</c> methods,
/// and resets the object to its initial state.
/// </summary>
/// <param name="outputLength">The size of the hash to produce.</param>
/// <returns>The computed hash.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="outputLength" /> is negative.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
/// <seealso cref="GetCurrentHash(int)" />
public byte[] GetHashAndReset(int outputLength)
{
ArgumentOutOfRangeException.ThrowIfNegative(outputLength);
CheckDisposed();
byte[] result = new byte[outputLength];
int written = _kmacProvider.Finalize(result);
Debug.Assert(written == outputLength);
_kmacProvider.Reset();
return result;
}
/// <summary>
/// Fills the buffer with the hash for the data accumulated from prior calls to the <c>AppendData</c> methods,
/// and resets the object to its initial state.
/// </summary>
/// <param name="destination">The buffer to fill with the hash.</param>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
/// <seealso cref="GetCurrentHash(Span{byte})" />
public void GetHashAndReset(Span<byte> destination)
{
CheckDisposed();
int written = _kmacProvider.Finalize(destination);
Debug.Assert(written == destination.Length);
_kmacProvider.Reset();
}
/// <summary>
/// Retrieves the hash for the data accumulated from prior calls to the <c>AppendData</c> methods,
/// without resetting the object to its initial state.
/// </summary>
/// <param name="outputLength">The size of the hash to produce.</param>
/// <returns>The computed hash.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="outputLength" /> is negative.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
/// <seealso cref="GetHashAndReset(int)" />
public byte[] GetCurrentHash(int outputLength)
{
ArgumentOutOfRangeException.ThrowIfNegative(outputLength);
CheckDisposed();
byte[] result = new byte[outputLength];
int written = _kmacProvider.Current(result);
Debug.Assert(written == outputLength);
return result;
}
/// <summary>
/// Fills the buffer with the hash for the data accumulated from prior calls to the <c>AppendData</c> methods,
/// without resetting the object to its initial state.
/// </summary>
/// <param name="destination">The buffer to fill with the hash.</param>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
/// <seealso cref="GetHashAndReset(Span{byte})" />
public void GetCurrentHash(Span<byte> destination)
{
CheckDisposed();
int written = _kmacProvider.Current(destination);
Debug.Assert(written == destination.Length);
}
/// <summary>
/// Creates a new instance of <see cref="KmacXof128" /> with the existing appended data preserved.
/// </summary>
/// <returns>A clone of the current instance.</returns>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
public KmacXof128 Clone()
{
CheckDisposed();
return new KmacXof128(_kmacProvider.Clone());
}
/// <summary>
/// Verifies the hash for the data accumulated from prior calls to the <c>AppendData</c> methods,
/// without resetting the object to its initial state.
/// </summary>
/// <param name="hash">The hash to verify.</param>
/// <returns>
/// <see langword="true" /> if the computed hash is equal to
/// <paramref name="hash" />; otherwise <see langword="false" />.
/// </returns>
/// <exception cref="ArgumentException">
/// <paramref name="hash"/> is empty.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
/// <remarks>
/// The length of the hash to produce and verify is determined by the length of <paramref name="hash" />.
/// Callers should ensure the length of the hash meets the desired security requirements.
/// </remarks>
public bool VerifyCurrentHash(ReadOnlySpan<byte> hash)
{
if (hash.IsEmpty)
throw new ArgumentException(SR.Argument_HashEmpty, nameof(hash));
CheckDisposed();
return _kmacProvider.VerifyCurrentHash(hash);
}
/// <inheritdoc cref="VerifyCurrentHash(ReadOnlySpan{byte})" />
/// <exception cref="ArgumentNullException">
/// <paramref name="hash"/> is <see langword="null" />.
/// </exception>
public bool VerifyCurrentHash(byte[] hash)
{
ArgumentNullException.ThrowIfNull(hash);
return VerifyCurrentHash(new ReadOnlySpan<byte>(hash));
}
/// <summary>
/// Verifies the hash for the data accumulated from prior calls to the <c>AppendData</c> methods,
/// and resets the object to its initial state.
/// </summary>
/// <param name="hash">The hash to verify.</param>
/// <returns>
/// <see langword="true" /> if the computed hash is equal to
/// <paramref name="hash" />; otherwise <see langword="false" />.
/// </returns>
/// <exception cref="ArgumentException">
/// <paramref name="hash"/> is empty.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
/// <remarks>
/// The length of the hash to produce and verify is determined by the length of <paramref name="hash" />.
/// Callers should ensure the length of the hash meets the desired security requirements.
/// </remarks>
public bool VerifyHashAndReset(ReadOnlySpan<byte> hash)
{
if (hash.IsEmpty)
throw new ArgumentException(SR.Argument_HashEmpty, nameof(hash));
CheckDisposed();
return _kmacProvider.VerifyHashAndReset(hash);
}
/// <inheritdoc cref="VerifyHashAndReset(ReadOnlySpan{byte})" />
/// <exception cref="ArgumentNullException">
/// <paramref name="hash"/> is <see langword="null" />.
/// </exception>
public bool VerifyHashAndReset(byte[] hash)
{
ArgumentNullException.ThrowIfNull(hash);
return VerifyHashAndReset(new ReadOnlySpan<byte>(hash));
}
/// <summary>
/// Release all resources used by the current instance of the <see cref="KmacXof128" /> class.
/// </summary>
public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
_kmacProvider.Dispose();
}
/// <summary>
/// Computes the hash of data using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The data to hash.</param>
/// <param name="outputLength">The size of the hash to produce.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <returns>The hash of the data.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="outputLength" /> is negative.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="key" /> or <paramref name="source" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public static byte[] HashData(
byte[] key,
byte[] source,
int outputLength,
byte[]? customizationString = null)
{
ArgumentNullException.ThrowIfNull(key);
ArgumentNullException.ThrowIfNull(source);
return HashData(new ReadOnlySpan<byte>(key), new ReadOnlySpan<byte>(source), outputLength, customizationString);
}
/// <summary>
/// Computes the hash of data using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The data to hash.</param>
/// <param name="outputLength">The size of the hash to produce.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <returns>The hash of the data.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="outputLength" /> is negative.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public static byte[] HashData(
ReadOnlySpan<byte> key,
ReadOnlySpan<byte> source,
int outputLength,
ReadOnlySpan<byte> customizationString = default)
{
ArgumentOutOfRangeException.ThrowIfNegative(outputLength);
CheckPlatformSupport();
byte[] output = new byte[outputLength];
HashDataCore(key, source, output, customizationString);
return output;
}
/// <summary>
/// Computes the hash of data using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The data to hash.</param>
/// <param name="destination">The buffer to fill with the hash.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public static void HashData(
ReadOnlySpan<byte> key,
ReadOnlySpan<byte> source,
Span<byte> destination,
ReadOnlySpan<byte> customizationString = default)
{
CheckPlatformSupport();
HashDataCore(key, source, destination, customizationString);
}
/// <summary>
/// Computes the hash of a stream using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The stream to hash.</param>
/// <param name="outputLength">The size of the hash to produce.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <returns>The hash of the data.</returns>
/// <exception cref="ArgumentException">
/// <paramref name="source" /> does not support reading.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="outputLength" /> is negative.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="key" /> or <paramref name="source" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public static byte[] HashData(
byte[] key,
Stream source,
int outputLength,
byte[]? customizationString = null)
{
ArgumentNullException.ThrowIfNull(key);
ArgumentNullException.ThrowIfNull(source);
ArgumentOutOfRangeException.ThrowIfNegative(outputLength);
CheckStreamCanRead(source);
CheckPlatformSupport();
return LiteHashProvider.KmacStream(HashAlgorithmNames.KMAC128, key, customizationString, outputLength, source, xof: true);
}
/// <summary>
/// Computes the hash of a stream using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The stream to hash.</param>
/// <param name="outputLength">The size of the hash to produce.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <returns>The hash of the data.</returns>
/// <exception cref="ArgumentException">
/// <paramref name="source" /> does not support reading.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="outputLength" /> is negative.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="source" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public static byte[] HashData(
ReadOnlySpan<byte> key,
Stream source,
int outputLength,
ReadOnlySpan<byte> customizationString = default)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentOutOfRangeException.ThrowIfNegative(outputLength);
CheckStreamCanRead(source);
CheckPlatformSupport();
return LiteHashProvider.KmacStream(HashAlgorithmNames.KMAC128, key, customizationString, outputLength, source, xof: true);
}
/// <summary>
/// Computes the hash of a stream using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The stream to hash.</param>
/// <param name="destination">The buffer to fill with the hash.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <exception cref="ArgumentException">
/// <paramref name="source" /> does not support reading.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="source" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public static void HashData(
ReadOnlySpan<byte> key,
Stream source,
Span<byte> destination,
ReadOnlySpan<byte> customizationString = default)
{
ArgumentNullException.ThrowIfNull(source);
CheckStreamCanRead(source);
CheckPlatformSupport();
LiteHashProvider.KmacStream(HashAlgorithmNames.KMAC128, key, customizationString, source, xof: true, destination);
}
/// <summary>
/// Asynchronously computes the hash of a stream using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The stream to hash.</param>
/// <param name="outputLength">The size of the hash to produce.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <param name="cancellationToken">
/// The token to monitor for cancellation requests.
/// The default value is <see cref="System.Threading.CancellationToken.None" />.
/// </param>
/// <returns>
/// A <see cref="ValueTask{TResult}" /> that completes with the computed hash.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="key" /> or <paramref name="source" /> is <see langword="null" />.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="source" /> does not support reading.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="outputLength" /> is negative.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="OperationCanceledException">
/// <paramref name="cancellationToken"/> has been canceled.
/// </exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public static ValueTask<byte[]> HashDataAsync(
byte[] key,
Stream source,
int outputLength,
byte[]? customizationString = null,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(key);
ArgumentNullException.ThrowIfNull(source);
ArgumentOutOfRangeException.ThrowIfNegative(outputLength);
CheckStreamCanRead(source);
CheckPlatformSupport();
return LiteHashProvider.KmacStreamAsync(HashAlgorithmNames.KMAC128, key, source, xof: true, outputLength, customizationString, cancellationToken);
}
/// <summary>
/// Asynchronously computes the hash of a stream using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The stream to hash.</param>
/// <param name="outputLength">The size of the hash to produce.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <param name="cancellationToken">
/// The token to monitor for cancellation requests.
/// The default value is <see cref="System.Threading.CancellationToken.None" />.
/// </param>
/// <returns>
/// A <see cref="ValueTask{TResult}" /> that completes with the computed hash.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="source" /> is <see langword="null" />.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="source" /> does not support reading.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="outputLength" /> is negative.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="OperationCanceledException">
/// <paramref name="cancellationToken"/> has been canceled.
/// </exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public static ValueTask<byte[]> HashDataAsync(
ReadOnlyMemory<byte> key,
Stream source,
int outputLength,
ReadOnlyMemory<byte> customizationString = default,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentOutOfRangeException.ThrowIfNegative(outputLength);
CheckStreamCanRead(source);
CheckPlatformSupport();
return LiteHashProvider.KmacStreamAsync(HashAlgorithmNames.KMAC128, key.Span, source, xof: true, outputLength, customizationString.Span, cancellationToken);
}
/// <summary>
/// Asynchronously computes the hash of a stream using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The stream to hash.</param>
/// <param name="destination">The buffer to fill with the hash.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <param name="cancellationToken">
/// The token to monitor for cancellation requests.
/// The default value is <see cref="System.Threading.CancellationToken.None" />.
/// </param>
/// <returns>A <see cref="ValueTask"/> that represents the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="source" /> is <see langword="null" />.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="source" /> does not support reading.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="OperationCanceledException">
/// <paramref name="cancellationToken"/> has been canceled.
/// </exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
public static ValueTask HashDataAsync(
ReadOnlyMemory<byte> key,
Stream source,
Memory<byte> destination,
ReadOnlyMemory<byte> customizationString = default,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(source);
CheckStreamCanRead(source);
CheckPlatformSupport();
return LiteHashProvider.KmacStreamAsync(HashAlgorithmNames.KMAC128, key.Span, source, xof: true, destination, customizationString.Span, cancellationToken);
}
/// <summary>
/// Verifies the hash of data using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The data to hash.</param>
/// <param name="hash">The hash to compare against.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <returns>
/// <see langword="true" /> if the computed hash of <paramref name="source"/> is equal to
/// <paramref name="hash" />; otherwise <see langword="false" />.
/// </returns>
/// <exception cref="ArgumentException">
/// <paramref name="hash" /> is empty.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
/// <remarks>
/// The length of the hash to produce and verify is determined by the length of <paramref name="hash" />.
/// Callers should ensure the length of the hash meets the desired security requirements.
/// </remarks>
public static bool Verify(
ReadOnlySpan<byte> key,
ReadOnlySpan<byte> source,
ReadOnlySpan<byte> hash,
ReadOnlySpan<byte> customizationString = default)
{
return KmacStatic<KmacTrait>.Verify(key, source, hash, customizationString);
}
/// <inheritdoc cref="Verify(ReadOnlySpan{byte}, ReadOnlySpan{byte}, ReadOnlySpan{byte}, ReadOnlySpan{byte})" />
/// <exception cref="ArgumentNullException">
/// <paramref name="key" />, <paramref name="source" />, or <paramref name="hash" /> is <see langword="null" />.
/// </exception>
public static bool Verify(byte[] key, byte[] source, byte[] hash, byte[]? customizationString = null)
{
return KmacStatic<KmacTrait>.Verify(key, source, hash, customizationString);
}
/// <summary>
/// Verifies the hash of a stream using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The stream to hash.</param>
/// <param name="hash">The hash to compare against.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <returns>
/// <see langword="true" /> if the computed hash of <paramref name="source"/> is equal to
/// <paramref name="hash" />; otherwise <see langword="false" />.
/// </returns>
/// <exception cref="ArgumentException">
/// <paramref name="hash" /> is empty.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="source" /> is <see langword="null"/>.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
/// <remarks>
/// The length of the hash to produce and verify is determined by the length of <paramref name="hash" />.
/// Callers should ensure the length of the hash meets the desired security requirements.
/// </remarks>
public static bool Verify(
ReadOnlySpan<byte> key,
Stream source,
ReadOnlySpan<byte> hash,
ReadOnlySpan<byte> customizationString = default)
{
return KmacStatic<KmacTrait>.Verify(key, source, hash, customizationString);
}
/// <inheritdoc cref="Verify(ReadOnlySpan{byte}, Stream, ReadOnlySpan{byte}, ReadOnlySpan{byte})" />
/// <exception cref="ArgumentNullException">
/// <paramref name="key" />, <paramref name="source" />, or <paramref name="hash" /> is <see langword="null" />.
/// </exception>
public static bool Verify(byte[] key, Stream source, byte[] hash, byte[]? customizationString = null)
{
return KmacStatic<KmacTrait>.Verify(key, source, hash, customizationString);
}
/// <inheritdoc cref="VerifyAsync(ReadOnlyMemory{byte}, Stream, ReadOnlyMemory{byte}, ReadOnlyMemory{byte}, CancellationToken)" />
/// <exception cref="ArgumentNullException">
/// <paramref name="key" />, <paramref name="source" />, or <paramref name="hash" /> is <see langword="null" />.
/// </exception>
public static ValueTask<bool> VerifyAsync(
byte[] key,
Stream source,
byte[] hash,
byte[]? customizationString = null,
CancellationToken cancellationToken = default)
{
return KmacStatic<KmacTrait>.VerifyAsync(key, source, hash, customizationString, cancellationToken);
}
/// <summary>
/// Asynchronously verifies the hash of a stream using the KMACXOF128 algorithm.
/// </summary>
/// <param name="key">The KMAC key.</param>
/// <param name="source">The stream to hash.</param>
/// <param name="hash">The hash to compare against.</param>
/// <param name="customizationString">An optional customization string. The default is no customization string.</param>
/// <param name="cancellationToken">
/// The token to monitor for cancellation requests.
/// The default value is <see cref="System.Threading.CancellationToken.None" />.
/// </param>
/// <returns>
/// A task that, when awaited, produces <see langword="true" /> if the computed hash of
/// <paramref name="source"/> is equal to <paramref name="hash" />; otherwise <see langword="false" />.
/// </returns>
/// <exception cref="ArgumentException">
/// <para><paramref name="hash" /> is empty.</para>
/// <para> -or- </para>
/// <para><paramref name="source" /> does not support reading.</para>
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="source" /> is <see langword="null"/>.
/// </exception>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="OperationCanceledException">
/// <paramref name="cancellationToken"/> has been canceled.
/// </exception>
/// <exception cref="PlatformNotSupportedException">
/// The platform does not support KMACXOF128. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports KMACXOF128.
/// </exception>
/// <remarks>
/// The length of the hash to produce and verify is determined by the length of <paramref name="hash" />.
/// Callers should ensure the length of the hash meets the desired security requirements.
/// </remarks>
public static ValueTask<bool> VerifyAsync(
ReadOnlyMemory<byte> key,
Stream source,
ReadOnlyMemory<byte> hash,
ReadOnlyMemory<byte> customizationString = default,
CancellationToken cancellationToken = default)
{
return KmacStatic<KmacTrait>.VerifyAsync(key, source, hash, customizationString, cancellationToken);
}
private static void HashDataCore(
ReadOnlySpan<byte> key,
ReadOnlySpan<byte> source,
Span<byte> destination,
ReadOnlySpan<byte> customizationString)
{
HashProviderDispenser.OneShotHashProvider.KmacData(
HashAlgorithmNames.KMAC128,
key,
source,
destination,
customizationString,
xof: true);
}
private void CheckDisposed() => ObjectDisposedException.ThrowIf(_disposed, this);
private static void CheckPlatformSupport()
{
if (!IsSupported)
{
throw new PlatformNotSupportedException();
}
}
private static void CheckStreamCanRead(Stream source)
{
if (!source.CanRead)
{
throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
}
}
}
}
|