未验证 提交 3188dcd2 编写于 作者: K Kevin Jones 提交者: GitHub

Add static one-shot methods for HMAC algorithms

上级 6a590ef0
......@@ -2,6 +2,7 @@
// 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;
......@@ -29,5 +30,29 @@ internal static partial class Crypto
[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;
}
}
}
......@@ -35,6 +35,17 @@ internal static partial class AppleCrypto
[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);
}
}
......
......@@ -2,6 +2,7 @@
// 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;
......@@ -29,5 +30,29 @@ internal static partial class Crypto
[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;
}
}
}
......@@ -17,6 +17,11 @@ public enum BCryptAlgPseudoHandle : uint
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,
}
......
......@@ -403,7 +403,7 @@ public static void CollectionEqual<T>(IEnumerable<T> expected, IEnumerable<T> ac
{
actualItemCountMapping[actualItem] = new ItemCount(1, 1);
}
actualCount++;
}
......@@ -431,7 +431,7 @@ public static void CollectionEqual<T>(IEnumerable<T> expected, IEnumerable<T> ac
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.
......@@ -475,6 +475,19 @@ public static void CollectionEqual<T>(IEnumerable<T> expected, IEnumerable<T> ac
}
}
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());
......@@ -556,7 +569,7 @@ public static void AtLeastOneEquals<T>(T expected1, T expected2, T value)
Assert.Equal(expectedParamName, exception.ParamName);
return exception;
}
private class ItemCount
{
public int Original { get; set; }
......
......@@ -136,3 +136,29 @@ void CryptoNative_HmacDestroy(jobject ctx)
{
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;
}
......@@ -11,3 +11,10 @@ PALEXPORT int32_t CryptoNative_HmacUpdate(jobject ctx, uint8_t* data, int32_t le
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);
......@@ -38,6 +38,7 @@ static const Entry s_cryptoAppleNative[] =
DllImportEntry(AppleCryptoNative_HmacUpdate)
DllImportEntry(AppleCryptoNative_HmacFinal)
DllImportEntry(AppleCryptoNative_HmacCurrent)
DllImportEntry(AppleCryptoNative_HmacOneShot)
DllImportEntry(AppleCryptoNative_SecKeychainItemCopyKeychain)
DllImportEntry(AppleCryptoNative_SecKeychainCreate)
DllImportEntry(AppleCryptoNative_SecKeychainDelete)
......
......@@ -116,7 +116,32 @@ int32_t AppleCryptoNative_HmacCurrent(const HmacCtx* ctx, uint8_t* pbOutput)
{
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;
}
......@@ -51,3 +51,17 @@ Computes the HMAC of the accumulated data in ctx without resetting the state.
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);
......@@ -202,6 +202,7 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_HmacCurrent)
DllImportEntry(CryptoNative_HmacDestroy)
DllImportEntry(CryptoNative_HmacFinal)
DllImportEntry(CryptoNative_HmacOneShot)
DllImportEntry(CryptoNative_HmacReset)
DllImportEntry(CryptoNative_HmacUpdate)
DllImportEntry(CryptoNative_LookupFriendlyNameByOid)
......
......@@ -362,6 +362,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
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) \
......@@ -797,6 +798,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#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
......
......@@ -130,3 +130,36 @@ int32_t CryptoNative_HmacCurrent(const HMAC_CTX* ctx, uint8_t* md, int32_t* len)
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 = &empty;
}
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;
}
......@@ -69,3 +69,15 @@ PALEXPORT int32_t CryptoNative_HmacFinal(HMAC_CTX* ctx, uint8_t* md, int32_t* le
* 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);
......@@ -469,8 +469,12 @@ public partial class HMACMD5 : System.Security.Cryptography.HMAC
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")]
......@@ -484,8 +488,12 @@ public partial class HMACSHA1 : System.Security.Cryptography.HMAC
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")]
......@@ -497,8 +505,12 @@ public partial class HMACSHA256 : System.Security.Cryptography.HMAC
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")]
......@@ -511,8 +523,12 @@ public partial class HMACSHA384 : System.Security.Cryptography.HMAC
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")]
......@@ -525,8 +541,12 @@ public partial class HMACSHA512 : System.Security.Cryptography.HMAC
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
......
......@@ -26,6 +26,15 @@ public static HashProvider CreateHashProvider(string hashAlgorithmId)
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);
......
......@@ -33,6 +33,40 @@ public static HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlySpa
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);
......
......@@ -25,6 +25,28 @@ internal static HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlyS
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);
......
......@@ -30,14 +30,48 @@ public static HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlySpa
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
......@@ -54,42 +88,60 @@ public static unsafe int HashData(string hashAlgorithmId, ReadOnlySpan<byte> sou
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
......@@ -104,10 +156,11 @@ private static unsafe void HashDataUsingPseudoHandle(string hashAlgorithmId, Rea
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)
{
......@@ -121,6 +174,7 @@ private static unsafe void HashDataUsingPseudoHandle(string hashAlgorithmId, Rea
private static void HashUpdateAndFinish(
SafeBCryptAlgorithmHandle algHandle,
int hashSize,
ReadOnlySpan<byte> key,
ReadOnlySpan<byte> source,
Span<byte> destination)
{
......@@ -129,8 +183,8 @@ private static unsafe void HashDataUsingPseudoHandle(string hashAlgorithmId, Rea
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;
......@@ -14,6 +15,9 @@ namespace System.Security.Cryptography
[UnsupportedOSPlatform("browser")]
public class HMACMD5 : HMAC
{
private const int HmacSizeBits = 128;
private const int HmacSizeBytes = HmacSizeBits / 8;
public HMACMD5()
: this(RandomNumberGenerator.GetBytes(BlockSize))
{
......@@ -33,6 +37,7 @@ public HMACMD5(byte[] key)
// we just want to be explicit in all HMAC extended classes
BlockSizeValue = BlockSize;
HashSizeValue = _hMacCommon.HashSizeInBits;
Debug.Assert(HashSizeValue == HmacSizeBits);
}
public override byte[] Key
......@@ -67,6 +72,89 @@ 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)
......
......@@ -3,6 +3,7 @@
using Internal.Cryptography;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.Versioning;
namespace System.Security.Cryptography
......@@ -15,6 +16,9 @@ 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))
{
......@@ -34,6 +38,7 @@ public HMACSHA1(byte[] key)
// we just want to be explicit in all HMAC extended classes
BlockSizeValue = BlockSize;
HashSizeValue = _hMacCommon.HashSizeInBits;
Debug.Assert(HashSizeValue == HmacSizeBits);
}
[EditorBrowsable(EditorBrowsableState.Never)]
......@@ -74,6 +79,89 @@ public override byte[] Key
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
{
......@@ -17,6 +16,9 @@ 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))
{
......@@ -36,6 +38,7 @@ public HMACSHA256(byte[] key)
// we just want to be explicit in all HMAC extended classes
BlockSizeValue = BlockSize;
HashSizeValue = _hMacCommon.HashSizeInBits;
Debug.Assert(HashSizeValue == HmacSizeBits);
}
public override byte[] Key
......@@ -70,6 +73,89 @@ 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
{
......@@ -17,6 +16,9 @@ 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))
{
......@@ -35,6 +37,7 @@ public HMACSHA384(byte[] key)
// change the default value of BlockSizeValue to 128 instead of 64
BlockSizeValue = BlockSize;
HashSizeValue = _hMacCommon.HashSizeInBits;
Debug.Assert(HashSizeValue == HmacSizeBits);
}
public bool ProduceLegacyHmacValues
......@@ -86,6 +89,89 @@ public override byte[] Key
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
{
......@@ -17,6 +16,9 @@ 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))
{
......@@ -84,6 +86,89 @@ public override byte[] Key
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)
......
......@@ -21,63 +21,80 @@ public class HmacMD5Tests : Rfc2202HmacTests
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]
......
......@@ -21,22 +21,39 @@ public class HmacSha1Tests : Rfc2202HmacTests
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()
......@@ -69,43 +86,43 @@ public void HmacSha1_ThrowsArgumentNullForNullConstructorKey()
[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
......@@ -8,59 +9,80 @@ 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
......@@ -8,18 +9,40 @@ 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()
{
......@@ -34,44 +57,43 @@ 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
......@@ -8,18 +9,40 @@ 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()
{
......@@ -34,44 +57,43 @@ 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]
......
......@@ -15,31 +15,36 @@ public abstract class HmacTests
// 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;
......@@ -55,13 +60,7 @@ protected HmacTests(byte[][] testKeys, byte[][] testData)
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())
......@@ -76,14 +75,22 @@ protected HmacTests(byte[][] testKeys, byte[][] testData)
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(
......@@ -232,5 +239,152 @@ public void InvalidKey_ThrowArgumentNullException()
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);
}
}
}
}
......@@ -24,8 +24,8 @@ public abstract class Rfc2202HmacTests : HmacTests
// 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)
{
}
}
......
......@@ -33,8 +33,8 @@ public abstract class Rfc4231HmacTests : HmacTests
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)
{
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册