using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace PspCrypto.Security.Cryptography
{
public class HMACSHA224 : HMAC
{
///
/// The hash size produced by the HMAC SHA224 algorithm, in bits.
///
public const int HashSizeInBits = 224;
///
/// The hash size produced by the HMAC SHA24 algorithm, in bytes.
///
public const int HashSizeInBytes = HashSizeInBits / 8;
public HMACSHA224()
: this(RandomNumberGenerator.GetBytes(BlockSize))
{ }
public HMACSHA224(byte[] key)
{
if (key is null)
{
throw new ArgumentNullException(nameof(key));
}
HashName = HashAlgorithmNames.SHA224;
_hMacCommon = new HMACCommon(HashAlgorithmNames.SHA224, key, BlockSize);
base.Key = _hMacCommon.ActualKey!;
// this not really needed as it'll initialize BlockSizeValue with same value it has which is 64.
// we just want to be explicit in all HMAC extended classes
BlockSizeValue = BlockSize;
HashSizeValue = _hMacCommon.HashSizeInBits;
Debug.Assert(HashSizeValue == HashSizeInBits);
}
public override byte[] Key
{
get
{
return base.Key;
}
set
{
ArgumentNullException.ThrowIfNull(value);
_hMacCommon.ChangeKey(value);
base.Key = _hMacCommon.ActualKey!;
}
}
protected override void HashCore(byte[] rgb, int ib, int cb) =>
_hMacCommon.AppendHashData(rgb, ib, cb);
protected override void HashCore(ReadOnlySpan source) =>
_hMacCommon.AppendHashData(source);
protected override byte[] HashFinal() =>
_hMacCommon.FinalizeHashAndReset();
protected override bool TryHashFinal(Span destination, out int bytesWritten) =>
_hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
public override void Initialize() => _hMacCommon.Reset();
///
/// Computes the HMAC of data using the SHA224 algorithm.
///
/// The HMAC key.
/// The data to HMAC.
/// The HMAC of the data.
///
/// or is .
///
public static byte[] HashData(byte[] key, byte[] source)
{
ArgumentNullException.ThrowIfNull(key);
ArgumentNullException.ThrowIfNull(source);
return HashData(new ReadOnlySpan(key), new ReadOnlySpan(source));
}
///
/// Computes the HMAC of data using the SHA224 algorithm.
///
/// The HMAC key.
/// The data to HMAC.
/// The HMAC of the data.
public static byte[] HashData(ReadOnlySpan key, ReadOnlySpan source)
{
byte[] buffer = new byte[HashSizeInBytes];
int written = HashData(key, source, buffer.AsSpan());
Debug.Assert(written == buffer.Length);
return buffer;
}
///
/// Computes the HMAC of data using the SHA224 algorithm.
///
/// The HMAC key.
/// The data to HMAC.
/// The buffer to receive the HMAC value.
/// The total number of bytes written to .
///
/// The buffer in is too small to hold the calculated hash
/// size. The SHA224 algorithm always produces a 224-bit HMAC, or 28 bytes.
///
public static int HashData(ReadOnlySpan key, ReadOnlySpan source, Span destination)
{
if (!TryHashData(key, source, destination, out int bytesWritten))
{
throw new ArgumentException("Destination is too short.", nameof(destination));
}
return bytesWritten;
}
///
/// Attempts to compute the HMAC of data using the SHA224 algorithm.
///
/// The HMAC key.
/// The data to HMAC.
/// The buffer to receive the HMAC value.
///
/// When this method returns, the total number of bytes written into .
///
///
/// if is too small to hold the
/// calculated hash, otherwise.
///
public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source, Span destination, out int bytesWritten)
{
if (destination.Length < HashSizeInBytes)
{
bytesWritten = 0;
return false;
}
bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA224, key, source, destination);
Debug.Assert(bytesWritten == HashSizeInBytes);
return true;
}
private HMACCommon _hMacCommon;
private const int BlockSize = 64;
}
}