// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
[DllImport(Libraries.AndroidCryptoNative, EntryPoint = "CryptoNative_HmacCurrent")]
internal static extern int HmacCurrent(SafeHmacCtxHandle ctx, ref byte data, ref int len);
+
+ [DllImport(Libraries.AndroidCryptoNative, EntryPoint = "CryptoNative_HmacOneShot")]
+ private static unsafe extern int HmacOneShot(IntPtr type, byte* key, int keySize, byte* source, int sourceSize, byte* md, ref int mdSize);
+
+ internal static unsafe int HmacOneShot(IntPtr type, ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
+ {
+ int size = destination.Length;
+ const int Success = 1;
+
+ fixed (byte* pKey = key)
+ fixed (byte* pSource = source)
+ fixed (byte* pDestination = destination)
+ {
+ int result = HmacOneShot(type, pKey, key.Length, pSource, source.Length, pDestination, ref size);
+
+ if (result != Success)
+ {
+ Debug.Assert(result == 0);
+ throw CreateOpenSslCryptographicException();
+ }
+ }
+
+ return size;
+ }
}
}
[DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacCurrent")]
private static extern int HmacCurrent(SafeHmacHandle ctx, ref byte pbOutput, int cbOutput);
+
+ [DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacOneShot")]
+ internal static unsafe extern int HmacOneShot(
+ PAL_HashAlgorithm algorithm,
+ byte* pKey,
+ int cbKey,
+ byte* pData,
+ int cbData,
+ byte* pOutput,
+ int cbOutput,
+ out int cbDigest);
}
}
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_HmacCurrent")]
internal static extern int HmacCurrent(SafeHmacCtxHandle ctx, ref byte data, ref int len);
+
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_HmacOneShot")]
+ private static unsafe extern int HmacOneShot(IntPtr type, byte* key, int keySize, byte* source, int sourceSize, byte* md, ref int mdSize);
+
+ internal static unsafe int HmacOneShot(IntPtr type, ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
+ {
+ int size = destination.Length;
+ const int Success = 1;
+
+ fixed (byte* pKey = key)
+ fixed (byte* pSource = source)
+ fixed (byte* pDestination = destination)
+ {
+ int result = HmacOneShot(type, pKey, key.Length, pSource, source.Length, pDestination, ref size);
+
+ if (result != Success)
+ {
+ Debug.Assert(result == 0);
+ throw CreateOpenSslCryptographicException();
+ }
+ }
+
+ return size;
+ }
}
}
BCRYPT_SHA256_ALG_HANDLE = 0x00000041,
BCRYPT_SHA384_ALG_HANDLE = 0x00000051,
BCRYPT_SHA512_ALG_HANDLE = 0x00000061,
+ BCRYPT_HMAC_MD5_ALG_HANDLE = 0x00000091,
+ BCRYPT_HMAC_SHA1_ALG_HANDLE = 0x000000a1,
+ BCRYPT_HMAC_SHA256_ALG_HANDLE = 0x000000b1,
+ BCRYPT_HMAC_SHA384_ALG_HANDLE = 0x000000c1,
+ BCRYPT_HMAC_SHA512_ALG_HANDLE = 0x000000d1,
BCRYPT_PBKDF2_ALG_HANDLE = 0x00000331,
}
{
actualItemCountMapping[actualItem] = new ItemCount(1, 1);
}
-
+
actualCount++;
}
countInfo.Remain--;
}
}
-
+
/// <summary>
/// Validates that the actual span is equal to the expected span.
/// If this fails, determine where the differences are and create an exception with that information.
}
}
+ public static void FilledWith<T>(T expected, ReadOnlySpan<T> actual)
+ {
+ EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+
+ for (int i = 0; i < actual.Length; i++)
+ {
+ if (!comparer.Equals(expected, actual[i]))
+ {
+ throw new XunitException($"Expected {expected?.ToString() ?? "null"} at position {i}");
+ }
+ }
+ }
+
public static void SequenceEqual<T>(Span<T> expected, Span<T> actual) where T : IEquatable<T> => SequenceEqual((ReadOnlySpan<T>)expected, (ReadOnlySpan<T>)actual);
public static void SequenceEqual<T>(T[] expected, T[] actual) where T : IEquatable<T> => SequenceEqual(expected.AsSpan(), actual.AsSpan());
Assert.Equal(expectedParamName, exception.ParamName);
return exception;
}
-
+
private class ItemCount
{
public int Original { get; set; }
{
ReleaseGRef(GetJNIEnv(), ctx);
}
+
+int32_t CryptoNative_HmacOneShot(intptr_t type,
+ uint8_t* key,
+ int32_t keyLen,
+ uint8_t* source,
+ int32_t sourceLen,
+ uint8_t* md,
+ int32_t* mdSize)
+{
+ jobject hmacCtx = CryptoNative_HmacCreate(key, keyLen, type);
+
+ if (hmacCtx == FAIL)
+ return FAIL;
+
+ int32_t ret = sourceLen == 0 ? SUCCESS : CryptoNative_HmacUpdate(hmacCtx, source, sourceLen);
+
+ if (ret != SUCCESS)
+ {
+ CryptoNative_HmacDestroy(hmacCtx);
+ return ret;
+ }
+
+ ret = CryptoNative_HmacFinal(hmacCtx, md, mdSize);
+ CryptoNative_HmacDestroy(hmacCtx);
+ return ret;
+}
PALEXPORT int32_t CryptoNative_HmacFinal(jobject ctx, uint8_t* md, int32_t* len);
PALEXPORT int32_t CryptoNative_HmacCurrent(jobject ctx, uint8_t* md, int32_t* len);
PALEXPORT void CryptoNative_HmacDestroy(jobject ctx);
+PALEXPORT int32_t CryptoNative_HmacOneShot(intptr_t type,
+ uint8_t* key,
+ int32_t keyLen,
+ uint8_t* source,
+ int32_t sourceLen,
+ uint8_t* md,
+ int32_t* mdSize);
DllImportEntry(AppleCryptoNative_HmacUpdate)
DllImportEntry(AppleCryptoNative_HmacFinal)
DllImportEntry(AppleCryptoNative_HmacCurrent)
+ DllImportEntry(AppleCryptoNative_HmacOneShot)
DllImportEntry(AppleCryptoNative_SecKeychainItemCopyKeychain)
DllImportEntry(AppleCryptoNative_SecKeychainCreate)
DllImportEntry(AppleCryptoNative_SecKeychainDelete)
{
if (ctx == NULL || pbOutput == NULL)
return 0;
-
+
HmacCtx dup = *ctx;
return AppleCryptoNative_HmacFinal(&dup, pbOutput);
}
+
+int32_t AppleCryptoNative_HmacOneShot(PAL_HashAlgorithm algorithm,
+ const uint8_t* pKey,
+ int32_t cbKey,
+ const uint8_t* pBuf,
+ int32_t cbBuf,
+ uint8_t* pOutput,
+ int32_t cbOutput,
+ int32_t* pcbDigest)
+{
+ if (pOutput == NULL || cbOutput <= 0 || pcbDigest == NULL)
+ return -1;
+
+ CCHmacAlgorithm ccAlgorithm = PalAlgorithmToAppleAlgorithm(algorithm);
+ *pcbDigest = GetHmacOutputSize(algorithm);
+
+ if (ccAlgorithm == UINT_MAX)
+ return -1;
+
+ if (cbOutput < *pcbDigest)
+ return -1;
+
+ CCHmac(ccAlgorithm, pKey, cbKey, pBuf, cbBuf, pOutput);
+ return 1;
+}
Returns 1 on success, 0 on error.
*/
PALEXPORT int32_t AppleCryptoNative_HmacCurrent(const HmacCtx* ctx, uint8_t* pbOutput);
+
+/*
+Computes the HMAC of data with a key in to the pOutput buffer in one step.
+
+Return 1 on success, 0 on error, and negative values for invalid input.
+*/
+PALEXPORT int32_t AppleCryptoNative_HmacOneShot(PAL_HashAlgorithm algorithm,
+ const uint8_t* pKey,
+ int32_t cbKey,
+ const uint8_t* pBuf,
+ int32_t cbBuf,
+ uint8_t* pOutput,
+ int32_t cbOutput,
+ int32_t* pcbDigest);
DllImportEntry(CryptoNative_HmacCurrent)
DllImportEntry(CryptoNative_HmacDestroy)
DllImportEntry(CryptoNative_HmacFinal)
+ DllImportEntry(CryptoNative_HmacOneShot)
DllImportEntry(CryptoNative_HmacReset)
DllImportEntry(CryptoNative_HmacUpdate)
DllImportEntry(CryptoNative_LookupFriendlyNameByOid)
REQUIRED_FUNCTION(EVP_sha512) \
REQUIRED_FUNCTION(EXTENDED_KEY_USAGE_free) \
REQUIRED_FUNCTION(GENERAL_NAMES_free) \
+ REQUIRED_FUNCTION(HMAC) \
LEGACY_FUNCTION(HMAC_CTX_cleanup) \
REQUIRED_FUNCTION(HMAC_CTX_copy) \
FALLBACK_FUNCTION(HMAC_CTX_free) \
#define EVP_sha512 EVP_sha512_ptr
#define EXTENDED_KEY_USAGE_free EXTENDED_KEY_USAGE_free_ptr
#define GENERAL_NAMES_free GENERAL_NAMES_free_ptr
+#define HMAC HMAC_ptr
#define HMAC_CTX_cleanup HMAC_CTX_cleanup_ptr
#define HMAC_CTX_copy HMAC_CTX_copy_ptr
#define HMAC_CTX_free HMAC_CTX_free_ptr
return 0;
}
+
+int32_t CryptoNative_HmacOneShot(const EVP_MD* type,
+ const uint8_t* key,
+ int32_t keySize,
+ const uint8_t* source,
+ int32_t sourceSize,
+ uint8_t* md,
+ int32_t* mdSize)
+{
+ assert(mdSize != NULL && type != NULL && md != NULL && mdSize != NULL);
+ assert(keySize >= 0 && *mdSize >= 0);
+ assert(key != NULL || keySize == 0);
+ assert(source != NULL || sourceSize == 0);
+
+ uint8_t empty = 0;
+
+ if (key == NULL)
+ {
+ if (keySize != 0)
+ {
+ return -1;
+ }
+
+ key = ∅
+ }
+
+ unsigned int unsignedSource = Int32ToUint32(sourceSize);
+ unsigned int unsignedSize = Int32ToUint32(*mdSize);
+ unsigned char* result = HMAC(type, key, keySize, source, unsignedSource, md, &unsignedSize);
+ *mdSize = Uint32ToInt32(unsignedSize);
+
+ return result == NULL ? 0 : 1;
+}
* Returns 1 for success or 0 for failure.
*/
PALEXPORT int32_t CryptoNative_HmacCurrent(const HMAC_CTX* ctx, uint8_t* md, int32_t* len);
+
+/**
+ * Computes the HMAC of data using a key in a single operation.
+ * Returns -1 on invalid input, 0 on failure, and 1 on success.
+ */
+PALEXPORT int32_t CryptoNative_HmacOneShot(const EVP_MD* type,
+ const uint8_t* key,
+ int32_t keySize,
+ const uint8_t* source,
+ int32_t sourceSize,
+ uint8_t* md,
+ int32_t* mdSize);
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
+ public static byte[] HashData(byte[] key, byte[] source) { throw null; }
+ public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
+ public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
+ public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
+ public static byte[] HashData(byte[] key, byte[] source) { throw null; }
+ public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
+ public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
+ public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
+ public static byte[] HashData(byte[] key, byte[] source) { throw null; }
+ public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
+ public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
+ public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
+ public static byte[] HashData(byte[] key, byte[] source) { throw null; }
+ public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
+ public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
+ public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
+ public static byte[] HashData(byte[] key, byte[] source) { throw null; }
+ public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
+ public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
+ public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
public sealed partial class IncrementalHash : System.IDisposable
public static class OneShotHashProvider
{
+ public static unsafe int MacData(
+ string hashAlgorithmId,
+ ReadOnlySpan<byte> key,
+ ReadOnlySpan<byte> source,
+ Span<byte> destination)
+ {
+ throw new PlatformNotSupportedException(SR.SystemSecurityCryptographyAlgorithms_PlatformNotSupported);
+ }
+
public static int HashData(string hashAlgorithmId, ReadOnlySpan<byte> source, Span<byte> destination)
{
HashProvider provider = HashProviderDispenser.CreateHashProvider(hashAlgorithmId);
internal static class OneShotHashProvider
{
+ public static unsafe int MacData(
+ string hashAlgorithmId,
+ ReadOnlySpan<byte> key,
+ ReadOnlySpan<byte> source,
+ Span<byte> destination)
+ {
+ Interop.AppleCrypto.PAL_HashAlgorithm algorithm = HashAlgorithmToPal(hashAlgorithmId);
+
+ fixed (byte* pKey = key)
+ fixed (byte* pSource = source)
+ fixed (byte* pDestination = destination)
+ {
+ int ret = Interop.AppleCrypto.HmacOneShot(
+ algorithm,
+ pKey,
+ key.Length,
+ pSource,
+ source.Length,
+ pDestination,
+ destination.Length,
+ out int digestSize);
+
+ if (ret != 1)
+ {
+ Debug.Fail($"MacData return value {ret} was not 1");
+ throw new CryptographicException();
+ }
+
+ Debug.Assert(digestSize <= destination.Length);
+
+ return digestSize;
+ }
+ }
+
public static unsafe int HashData(string hashAlgorithmId, ReadOnlySpan<byte> source, Span<byte> destination)
{
Interop.AppleCrypto.PAL_HashAlgorithm algorithm = HashAlgorithmToPal(hashAlgorithmId);
internal static class OneShotHashProvider
{
+ public static int MacData(
+ string hashAlgorithmId,
+ ReadOnlySpan<byte> key,
+ ReadOnlySpan<byte> source,
+ Span<byte> destination)
+ {
+ IntPtr evpType = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId);
+ Debug.Assert(evpType != IntPtr.Zero);
+
+ int hashSize = Interop.Crypto.EvpMdSize(evpType);
+
+ if (hashSize <= 0 || destination.Length < hashSize)
+ {
+ Debug.Fail("Destination length or hash size not valid.");
+ throw new CryptographicException();
+ }
+
+ int written = Interop.Crypto.HmacOneShot(evpType, key, source, destination);
+ Debug.Assert(written == hashSize);
+ return written;
+ }
+
public static unsafe int HashData(string hashAlgorithmId, ReadOnlySpan<byte> source, Span<byte> destination)
{
IntPtr evpType = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId);
public static class OneShotHashProvider
{
+ public static unsafe int MacData(
+ string hashAlgorithmId,
+ ReadOnlySpan<byte> key,
+ ReadOnlySpan<byte> source,
+ Span<byte> destination)
+ {
+ int hashSize; // in bytes
+
+ // Use a pseudo-handle if available.
+ if (Interop.BCrypt.PseudoHandlesSupported)
+ {
+ HashDataUsingPseudoHandle(hashAlgorithmId, source, key, isHmac: true, destination, out hashSize);
+ return hashSize;
+ }
+ else
+ {
+ // Pseudo-handle not available. Fall back to a shared handle with no using or dispose.
+ SafeBCryptAlgorithmHandle cachedAlgorithmHandle = BCryptAlgorithmCache.GetCachedBCryptAlgorithmHandle(
+ hashAlgorithmId,
+ BCryptOpenAlgorithmProviderFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG,
+ out hashSize);
+
+ if (destination.Length < hashSize)
+ {
+ Debug.Fail("Caller should have checked length.");
+ throw new CryptographicException();
+ }
+
+ HashUpdateAndFinish(cachedAlgorithmHandle, hashSize, key, source, destination);
+
+ return hashSize;
+ }
+ }
+
public static unsafe int HashData(string hashAlgorithmId, ReadOnlySpan<byte> source, Span<byte> destination)
{
int hashSize; // in bytes
- // Try using a pseudo-handle if available.
+ // Use a pseudo-handle if available.
if (Interop.BCrypt.PseudoHandlesSupported)
{
- HashDataUsingPseudoHandle(hashAlgorithmId, source, destination, out hashSize);
+ HashDataUsingPseudoHandle(hashAlgorithmId, source, key: default, isHmac : false, destination, out hashSize);
return hashSize;
}
else
throw new CryptographicException();
}
- HashUpdateAndFinish(cachedAlgorithmHandle, hashSize, source, destination);
+ HashUpdateAndFinish(cachedAlgorithmHandle, hashSize, key: default, source, destination);
return hashSize;
}
}
- private static unsafe void HashDataUsingPseudoHandle(string hashAlgorithmId, ReadOnlySpan<byte> source, Span<byte> destination, out int hashSize)
+ private static unsafe void HashDataUsingPseudoHandle(
+ string hashAlgorithmId,
+ ReadOnlySpan<byte> source,
+ ReadOnlySpan<byte> key,
+ bool isHmac,
+ Span<byte> destination,
+ out int hashSize)
{
hashSize = default;
+ Debug.Assert(isHmac ? true : key.IsEmpty);
+
Interop.BCrypt.BCryptAlgPseudoHandle algHandle;
int digestSizeInBytes;
if (hashAlgorithmId == HashAlgorithmNames.MD5)
{
- algHandle = Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_MD5_ALG_HANDLE;
+ algHandle = isHmac ?
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_HMAC_MD5_ALG_HANDLE :
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_MD5_ALG_HANDLE;
digestSizeInBytes = 128 / 8;
}
else if (hashAlgorithmId == HashAlgorithmNames.SHA1)
{
- algHandle = Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA1_ALG_HANDLE;
+ algHandle = isHmac ?
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_HMAC_SHA1_ALG_HANDLE :
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA1_ALG_HANDLE;
digestSizeInBytes = 160 / 8;
}
else if (hashAlgorithmId == HashAlgorithmNames.SHA256)
{
- algHandle = Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA256_ALG_HANDLE;
+ algHandle = isHmac ?
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_HMAC_SHA256_ALG_HANDLE :
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA256_ALG_HANDLE;
digestSizeInBytes = 256 / 8;
}
else if (hashAlgorithmId == HashAlgorithmNames.SHA384)
{
- algHandle = Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA384_ALG_HANDLE;
+ algHandle = isHmac ?
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_HMAC_SHA384_ALG_HANDLE :
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA384_ALG_HANDLE;
digestSizeInBytes = 384 / 8;
}
else if (hashAlgorithmId == HashAlgorithmNames.SHA512)
{
- algHandle = Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA512_ALG_HANDLE;
+ algHandle = isHmac ?
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_HMAC_SHA512_ALG_HANDLE :
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA512_ALG_HANDLE;
digestSizeInBytes = 512 / 8;
}
else
throw new CryptographicException();
}
+ fixed (byte* pKey = &MemoryMarshal.GetReference(key))
fixed (byte* pSrc = &MemoryMarshal.GetReference(source))
fixed (byte* pDest = &MemoryMarshal.GetReference(destination))
{
- NTSTATUS ntStatus = Interop.BCrypt.BCryptHash((uint)algHandle, pbSecret: null, cbSecret: 0, pSrc, source.Length, pDest, digestSizeInBytes);
+ NTSTATUS ntStatus = Interop.BCrypt.BCryptHash((uint)algHandle, pKey, key.Length, pSrc, source.Length, pDest, digestSizeInBytes);
if (ntStatus != NTSTATUS.STATUS_SUCCESS)
{
private static void HashUpdateAndFinish(
SafeBCryptAlgorithmHandle algHandle,
int hashSize,
+ ReadOnlySpan<byte> key,
ReadOnlySpan<byte> source,
Span<byte> destination)
{
out SafeBCryptHashHandle hHash,
IntPtr.Zero,
0,
- default,
- 0,
+ key,
+ key.Length,
BCryptCreateHashFlags.None);
if (ntStatus != NTSTATUS.STATUS_SUCCESS)
// 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.Runtime.Versioning;
using Internal.Cryptography;
[UnsupportedOSPlatform("browser")]
public class HMACMD5 : HMAC
{
+ private const int HmacSizeBits = 128;
+ private const int HmacSizeBytes = HmacSizeBits / 8;
+
public HMACMD5()
: this(RandomNumberGenerator.GetBytes(BlockSize))
{
// we just want to be explicit in all HMAC extended classes
BlockSizeValue = BlockSize;
HashSizeValue = _hMacCommon.HashSizeInBits;
+ Debug.Assert(HashSizeValue == HmacSizeBits);
}
public override byte[] Key
public override void Initialize() => _hMacCommon.Reset();
+ /// <summary>
+ /// Computes the HMAC of data using the MD5 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="key" /> or <paramref name="source" /> is <see langword="null" />.
+ /// </exception>
+ public static byte[] HashData(byte[] key, byte[] source)
+ {
+ if (key is null)
+ throw new ArgumentNullException(nameof(key));
+ if (source is null)
+ throw new ArgumentNullException(nameof(source));
+
+ return HashData(new ReadOnlySpan<byte>(key), new ReadOnlySpan<byte>(source));
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the MD5 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source)
+ {
+ byte[] buffer = new byte[HmacSizeBytes];
+
+ int written = HashData(key, source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the MD5 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <returns>The total number of bytes written to <paramref name="destination" />.</returns>
+ /// <exception cref="ArgumentException">
+ /// The buffer in <paramref name="destination"/> is too small to hold the calculated hash
+ /// size. The MD5 algorithm always produces a 128-bit HMAC, or 16 bytes.
+ /// </exception>
+ public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
+ {
+ if (!TryHashData(key, source, destination, out int bytesWritten))
+ {
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+ }
+
+ return bytesWritten;
+ }
+
+ /// <summary>
+ /// Attempts to compute the HMAC of data using the MD5 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <param name="bytesWritten">
+ /// When this method returns, the total number of bytes written into <paramref name="destination"/>.
+ /// </param>
+ /// <returns>
+ /// <see langword="false"/> if <paramref name="destination"/> is too small to hold the
+ /// calculated hash, <see langword="true"/> otherwise.
+ /// </returns>
+ public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ {
+ if (destination.Length < HmacSizeBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.MD5, key, source, destination);
+ Debug.Assert(bytesWritten == HmacSizeBytes);
+
+ return true;
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing)
using Internal.Cryptography;
using System.ComponentModel;
+using System.Diagnostics;
using System.Runtime.Versioning;
namespace System.Security.Cryptography
[UnsupportedOSPlatform("browser")]
public class HMACSHA1 : HMAC
{
+ private const int HmacSizeBits = 160;
+ private const int HmacSizeBytes = HmacSizeBits / 8;
+
public HMACSHA1()
: this(RandomNumberGenerator.GetBytes(BlockSize))
{
// we just want to be explicit in all HMAC extended classes
BlockSizeValue = BlockSize;
HashSizeValue = _hMacCommon.HashSizeInBits;
+ Debug.Assert(HashSizeValue == HmacSizeBits);
}
[EditorBrowsable(EditorBrowsableState.Never)]
public override void Initialize() => _hMacCommon.Reset();
+ /// <summary>
+ /// Computes the HMAC of data using the SHA1 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="key" /> or <paramref name="source" /> is <see langword="null" />.
+ /// </exception>
+ public static byte[] HashData(byte[] key, byte[] source)
+ {
+ if (key is null)
+ throw new ArgumentNullException(nameof(key));
+ if (source is null)
+ throw new ArgumentNullException(nameof(source));
+
+ return HashData(new ReadOnlySpan<byte>(key), new ReadOnlySpan<byte>(source));
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the SHA1 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source)
+ {
+ byte[] buffer = new byte[HmacSizeBytes];
+
+ int written = HashData(key, source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the SHA1 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <returns>The total number of bytes written to <paramref name="destination" />.</returns>
+ /// <exception cref="ArgumentException">
+ /// The buffer in <paramref name="destination"/> is too small to hold the calculated hash
+ /// size. The SHA1 algorithm always produces a 160-bit HMAC, or 20 bytes.
+ /// </exception>
+ public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
+ {
+ if (!TryHashData(key, source, destination, out int bytesWritten))
+ {
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+ }
+
+ return bytesWritten;
+ }
+
+ /// <summary>
+ /// Attempts to compute the HMAC of data using the SHA1 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <param name="bytesWritten">
+ /// When this method returns, the total number of bytes written into <paramref name="destination"/>.
+ /// </param>
+ /// <returns>
+ /// <see langword="false"/> if <paramref name="destination"/> is too small to hold the
+ /// calculated hash, <see langword="true"/> otherwise.
+ /// </returns>
+ public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ {
+ if (destination.Length < HmacSizeBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA1, key, source, destination);
+ Debug.Assert(bytesWritten == HmacSizeBytes);
+
+ return true;
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
+using Internal.Cryptography;
using System.Diagnostics;
using System.Runtime.Versioning;
using System.Security.Cryptography;
-using Internal.Cryptography;
namespace System.Security.Cryptography
{
[UnsupportedOSPlatform("browser")]
public class HMACSHA256 : HMAC
{
+ private const int HmacSizeBits = 256;
+ private const int HmacSizeBytes = HmacSizeBits / 8;
+
public HMACSHA256()
: this(RandomNumberGenerator.GetBytes(BlockSize))
{
// we just want to be explicit in all HMAC extended classes
BlockSizeValue = BlockSize;
HashSizeValue = _hMacCommon.HashSizeInBits;
+ Debug.Assert(HashSizeValue == HmacSizeBits);
}
public override byte[] Key
public override void Initialize() => _hMacCommon.Reset();
+ /// <summary>
+ /// Computes the HMAC of data using the SHA256 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="key" /> or <paramref name="source" /> is <see langword="null" />.
+ /// </exception>
+ public static byte[] HashData(byte[] key, byte[] source)
+ {
+ if (key is null)
+ throw new ArgumentNullException(nameof(key));
+ if (source is null)
+ throw new ArgumentNullException(nameof(source));
+
+ return HashData(new ReadOnlySpan<byte>(key), new ReadOnlySpan<byte>(source));
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the SHA256 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source)
+ {
+ byte[] buffer = new byte[HmacSizeBytes];
+
+ int written = HashData(key, source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the SHA256 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <returns>The total number of bytes written to <paramref name="destination" />.</returns>
+ /// <exception cref="ArgumentException">
+ /// The buffer in <paramref name="destination"/> is too small to hold the calculated hash
+ /// size. The SHA256 algorithm always produces a 256-bit HMAC, or 32 bytes.
+ /// </exception>
+ public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
+ {
+ if (!TryHashData(key, source, destination, out int bytesWritten))
+ {
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+ }
+
+ return bytesWritten;
+ }
+
+ /// <summary>
+ /// Attempts to compute the HMAC of data using the SHA256 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <param name="bytesWritten">
+ /// When this method returns, the total number of bytes written into <paramref name="destination"/>.
+ /// </param>
+ /// <returns>
+ /// <see langword="false"/> if <paramref name="destination"/> is too small to hold the
+ /// calculated hash, <see langword="true"/> otherwise.
+ /// </returns>
+ public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ {
+ if (destination.Length < HmacSizeBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA256, key, source, destination);
+ Debug.Assert(bytesWritten == HmacSizeBytes);
+
+ return true;
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
+using Internal.Cryptography;
using System.Diagnostics;
using System.Runtime.Versioning;
using System.Security.Cryptography;
-using Internal.Cryptography;
namespace System.Security.Cryptography
{
[UnsupportedOSPlatform("browser")]
public class HMACSHA384 : HMAC
{
+ private const int HmacSizeBits = 384;
+ private const int HmacSizeBytes = HmacSizeBits / 8;
+
public HMACSHA384()
: this(RandomNumberGenerator.GetBytes(BlockSize))
{
// change the default value of BlockSizeValue to 128 instead of 64
BlockSizeValue = BlockSize;
HashSizeValue = _hMacCommon.HashSizeInBits;
+ Debug.Assert(HashSizeValue == HmacSizeBits);
}
public bool ProduceLegacyHmacValues
public override void Initialize() => _hMacCommon.Reset();
+ /// <summary>
+ /// Computes the HMAC of data using the SHA384 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="key" /> or <paramref name="source" /> is <see langword="null" />.
+ /// </exception>
+ public static byte[] HashData(byte[] key, byte[] source)
+ {
+ if (key is null)
+ throw new ArgumentNullException(nameof(key));
+ if (source is null)
+ throw new ArgumentNullException(nameof(source));
+
+ return HashData(new ReadOnlySpan<byte>(key), new ReadOnlySpan<byte>(source));
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the SHA384 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source)
+ {
+ byte[] buffer = new byte[HmacSizeBytes];
+
+ int written = HashData(key, source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the SHA384 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <returns>The total number of bytes written to <paramref name="destination" />.</returns>
+ /// <exception cref="ArgumentException">
+ /// The buffer in <paramref name="destination"/> is too small to hold the calculated hash
+ /// size. The SHA384 algorithm always produces a 384-bit HMAC, or 48 bytes.
+ /// </exception>
+ public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
+ {
+ if (!TryHashData(key, source, destination, out int bytesWritten))
+ {
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+ }
+
+ return bytesWritten;
+ }
+
+ /// <summary>
+ /// Attempts to compute the HMAC of data using the SHA384 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <param name="bytesWritten">
+ /// When this method returns, the total number of bytes written into <paramref name="destination"/>.
+ /// </param>
+ /// <returns>
+ /// <see langword="false"/> if <paramref name="destination"/> is too small to hold the
+ /// calculated hash, <see langword="true"/> otherwise.
+ /// </returns>
+ public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ {
+ if (destination.Length < HmacSizeBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA384, key, source, destination);
+ Debug.Assert(bytesWritten == HmacSizeBytes);
+
+ return true;
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
+using Internal.Cryptography;
using System.Diagnostics;
using System.Runtime.Versioning;
using System.Security.Cryptography;
-using Internal.Cryptography;
namespace System.Security.Cryptography
{
[UnsupportedOSPlatform("browser")]
public class HMACSHA512 : HMAC
{
+ private const int HmacSizeBits = 512;
+ private const int HmacSizeBytes = HmacSizeBits / 8;
+
public HMACSHA512()
: this(RandomNumberGenerator.GetBytes(BlockSize))
{
public override void Initialize() => _hMacCommon.Reset();
+ /// <summary>
+ /// Computes the HMAC of data using the SHA512 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="key" /> or <paramref name="source" /> is <see langword="null" />.
+ /// </exception>
+ public static byte[] HashData(byte[] key, byte[] source)
+ {
+ if (key is null)
+ throw new ArgumentNullException(nameof(key));
+ if (source is null)
+ throw new ArgumentNullException(nameof(source));
+
+ return HashData(new ReadOnlySpan<byte>(key), new ReadOnlySpan<byte>(source));
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the SHA512 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <returns>The HMAC of the data.</returns>
+ public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source)
+ {
+ byte[] buffer = new byte[HmacSizeBytes];
+
+ int written = HashData(key, source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ /// <summary>
+ /// Computes the HMAC of data using the SHA512 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <returns>The total number of bytes written to <paramref name="destination" />.</returns>
+ /// <exception cref="ArgumentException">
+ /// The buffer in <paramref name="destination"/> is too small to hold the calculated hash
+ /// size. The SHA512 algorithm always produces a 512-bit HMAC, or 64 bytes.
+ /// </exception>
+ public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
+ {
+ if (!TryHashData(key, source, destination, out int bytesWritten))
+ {
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+ }
+
+ return bytesWritten;
+ }
+
+ /// <summary>
+ /// Attempts to compute the HMAC of data using the SHA512 algorithm.
+ /// </summary>
+ /// <param name="key">The HMAC key.</param>
+ /// <param name="source">The data to HMAC.</param>
+ /// <param name="destination">The buffer to receive the HMAC value.</param>
+ /// <param name="bytesWritten">
+ /// When this method returns, the total number of bytes written into <paramref name="destination"/>.
+ /// </param>
+ /// <returns>
+ /// <see langword="false"/> if <paramref name="destination"/> is too small to hold the
+ /// calculated hash, <see langword="true"/> otherwise.
+ /// </returns>
+ public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ {
+ if (destination.Length < HmacSizeBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA512, key, source, destination);
+ Debug.Assert(bytesWritten == HmacSizeBytes);
+
+ return true;
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing)
ByteUtils.RepeatByte(0xaa, 80),
};
- public HmacMD5Tests()
- : base(s_testKeys2202)
+ private static readonly byte[][] s_testMacs2202 =
{
- }
+ null,
+ ByteUtils.HexToByteArray("9294727a3638bb1c13f48ef8158bfc9d"),
+ ByteUtils.HexToByteArray("750c783e6ab0b503eaa86e310a5db738"),
+ ByteUtils.HexToByteArray("56be34521d144c88dbb8c733f0e8b3f6"),
+ ByteUtils.HexToByteArray("697eaf0aca3a3aea3a75164746ffaa79"),
+ ByteUtils.HexToByteArray("56461ef2342edc00f9bab995690efd4c"),
+ ByteUtils.HexToByteArray("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"),
+ ByteUtils.HexToByteArray("6f630fad67cda0ee1fb1f562db3aa53e"),
+ };
- protected override HMAC Create()
+ public HmacMD5Tests()
+ : base(s_testKeys2202, s_testMacs2202)
{
- return new HMACMD5();
}
- protected override HashAlgorithm CreateHashAlgorithm()
- {
- return MD5.Create();
- }
+ protected override int BlockSize => 64;
+ protected override int MacSize => 16;
+
+ protected override HMAC Create() => new HMACMD5();
+ protected override HashAlgorithm CreateHashAlgorithm() => MD5.Create();
+ protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
+ HMACMD5.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source) =>
+ HMACMD5.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination) =>
+ HMACMD5.HashData(key, source, destination);
- protected override int BlockSize { get { return 64; } }
+ protected override bool TryHashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int written) =>
+ HMACMD5.TryHashData(key, source, destination, out written);
[Fact]
public void HmacMD5_Rfc2202_1()
{
- VerifyHmac(1, "9294727a3638bb1c13f48ef8158bfc9d");
+ VerifyHmac(1, s_testMacs2202[1]);
}
[Fact]
public void HmacMD5_Rfc2202_2()
{
- VerifyHmac(2, "750c783e6ab0b503eaa86e310a5db738");
+ VerifyHmac(2, s_testMacs2202[2]);
}
[Fact]
public void HmacMD5_Rfc2202_3()
{
- VerifyHmac(3, "56be34521d144c88dbb8c733f0e8b3f6");
+ VerifyHmac(3, s_testMacs2202[3]);
}
[Fact]
public void HmacMD5_Rfc2202_4()
{
- VerifyHmac(4, "697eaf0aca3a3aea3a75164746ffaa79");
+ VerifyHmac(4, s_testMacs2202[4]);
}
[Fact]
public void HmacMD5_Rfc2202_5()
{
- VerifyHmac(5, "56461ef2342edc00f9bab995690efd4c");
+ VerifyHmac(5, s_testMacs2202[5]);
}
[Fact]
public void HmacMD5_Rfc2202_6()
{
- VerifyHmac(6, "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd");
+ VerifyHmac(6, s_testMacs2202[6]);
}
[Fact]
public void HmacMD5_Rfc2202_7()
{
- VerifyHmac(7, "6f630fad67cda0ee1fb1f562db3aa53e");
+ VerifyHmac(7, s_testMacs2202[7]);
}
[Fact]
ByteUtils.RepeatByte(0xaa, 80),
};
- public HmacSha1Tests()
- : base(s_testKeys2202)
+ private static readonly byte[][] s_testMacs2202 =
{
- }
+ null,
+ ByteUtils.HexToByteArray("b617318655057264e28bc0b6fb378c8ef146be00"),
+ ByteUtils.HexToByteArray("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"),
+ ByteUtils.HexToByteArray("125d7342b9ac11cd91a39af48aa17b4f63f175d3"),
+ ByteUtils.HexToByteArray("4c9007f4026250c6bc8414f9bf50c86c2d7235da"),
+ ByteUtils.HexToByteArray("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
+ ByteUtils.HexToByteArray("aa4ae5e15272d00e95705637ce8a3b55ed402112"),
+ ByteUtils.HexToByteArray("e8e99d0f45237d786d6bbaa7965c7808bbff1a91"),
+ };
- protected override HMAC Create()
+ public HmacSha1Tests()
+ : base(s_testKeys2202, s_testMacs2202)
{
- return new HMACSHA1();
}
- protected override HashAlgorithm CreateHashAlgorithm()
- {
- return SHA1.Create();
- }
+ protected override int BlockSize => 64;
+ protected override int MacSize => 20;
+
+ protected override HMAC Create() => new HMACSHA1();
+ protected override HashAlgorithm CreateHashAlgorithm() => SHA1.Create();
+ protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
+ HMACSHA1.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source) =>
+ HMACSHA1.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination) =>
+ HMACSHA1.HashData(key, source, destination);
- protected override int BlockSize { get { return 64; } }
+ protected override bool TryHashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int written) =>
+ HMACSHA1.TryHashData(key, source, destination, out written);
[Fact]
public void HmacSha1_Byte_Constructors()
[Fact]
public void HmacSha1_Rfc2202_1()
{
- VerifyHmac(1, "b617318655057264e28bc0b6fb378c8ef146be00");
+ VerifyHmac(1, s_testMacs2202[1]);
}
[Fact]
public void HmacSha1_Rfc2202_2()
{
- VerifyHmac(2, "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79");
+ VerifyHmac(2, s_testMacs2202[2]);
}
[Fact]
public void HmacSha1_Rfc2202_3()
{
- VerifyHmac(3, "125d7342b9ac11cd91a39af48aa17b4f63f175d3");
+ VerifyHmac(3, s_testMacs2202[3]);
}
[Fact]
public void HmacSha1_Rfc2202_4()
{
- VerifyHmac(4, "4c9007f4026250c6bc8414f9bf50c86c2d7235da");
+ VerifyHmac(4, s_testMacs2202[4]);
}
[Fact]
public void HmacSha1_Rfc2202_5()
{
- VerifyHmac(5, "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04");
+ VerifyHmac(5, s_testMacs2202[5]);
}
[Fact]
public void HmacSha1_Rfc2202_6()
{
- VerifyHmac(6, "aa4ae5e15272d00e95705637ce8a3b55ed402112");
+ VerifyHmac(6, s_testMacs2202[6]);
}
[Fact]
public void HmacSha1_Rfc2202_7()
{
- VerifyHmac(7, "e8e99d0f45237d786d6bbaa7965c7808bbff1a91");
+ VerifyHmac(7, s_testMacs2202[7]);
}
[Fact]
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Test.Cryptography;
using Xunit;
namespace System.Security.Cryptography.Hashing.Algorithms.Tests
[SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")]
public class HmacSha256Tests : Rfc4231HmacTests
{
- protected override HMAC Create()
+ protected override int BlockSize => 64;
+ protected override int MacSize => 32;
+
+ protected override HMAC Create() => new HMACSHA256();
+ protected override HashAlgorithm CreateHashAlgorithm() => SHA256.Create();
+ protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
+ HMACSHA256.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source) =>
+ HMACSHA256.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination) =>
+ HMACSHA256.HashData(key, source, destination);
+
+ protected override bool TryHashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int written) =>
+ HMACSHA256.TryHashData(key, source, destination, out written);
+
+ private static byte[][] s_testMacs4231 =
{
- return new HMACSHA256();
- }
+ null,
+ ByteUtils.HexToByteArray("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"),
+ ByteUtils.HexToByteArray("5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"),
+ ByteUtils.HexToByteArray("773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"),
+ ByteUtils.HexToByteArray("82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"),
+ // RFC 4231 only defines the first 128 bits of this value.
+ ByteUtils.HexToByteArray("a3b6167473100ee06e0c796c2955552b"),
+ ByteUtils.HexToByteArray("60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"),
+ ByteUtils.HexToByteArray("9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"),
+ };
- protected override HashAlgorithm CreateHashAlgorithm()
+ public HmacSha256Tests() : base(s_testMacs4231)
{
- return SHA256.Create();
}
- protected override int BlockSize { get { return 64; } }
-
[Fact]
public void HmacSha256_Rfc4231_1()
{
- VerifyHmac(1, "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7");
+ VerifyHmac(1, s_testMacs4231[1]);
}
[Fact]
public void HmacSha256_Rfc4231_2()
{
- VerifyHmac(2, "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843");
+ VerifyHmac(2, s_testMacs4231[2]);
}
[Fact]
public void HmacSha256_Rfc4231_3()
{
- VerifyHmac(3, "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe");
+ VerifyHmac(3, s_testMacs4231[3]);
}
[Fact]
public void HmacSha256_Rfc4231_4()
{
- VerifyHmac(4, "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b");
+ VerifyHmac(4, s_testMacs4231[4]);
}
[Fact]
public void HmacSha256_Rfc4231_5()
{
- // RFC 4231 only defines the first 128 bits of this value.
- VerifyHmac(5, "a3b6167473100ee06e0c796c2955552b", 128 / 8);
+ VerifyHmac(5, s_testMacs4231[5]);
}
[Fact]
public void HmacSha256_Rfc4231_6()
{
- VerifyHmac(6, "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54");
+ VerifyHmac(6, s_testMacs4231[6]);
}
[Fact]
public void HmacSha256_Rfc4231_7()
{
- VerifyHmac(7, "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2");
+ VerifyHmac(7, s_testMacs4231[7]);
}
[Fact]
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Test.Cryptography;
using Xunit;
namespace System.Security.Cryptography.Hashing.Algorithms.Tests
[SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")]
public class HmacSha384Tests : Rfc4231HmacTests
{
- protected override HMAC Create()
+ protected override int BlockSize => 128;
+ protected override int MacSize => 48;
+
+ protected override HMAC Create() => new HMACSHA384();
+ protected override HashAlgorithm CreateHashAlgorithm() => SHA384.Create();
+ protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
+ HMACSHA384.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source) =>
+ HMACSHA384.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination) =>
+ HMACSHA384.HashData(key, source, destination);
+
+ protected override bool TryHashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int written) =>
+ HMACSHA384.TryHashData(key, source, destination, out written);
+
+ private static byte[][] s_testMacs4231 =
{
- return new HMACSHA384();
- }
+ null,
+ ByteUtils.HexToByteArray("afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6"),
+ ByteUtils.HexToByteArray("af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649"),
+ ByteUtils.HexToByteArray("88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27"),
+ ByteUtils.HexToByteArray("3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb"),
+ // RFC 4231 only defines the first 128 bits of this value.
+ ByteUtils.HexToByteArray("3abf34c3503b2a23a46efc619baef897"),
+ ByteUtils.HexToByteArray("4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952"),
+ ByteUtils.HexToByteArray("6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e"),
+ };
- protected override HashAlgorithm CreateHashAlgorithm()
+ public HmacSha384Tests() : base(s_testMacs4231)
{
- return SHA384.Create();
}
- protected override int BlockSize { get { return 128; } }
-
[Fact]
public void ProduceLegacyHmacValues()
{
[Fact]
public void HmacSha384_Rfc4231_1()
{
- VerifyHmac(1, "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6");
+ VerifyHmac(1, s_testMacs4231[1]);
}
[Fact]
public void HmacSha384_Rfc4231_2()
{
- VerifyHmac(2, "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649");
+ VerifyHmac(2, s_testMacs4231[2]);
}
[Fact]
public void HmacSha384_Rfc4231_3()
{
- VerifyHmac(3, "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27");
+ VerifyHmac(3, s_testMacs4231[3]);
}
[Fact]
public void HmacSha384_Rfc4231_4()
{
- VerifyHmac(4, "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb");
+ VerifyHmac(4, s_testMacs4231[4]);
}
[Fact]
public void HmacSha384_Rfc4231_5()
{
- // RFC 4231 only defines the first 128 bits of this value.
- VerifyHmac(5, "3abf34c3503b2a23a46efc619baef897", 128 / 8);
+ VerifyHmac(5, s_testMacs4231[5]);
}
[Fact]
public void HmacSha384_Rfc4231_6()
{
- VerifyHmac(6, "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952");
+ VerifyHmac(6, s_testMacs4231[6]);
}
[Fact]
public void HmacSha384_Rfc4231_7()
{
- VerifyHmac(7, "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e");
+ VerifyHmac(7, s_testMacs4231[7]);
}
[Fact]
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Test.Cryptography;
using Xunit;
namespace System.Security.Cryptography.Hashing.Algorithms.Tests
[SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")]
public class HmacSha512Tests : Rfc4231HmacTests
{
- protected override HMAC Create()
+ protected override int BlockSize => 128;
+ protected override int MacSize => 64;
+
+ protected override HMAC Create() => new HMACSHA512();
+ protected override HashAlgorithm CreateHashAlgorithm() => SHA512.Create();
+ protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
+ HMACSHA512.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source) =>
+ HMACSHA512.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination) =>
+ HMACSHA512.HashData(key, source, destination);
+
+ protected override bool TryHashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int written) =>
+ HMACSHA512.TryHashData(key, source, destination, out written);
+
+ private static byte[][] s_testMacs4231 =
{
- return new HMACSHA512();
- }
+ null,
+ ByteUtils.HexToByteArray("87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"),
+ ByteUtils.HexToByteArray("164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737"),
+ ByteUtils.HexToByteArray("fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb"),
+ ByteUtils.HexToByteArray("b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd"),
+ // RFC 4231 only defines the first 128 bits of this value.
+ ByteUtils.HexToByteArray("415fad6271580a531d4179bc891d87a6"),
+ ByteUtils.HexToByteArray("80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598"),
+ ByteUtils.HexToByteArray("e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"),
+ };
- protected override HashAlgorithm CreateHashAlgorithm()
+ public HmacSha512Tests() : base(s_testMacs4231)
{
- return SHA512.Create();
}
- protected override int BlockSize { get { return 128; } }
-
[Fact]
public void ProduceLegacyHmacValues()
{
[Fact]
public void HmacSha512_Rfc4231_1()
{
- VerifyHmac(1, "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854");
+ VerifyHmac(1, s_testMacs4231[1]);
}
[Fact]
public void HmacSha512_Rfc4231_2()
{
- VerifyHmac(2, "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737");
+ VerifyHmac(2, s_testMacs4231[2]);
}
[Fact]
public void HmacSha512_Rfc4231_3()
{
- VerifyHmac(3, "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb");
+ VerifyHmac(3, s_testMacs4231[3]);
}
[Fact]
public void HmacSha512_Rfc4231_4()
{
- VerifyHmac(4, "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd");
+ VerifyHmac(4, s_testMacs4231[4]);
}
[Fact]
public void HmacSha512_Rfc4231_5()
{
- // RFC 4231 only defines the first 128 bits of this value.
- VerifyHmac(5, "415fad6271580a531d4179bc891d87a6", 128 / 8);
+ VerifyHmac(5, s_testMacs4231[5]);
}
[Fact]
public void HmacSha512_Rfc4231_6()
{
- VerifyHmac(6, "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598");
+ VerifyHmac(6, s_testMacs4231[6]);
}
[Fact]
public void HmacSha512_Rfc4231_7()
{
- VerifyHmac(7, "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58");
+ VerifyHmac(7, s_testMacs4231[7]);
}
[Fact]
// They share the same datasets for cases 1-5, but cases 6 and 7 differ.
private readonly byte[][] _testKeys;
private readonly byte[][] _testData;
+ private readonly byte[][] _testMacs;
- protected HmacTests(byte[][] testKeys, byte[][] testData)
+ protected HmacTests(byte[][] testKeys, byte[][] testData, byte[][] testMacs)
{
_testKeys = testKeys;
_testData = testData;
+ _testMacs = testMacs;
}
protected abstract HMAC Create();
protected abstract HashAlgorithm CreateHashAlgorithm();
+ protected abstract byte[] HashDataOneShot(byte[] key, byte[] source);
+ protected abstract byte[] HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
+ protected abstract int HashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
+ protected abstract bool TryHashDataOneShot(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int written);
protected abstract int BlockSize { get; }
+ protected abstract int MacSize { get; }
- protected void VerifyHmac(
- int testCaseId,
- string digest,
- int truncateSize = -1)
+ protected void VerifyHmac(int testCaseId, byte[] digestBytes)
{
- byte[] digestBytes = ByteUtils.HexToByteArray(digest);
byte[] data = _testData[testCaseId];
byte[] computedDigest;
+ int truncateSize = digestBytes.Length;
+ AssertExtensions.LessThanOrEqualTo(truncateSize, MacSize);
using (HMAC hmac = Create())
{
- Assert.True(hmac.HashSize > 0);
+ Assert.Equal(MacSize, hmac.HashSize / 8);
byte[] key = (byte[])_testKeys[testCaseId].Clone();
hmac.Key = key;
computedDigest = hmac.ComputeHash(data);
}
- if (truncateSize != -1)
- {
- byte[] tmp = new byte[truncateSize];
- Array.Copy(computedDigest, tmp, truncateSize);
- computedDigest = tmp;
- }
-
+ computedDigest = Truncate(computedDigest, truncateSize);
Assert.Equal(digestBytes, computedDigest);
using (HMAC hmac = Create())
computedDigest = hmac.Hash;
}
- if (truncateSize != -1)
- {
- byte[] tmp = new byte[truncateSize];
- Array.Copy(computedDigest, tmp, truncateSize);
- computedDigest = tmp;
- }
+ computedDigest = Truncate(computedDigest, truncateSize);
+ Assert.Equal(digestBytes, computedDigest);
+
+ // One shot - allocating and byte array inputs
+ computedDigest = HashDataOneShot(_testKeys[testCaseId], data);
+ computedDigest = Truncate(computedDigest, truncateSize);
Assert.Equal(digestBytes, computedDigest);
+
+ static byte[] Truncate(byte[] digest, int truncateSize)
+ {
+ if (truncateSize == -1)
+ return digest;
+
+ return digest.AsSpan(0, truncateSize).ToArray();
+ }
}
protected void VerifyHmac_KeyAlreadySet(
AssertExtensions.Throws<ArgumentNullException>("value", () => hash.Key = null);
}
}
+
+ [Fact]
+ public void OneShot_NullKey_ArgumentNullException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("key", () =>
+ HashDataOneShot(key: (byte[])null, source: Array.Empty<byte>()));
+ }
+
+ [Fact]
+ public void OneShot_NullSource_ArgumentNullException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("source", () =>
+ HashDataOneShot(key: Array.Empty<byte>(), source: (byte[])null));
+ }
+
+ [Fact]
+ public void OneShot_ExistingBuffer_TooSmall()
+ {
+ byte[] buffer = new byte[MacSize - 1];
+ byte[] key = _testKeys[1];
+ byte[] data = _testData[1];
+
+ AssertExtensions.Throws<ArgumentException>("destination", () =>
+ HashDataOneShot(key, data, buffer));
+
+ AssertExtensions.FilledWith<byte>(0, buffer);
+ }
+
+ [Fact]
+ public void OneShot_TryExistingBuffer_TooSmall()
+ {
+ byte[] buffer = new byte[MacSize - 1];
+ byte[] key = _testKeys[1];
+ byte[] data = _testData[1];
+
+ Assert.False(TryHashDataOneShot(key, data, buffer, out int written));
+ Assert.Equal(0, written);
+ AssertExtensions.FilledWith<byte>(0, buffer);
+ }
+
+ [Fact]
+ public void OneShot_TryExistingBuffer_Exact()
+ {
+ for (int caseId = 1; caseId <= 7; caseId++)
+ {
+ byte[] buffer = new byte[MacSize];
+ byte[] key = _testKeys[caseId];
+ byte[] data = _testData[caseId];
+
+ Assert.True(TryHashDataOneShot(key, data, buffer, out int written));
+ Assert.Equal(MacSize, written);
+
+ ReadOnlySpan<byte> expectedMac = _testMacs[caseId];
+ Span<byte> truncatedBuffer = buffer.AsSpan(0, expectedMac.Length);
+ AssertExtensions.SequenceEqual(expectedMac, truncatedBuffer);
+ }
+ }
+
+ [Fact]
+ public void OneShot_TryExistingBuffer_Larger()
+ {
+ for (int caseId = 1; caseId <= 7; caseId++)
+ {
+ Span<byte> buffer = new byte[MacSize + 20];
+ byte[] key = _testKeys[caseId];
+ byte[] data = _testData[caseId];
+
+ buffer.Fill(0xCC);
+ Span<byte> writeBuffer = buffer.Slice(10, MacSize);
+
+ Assert.True(TryHashDataOneShot(key, data, writeBuffer, out int written));
+ Assert.Equal(MacSize, written);
+
+ ReadOnlySpan<byte> expectedMac = _testMacs[caseId];
+ Span<byte> truncatedWriteBuffer = writeBuffer.Slice(0, expectedMac.Length);
+ AssertExtensions.SequenceEqual(expectedMac, truncatedWriteBuffer);
+ AssertExtensions.FilledWith<byte>(0xCC, buffer[..10]);
+ AssertExtensions.FilledWith<byte>(0xCC, buffer[^10..]);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 10)]
+ [InlineData(10, 10)]
+ [InlineData(10, 0)]
+ [InlineData(10, 20)]
+ public void OneShot_TryExistingBuffer_OverlapsKey(int keyOffset, int bufferOffset)
+ {
+ for (int caseId = 1; caseId <= 7; caseId++)
+ {
+ byte[] key = _testKeys[caseId];
+ byte[] data = _testData[caseId];
+ Span<byte> buffer = new byte[Math.Max(key.Length, MacSize) + Math.Max(keyOffset, bufferOffset)];
+
+ Span<byte> writeBuffer = buffer.Slice(bufferOffset, MacSize);
+ Span<byte> keyBuffer = buffer.Slice(keyOffset, key.Length);
+ key.AsSpan().CopyTo(keyBuffer);
+
+ Assert.True(TryHashDataOneShot(keyBuffer, data, writeBuffer, out int written));
+ Assert.Equal(MacSize, written);
+
+ ReadOnlySpan<byte> expectedMac = _testMacs[caseId];
+ Span<byte> truncatedWriteBuffer = writeBuffer.Slice(0, expectedMac.Length);
+ AssertExtensions.SequenceEqual(expectedMac, truncatedWriteBuffer);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 10)]
+ [InlineData(10, 10)]
+ [InlineData(10, 0)]
+ [InlineData(10, 20)]
+ public void OneShot_TryExistingBuffer_OverlapsSource(int sourceOffset, int bufferOffset)
+ {
+ for (int caseId = 1; caseId <= 7; caseId++)
+ {
+ byte[] key = _testKeys[caseId];
+ byte[] data = _testData[caseId];
+ Span<byte> buffer = new byte[Math.Max(data.Length, MacSize) + Math.Max(sourceOffset, bufferOffset)];
+
+ Span<byte> writeBuffer = buffer.Slice(bufferOffset, MacSize);
+ Span<byte> dataBuffer = buffer.Slice(sourceOffset, data.Length);
+ data.AsSpan().CopyTo(dataBuffer);
+
+ Assert.True(TryHashDataOneShot(key, dataBuffer, writeBuffer, out int written));
+ Assert.Equal(MacSize, written);
+
+ ReadOnlySpan<byte> expectedMac = _testMacs[caseId];
+ Span<byte> truncatedWriteBuffer = writeBuffer.Slice(0, expectedMac.Length);
+ AssertExtensions.SequenceEqual(expectedMac, truncatedWriteBuffer);
+ }
+ }
+
+ [Theory]
+ [InlineData(new byte[0], new byte[] { 1 })]
+ [InlineData(new byte[] { 1 }, new byte[0])]
+ public void OneShot_Empty_Matches_Instances(byte[] key, byte[] source)
+ {
+ using (HMAC hash = Create())
+ {
+ hash.Key = key;
+ byte[] mac = hash.ComputeHash(source, 0, source.Length);
+
+ byte[] oneShot = HashDataOneShot(key, source);
+ Assert.Equal(mac, oneShot);
+ }
+ }
}
}
// The keys for test cases 1, 3, and 5 for RFC2202 are sized to match the
// algorithm (16 bytes for MD5, 20 for SHA-1), so they need to be provided by
// the more derived type.
- protected Rfc2202HmacTests(byte[][] testKeys) :
- base(testKeys, s_testData2202)
+ protected Rfc2202HmacTests(byte[][] testKeys, byte[][] testMacs) :
+ base(testKeys, s_testData2202, testMacs)
{
}
}
ByteUtils.AsciiBytes("This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."),
};
- protected Rfc4231HmacTests() :
- base(s_testKeys4231, s_testData4231)
+ protected Rfc4231HmacTests(byte[][] testMacs) :
+ base(s_testKeys4231, s_testData4231, testMacs)
{
}
}