Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Toub <stoub@microsoft.com>2017-08-10 16:05:48 +0300
committerGitHub <noreply@github.com>2017-08-10 16:05:48 +0300
commit154c2a35d5480d359729959f3e3e7d8578a18612 (patch)
tree715709bd61943affc601b7a785738d1e45191bd7 /src/System.Security.Cryptography.Algorithms
parent6c8411036d4b196c48433ac5e0118b2de525c01c (diff)
Add Span-based overloads to HashAlgorithm and IncrementalHash (#23076)
* Add Span-based overloads to HashAlgorithm and IncrementalHash - Added IncrementalHash.AppendData/TryGetHashAndReset span-based methods - Added HashAlgorithm.TryComputeHash/HashCore/TryHashFinal span-based methods - Overrode methods on MD5, SHA1, SHA1Managed, SHA256, SHA256Managed, SHA384, SHA384Managed, SHA512, SHA512Managed, HMACMD5, HMACSHA1, HMACSHA256, HMACSHA384, HMACSHA512, MD5CryptoServiceProvider, SHA1CryptoServiceProvider, SHA256CryptoServiceProvider, SHA512CryptoServiceProvider - Added tests - Some minor formatting cleanup along the way to make things more consistent with the new code being added * Address PR feedback - Rewrite HashProviderDispenser (OSX) FinalizeHashAndReset in terms of TryFinalizeHashAndReset - Reorder _running/SetKey check in HashProviderDispenser - Add bigger-than-needed-span test for HashAlgorithm - Fix incorrect const usage in original and copied test - Change HashAlgorithm.Hash to avoid throwing if HashValue is null - Make TryComputeHash null out HashValue on success - Cache HashSizeValue/8 into a local in TryHashFinal rather than recomputing
Diffstat (limited to 'src/System.Security.Cryptography.Algorithms')
-rw-r--r--src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs6
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HMACCommon.cs40
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs93
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs98
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACMD5.cs25
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA1.cs21
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA256.cs21
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA384.cs21
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA512.cs21
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/IncrementalHash.cs45
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/MD5.cs27
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1.cs27
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1Managed.cs17
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256.cs27
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256Managed.cs17
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384.cs27
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384Managed.cs17
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512.cs27
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512Managed.cs17
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.cs10
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.netcoreapp.cs70
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs32
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.netcoreapp.cs184
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj2
24 files changed, 589 insertions, 303 deletions
diff --git a/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs b/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs
index b2d67d0e63..c96d9ce3ca 100644
--- a/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs
+++ b/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs
@@ -8,6 +8,12 @@
namespace System.Security.Cryptography
{
+ public sealed partial class IncrementalHash : System.IDisposable
+ {
+ public void AppendData(ReadOnlySpan<byte> data) { }
+ public bool TryGetHashAndReset(Span<byte> destination, out int bytesWritten) { throw null; }
+ }
+
public abstract partial class RandomNumberGenerator : System.IDisposable
{
public virtual void GetBytes(Span<byte> data) { }
diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HMACCommon.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HMACCommon.cs
index a5f5aa6b54..8a6d4006bd 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HMACCommon.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HMACCommon.cs
@@ -4,9 +4,6 @@
using System;
using System.Diagnostics;
-using System.Security.Cryptography;
-
-using Internal.Cryptography;
namespace Internal.Cryptography
{
@@ -30,13 +27,7 @@ namespace Internal.Cryptography
ChangeKey(key);
}
- public int HashSizeInBits
- {
- get
- {
- return _hMacProvider.HashSizeInBytes * 8;
- }
- }
+ public int HashSizeInBits => _hMacProvider.HashSizeInBytes * 8;
public void ChangeKey(byte[] key)
{
@@ -46,15 +37,16 @@ namespace Internal.Cryptography
{
// Perform RFC 2104, section 2 key adjustment.
if (_lazyHashProvider == null)
+ {
_lazyHashProvider = HashProviderDispenser.CreateHashProvider(_hashAlgorithmId);
+ }
_lazyHashProvider.AppendHashData(key, 0, key.Length);
key = _lazyHashProvider.FinalizeHashAndReset();
}
HashProvider oldHashProvider = _hMacProvider;
_hMacProvider = null;
- if (oldHashProvider != null)
- oldHashProvider.Dispose(true);
+ oldHashProvider?.Dispose(true);
_hMacProvider = HashProviderDispenser.CreateMacProvider(_hashAlgorithmId, key);
ActualKey = key;
@@ -65,31 +57,31 @@ namespace Internal.Cryptography
public byte[] ActualKey { get; private set; }
// Adds new data to be hashed. This can be called repeatedly in order to hash data from noncontiguous sources.
- public void AppendHashData(byte[] data, int offset, int count)
- {
+ public void AppendHashData(byte[] data, int offset, int count) =>
_hMacProvider.AppendHashData(data, offset, count);
- }
+
+ public void AppendHashData(ReadOnlySpan<byte> source) =>
+ _hMacProvider.AppendHashData(source);
// Compute the hash based on the appended data and resets the HashProvider for more hashing.
- public byte[] FinalizeHashAndReset()
- {
- return _hMacProvider.FinalizeHashAndReset();
- }
+ public byte[] FinalizeHashAndReset() =>
+ _hMacProvider.FinalizeHashAndReset();
+
+ public bool TryFinalizeHashAndReset(Span<byte> destination, out int bytesWritten) =>
+ _hMacProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public void Dispose(bool disposing)
{
- if (disposing)
+ if (disposing && _hMacProvider != null)
{
- if (_hMacProvider != null)
- _hMacProvider.Dispose(true);
+ _hMacProvider.Dispose(true);
_hMacProvider = null;
}
}
- private readonly String _hashAlgorithmId;
+ private readonly string _hashAlgorithmId;
private HashProvider _hMacProvider;
private volatile HashProvider _lazyHashProvider;
-
private readonly int _blockSize;
}
}
diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs
index ea9fbaa465..b663864fd8 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs
@@ -86,43 +86,22 @@ namespace Internal.Cryptography
HashSizeInBytes = hashSizeInBytes;
}
- public override unsafe void AppendHashDataCore(byte[] data, int offset, int count)
+ public override void AppendHashData(ReadOnlySpan<byte> data)
{
- Debug.Assert(data != null);
- Debug.Assert(offset >= 0);
- Debug.Assert(offset < data.Length);
- Debug.Assert(count >= 0);
- Debug.Assert(data.Length - offset > count);
-
if (!_running)
{
SetKey();
}
- int ret;
-
- fixed (byte* pData = data)
- {
- byte* pbData = pData + offset;
- ret = Interop.AppleCrypto.HmacUpdate(_ctx, pbData, count);
- }
-
- if (ret != 1)
+ if (Interop.AppleCrypto.HmacUpdate(_ctx, data, data.Length) != 1)
{
throw new CryptographicException();
}
}
- private unsafe void SetKey()
+ private void SetKey()
{
- int ret;
-
- fixed (byte* pbKey = _key)
- {
- ret = Interop.AppleCrypto.HmacInit(_ctx, pbKey, _key.Length);
- }
-
- if (ret != 1)
+ if (Interop.AppleCrypto.HmacInit(_ctx, _key, _key.Length) != 1)
{
throw new CryptographicException();
}
@@ -132,26 +111,34 @@ namespace Internal.Cryptography
public override unsafe byte[] FinalizeHashAndReset()
{
- if (!_running)
+ var output = new byte[HashSizeInBytes];
+ bool success = TryFinalizeHashAndReset(output, out int bytesWritten);
+ Debug.Assert(success);
+ Debug.Assert(bytesWritten == output.Length);
+ return output;
+ }
+
+ public override bool TryFinalizeHashAndReset(Span<byte> destination, out int bytesWritten)
+ {
+ if (destination.Length < HashSizeInBytes)
{
- SetKey();
+ bytesWritten = 0;
+ return false;
}
- byte[] output = new byte[HashSizeInBytes];
- int ret;
-
- fixed (byte* pbOutput = output)
+ if (!_running)
{
- ret = Interop.AppleCrypto.HmacFinal(_ctx, pbOutput, output.Length);
+ SetKey();
}
- if (ret != 1)
+ if (Interop.AppleCrypto.HmacFinal(_ctx, destination, destination.Length) != 1)
{
throw new CryptographicException();
}
+ bytesWritten = HashSizeInBytes;
_running = false;
- return output;
+ return true;
}
public override void Dispose(bool disposing)
@@ -193,22 +180,9 @@ namespace Internal.Cryptography
HashSizeInBytes = hashSizeInBytes;
}
- public override unsafe void AppendHashDataCore(byte[] data, int offset, int count)
+ public override void AppendHashData(ReadOnlySpan<byte> data)
{
- Debug.Assert(data != null);
- Debug.Assert(offset >= 0);
- Debug.Assert(offset < data.Length);
- Debug.Assert(count >= 0);
- Debug.Assert(data.Length - offset > count);
-
- int ret;
-
- fixed (byte* pData = data)
- {
- byte* pbData = pData + offset;
- ret = Interop.AppleCrypto.DigestUpdate(_ctx, pbData, count);
- }
-
+ int ret = Interop.AppleCrypto.DigestUpdate(_ctx, data, data.Length);
if (ret != 1)
{
Debug.Assert(ret == 0, $"DigestUpdate return value {ret} was not 0 or 1");
@@ -216,23 +190,32 @@ namespace Internal.Cryptography
}
}
- public override unsafe byte[] FinalizeHashAndReset()
+ public override byte[] FinalizeHashAndReset()
{
- byte[] hash = new byte[HashSizeInBytes];
- int ret;
+ var hash = new byte[HashSizeInBytes];
+ bool success = TryFinalizeHashAndReset(hash, out int bytesWritten);
+ Debug.Assert(success);
+ Debug.Assert(bytesWritten == hash.Length);
+ return hash;
+ }
- fixed (byte* pHash = hash)
+ public override bool TryFinalizeHashAndReset(Span<byte> destination, out int bytesWritten)
+ {
+ if (destination.Length < HashSizeInBytes)
{
- ret = Interop.AppleCrypto.DigestFinal(_ctx, pHash, hash.Length);
+ bytesWritten = 0;
+ return false;
}
+ int ret = Interop.AppleCrypto.DigestFinal(_ctx, destination, destination.Length);
if (ret != 1)
{
Debug.Assert(ret == 0, $"DigestFinal return value {ret} was not 0 or 1");
throw new CryptographicException();
}
- return hash;
+ bytesWritten = HashSizeInBytes;
+ return true;
}
public override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs
index 24473ee480..c838da7bfc 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs
@@ -74,35 +74,43 @@ namespace Internal.Cryptography
Interop.Crypto.CheckValidOpenSslHandle(_ctx);
}
- public sealed override unsafe void AppendHashDataCore(byte[] data, int offset, int count)
+ public override void AppendHashData(ReadOnlySpan<byte> data) =>
+ Check(Interop.Crypto.EvpDigestUpdate(_ctx, data, data.Length));
+
+ public override byte[] FinalizeHashAndReset()
{
- fixed (byte* md = data)
- {
- Check(Interop.Crypto.EvpDigestUpdate(_ctx, md + offset, count));
- }
+ var result = new byte[_hashSize];
+ bool success = TryFinalizeHashAndReset(result, out int bytesWritten);
+ Debug.Assert(success);
+ Debug.Assert(result.Length == bytesWritten);
+ return result;
}
- public sealed override unsafe byte[] FinalizeHashAndReset()
+ public override unsafe bool TryFinalizeHashAndReset(Span<byte> destination, out int bytesWritten)
{
- byte* md = stackalloc byte[Interop.Crypto.EVP_MAX_MD_SIZE];
- uint length = (uint)Interop.Crypto.EVP_MAX_MD_SIZE;
- Check(Interop.Crypto.EvpDigestFinalEx(_ctx, md, ref length));
- Debug.Assert(length == _hashSize);
+ if (destination.Length < _hashSize)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ fixed (byte* ptrDest = &destination.DangerousGetPinnableReference())
+ {
+ uint length = (uint)destination.Length;
+ Check(Interop.Crypto.EvpDigestFinalEx(_ctx, ptrDest, ref length));
+ Debug.Assert(length == _hashSize);
+ bytesWritten = (int)length;
+ }
// Reset the algorithm provider.
Check(Interop.Crypto.EvpDigestReset(_ctx, _algorithmEvp));
- byte[] result = new byte[(int)length];
- Marshal.Copy((IntPtr)md, result, 0, (int)length);
- return result;
+ return true;
}
- public sealed override int HashSizeInBytes
- {
- get { return _hashSize; }
- }
+ public override int HashSizeInBytes => _hashSize;
- public sealed override void Dispose(bool disposing)
+ public override void Dispose(bool disposing)
{
if (disposing)
{
@@ -134,42 +142,46 @@ namespace Internal.Cryptography
}
}
- public sealed override unsafe void AppendHashDataCore(byte[] data, int offset, int count)
+ public override void AppendHashData(ReadOnlySpan<byte> data) =>
+ Check(Interop.Crypto.HmacUpdate(_hmacCtx, data, data.Length));
+
+ public override byte[] FinalizeHashAndReset()
{
- fixed (byte* md = data)
- {
- Check(Interop.Crypto.HmacUpdate(_hmacCtx, md + offset, count));
- }
+ var hash = new byte[_hashSize];
+ bool success = TryFinalizeHashAndReset(hash, out int bytesWritten);
+ Debug.Assert(success);
+ Debug.Assert(hash.Length == bytesWritten);
+ return hash;
}
- public sealed override unsafe byte[] FinalizeHashAndReset()
+ public override unsafe bool TryFinalizeHashAndReset(Span<byte> destination, out int bytesWritten)
{
- byte* md = stackalloc byte[Interop.Crypto.EVP_MAX_MD_SIZE];
- int length = Interop.Crypto.EVP_MAX_MD_SIZE;
- Check(Interop.Crypto.HmacFinal(_hmacCtx, md, ref length));
- Debug.Assert(length == _hashSize);
+ if (destination.Length < _hashSize)
+ {
+ bytesWritten = 0;
+ return false;
+ }
- Check(Interop.Crypto.HmacReset(_hmacCtx));
+ fixed (byte* ptrDest = &destination.DangerousGetPinnableReference())
+ {
+ int length = destination.Length;
+ Check(Interop.Crypto.HmacFinal(_hmacCtx, ptrDest, ref length));
+ Debug.Assert(length == _hashSize);
+ bytesWritten = length;
+ }
- byte[] result = new byte[length];
- Marshal.Copy((IntPtr)md, result, 0, length);
- return result;
+ Check(Interop.Crypto.HmacReset(_hmacCtx));
+ return true;
}
- public sealed override int HashSizeInBytes
- {
- get { return _hashSize; }
- }
+ public override int HashSizeInBytes => _hashSize;
- public sealed override void Dispose(bool disposing)
+ public override void Dispose(bool disposing)
{
- if (disposing)
+ if (disposing && _hmacCtx != null)
{
- if (_hmacCtx != null)
- {
- _hmacCtx.Dispose();
- _hmacCtx = null;
- }
+ _hmacCtx.Dispose();
+ _hmacCtx = null;
}
}
}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACMD5.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACMD5.cs
index 6e9e633d09..c59156cad9 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACMD5.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACMD5.cs
@@ -2,10 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Diagnostics;
-using System.Security.Cryptography;
-
using Internal.Cryptography;
namespace System.Security.Cryptography
@@ -46,21 +42,22 @@ namespace System.Security.Cryptography
}
}
- protected override void HashCore(byte[] rgb, int ib, int cb)
- {
+ protected override void HashCore(byte[] rgb, int ib, int cb) =>
_hMacCommon.AppendHashData(rgb, ib, cb);
- }
- protected override byte[] HashFinal()
- {
- return _hMacCommon.FinalizeHashAndReset();
- }
+ protected override void HashCore(ReadOnlySpan<byte> source) =>
+ _hMacCommon.AppendHashData(source);
+
+ protected override byte[] HashFinal() =>
+ _hMacCommon.FinalizeHashAndReset();
+
+ protected override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
public override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected override void Dispose(bool disposing)
@@ -68,9 +65,11 @@ namespace System.Security.Cryptography
if (disposing)
{
HMACCommon hMacCommon = _hMacCommon;
- _hMacCommon = null;
if (hMacCommon != null)
+ {
+ _hMacCommon = null;
hMacCommon.Dispose(disposing);
+ }
}
base.Dispose(disposing);
}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA1.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA1.cs
index 3277039ad0..d885c2c2d2 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA1.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA1.cs
@@ -49,21 +49,22 @@ namespace System.Security.Cryptography
}
}
- protected override void HashCore(byte[] rgb, int ib, int cb)
- {
+ protected override void HashCore(byte[] rgb, int ib, int cb) =>
_hMacCommon.AppendHashData(rgb, ib, cb);
- }
- protected override byte[] HashFinal()
- {
- return _hMacCommon.FinalizeHashAndReset();
- }
+ protected override void HashCore(ReadOnlySpan<byte> source) =>
+ _hMacCommon.AppendHashData(source);
+
+ protected override byte[] HashFinal() =>
+ _hMacCommon.FinalizeHashAndReset();
+
+ protected override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
public override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected override void Dispose(bool disposing)
@@ -71,9 +72,11 @@ namespace System.Security.Cryptography
if (disposing)
{
HMACCommon hMacCommon = _hMacCommon;
- _hMacCommon = null;
if (hMacCommon != null)
+ {
+ _hMacCommon = null;
hMacCommon.Dispose(disposing);
+ }
}
base.Dispose(disposing);
}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA256.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA256.cs
index 268d4b79f1..59f893c7ab 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA256.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA256.cs
@@ -46,21 +46,22 @@ namespace System.Security.Cryptography
}
}
- protected override void HashCore(byte[] rgb, int ib, int cb)
- {
+ protected override void HashCore(byte[] rgb, int ib, int cb) =>
_hMacCommon.AppendHashData(rgb, ib, cb);
- }
- protected override byte[] HashFinal()
- {
- return _hMacCommon.FinalizeHashAndReset();
- }
+ protected override void HashCore(ReadOnlySpan<byte> source) =>
+ _hMacCommon.AppendHashData(source);
+
+ protected override byte[] HashFinal() =>
+ _hMacCommon.FinalizeHashAndReset();
+
+ protected override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
public override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected override void Dispose(bool disposing)
@@ -68,9 +69,11 @@ namespace System.Security.Cryptography
if (disposing)
{
HMACCommon hMacCommon = _hMacCommon;
- _hMacCommon = null;
if (hMacCommon != null)
+ {
+ _hMacCommon = null;
hMacCommon.Dispose(disposing);
+ }
}
base.Dispose(disposing);
}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA384.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA384.cs
index 64f73980b7..1f9ef0a24a 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA384.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA384.cs
@@ -62,21 +62,22 @@ namespace System.Security.Cryptography
}
}
- protected override void HashCore(byte[] rgb, int ib, int cb)
- {
+ protected override void HashCore(byte[] rgb, int ib, int cb) =>
_hMacCommon.AppendHashData(rgb, ib, cb);
- }
- protected override byte[] HashFinal()
- {
- return _hMacCommon.FinalizeHashAndReset();
- }
+ protected override void HashCore(ReadOnlySpan<byte> source) =>
+ _hMacCommon.AppendHashData(source);
+
+ protected override byte[] HashFinal() =>
+ _hMacCommon.FinalizeHashAndReset();
+
+ protected override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
public override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected override void Dispose(bool disposing)
@@ -84,9 +85,11 @@ namespace System.Security.Cryptography
if (disposing)
{
HMACCommon hMacCommon = _hMacCommon;
- _hMacCommon = null;
if (hMacCommon != null)
+ {
+ _hMacCommon = null;
hMacCommon.Dispose(disposing);
+ }
}
base.Dispose(disposing);
}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA512.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA512.cs
index f902b5c71e..0ab29f04ca 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA512.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/HMACSHA512.cs
@@ -60,21 +60,22 @@ namespace System.Security.Cryptography
}
}
- protected override void HashCore(byte[] rgb, int ib, int cb)
- {
+ protected override void HashCore(byte[] rgb, int ib, int cb) =>
_hMacCommon.AppendHashData(rgb, ib, cb);
- }
- protected override byte[] HashFinal()
- {
- return _hMacCommon.FinalizeHashAndReset();
- }
+ protected override void HashCore(ReadOnlySpan<byte> source) =>
+ _hMacCommon.AppendHashData(source);
+
+ protected override byte[] HashFinal() =>
+ _hMacCommon.FinalizeHashAndReset();
+
+ protected override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
public override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected override void Dispose(bool disposing)
@@ -82,9 +83,11 @@ namespace System.Security.Cryptography
if (disposing)
{
HMACCommon hMacCommon = _hMacCommon;
- _hMacCommon = null;
if (hMacCommon != null)
+ {
+ _hMacCommon = null;
hMacCommon.Dispose(disposing);
+ }
}
base.Dispose(disposing);
}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/IncrementalHash.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/IncrementalHash.cs
index eb46eea65a..13c13280ad 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/IncrementalHash.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/IncrementalHash.cs
@@ -40,10 +40,7 @@ namespace System.Security.Cryptography
/// <summary>
/// Get the name of the algorithm being performed.
/// </summary>
- public HashAlgorithmName AlgorithmName
- {
- get { return _algorithmName; }
- }
+ public HashAlgorithmName AlgorithmName => _algorithmName;
/// <summary>
/// Append the entire contents of <paramref name="data"/> to the data already processed in the hash or HMAC.
@@ -92,14 +89,24 @@ namespace System.Security.Cryptography
if (_disposed)
throw new ObjectDisposedException(typeof(IncrementalHash).Name);
+ AppendData(new ReadOnlySpan<byte>(data, offset, count));
+ }
+
+ public void AppendData(ReadOnlySpan<byte> data)
+ {
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(typeof(IncrementalHash).Name);
+ }
+
+ Debug.Assert((_hash != null) ^ (_hmac != null));
if (_hash != null)
{
- _hash.AppendHashDataCore(data, offset, count);
+ _hash.AppendHashData(data);
}
else
{
- Debug.Assert(_hmac != null, "Both _hash and _hmac were null");
- _hmac.AppendHashData(data, offset, count);
+ _hmac.AppendHashData(data);
}
}
@@ -113,21 +120,27 @@ namespace System.Security.Cryptography
public byte[] GetHashAndReset()
{
if (_disposed)
+ {
throw new ObjectDisposedException(typeof(IncrementalHash).Name);
+ }
- byte[] hashValue;
+ Debug.Assert((_hash != null) ^ (_hmac != null));
+ return _hash != null ?
+ _hash.FinalizeHashAndReset() :
+ _hmac.FinalizeHashAndReset();
+ }
- if (_hash != null)
- {
- hashValue = _hash.FinalizeHashAndReset();
- }
- else
+ public bool TryGetHashAndReset(Span<byte> destination, out int bytesWritten)
+ {
+ if (_disposed)
{
- Debug.Assert(_hmac != null, "Both _hash and _hmac were null");
- hashValue = _hmac.FinalizeHashAndReset();
+ throw new ObjectDisposedException(typeof(IncrementalHash).Name);
}
- return hashValue;
+ Debug.Assert((_hash != null) ^ (_hmac != null));
+ return _hash != null ?
+ _hash.TryFinalizeHashAndReset(destination, out bytesWritten) :
+ _hmac.TryFinalizeHashAndReset(destination, out bytesWritten);
}
/// <summary>
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/MD5.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/MD5.cs
index 444ec604c3..0049613885 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/MD5.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/MD5.cs
@@ -16,15 +16,9 @@ namespace System.Security.Cryptography
{
protected MD5() { }
- public static new MD5 Create()
- {
- return new Implementation();
- }
+ public static new MD5 Create() => new Implementation();
- public static new MD5 Create(String algName)
- {
- return (MD5)CryptoConfig.CreateFromName(algName);
- }
+ public static new MD5 Create(String algName) => (MD5)CryptoConfig.CreateFromName(algName);
private sealed class Implementation : MD5
{
@@ -36,21 +30,22 @@ namespace System.Security.Cryptography
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
}
- protected sealed override void HashCore(byte[] array, int ibStart, int cbSize)
- {
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
_hashProvider.AppendHashData(array, ibStart, cbSize);
- }
- protected sealed override byte[] HashFinal()
- {
- return _hashProvider.FinalizeHashAndReset();
- }
+ protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public sealed override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected sealed override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1.cs
index 1d075f9d88..d9ad3a8b59 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1.cs
@@ -17,15 +17,9 @@ namespace System.Security.Cryptography
protected SHA1() { }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "This is the implementaton of SHA1")]
- public static new SHA1 Create()
- {
- return new Implementation();
- }
+ public static new SHA1 Create() => new Implementation();
- public static new SHA1 Create(string hashName)
- {
- return (SHA1)CryptoConfig.CreateFromName(hashName);
- }
+ public static new SHA1 Create(string hashName) => (SHA1)CryptoConfig.CreateFromName(hashName);
private sealed class Implementation : SHA1
{
@@ -37,21 +31,22 @@ namespace System.Security.Cryptography
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
}
- protected sealed override void HashCore(byte[] array, int ibStart, int cbSize)
- {
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
_hashProvider.AppendHashData(array, ibStart, cbSize);
- }
- protected sealed override byte[] HashFinal()
- {
- return _hashProvider.FinalizeHashAndReset();
- }
+ protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public sealed override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected sealed override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1Managed.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1Managed.cs
index 1bd1c7867b..fab9ff8252 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1Managed.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA1Managed.cs
@@ -19,21 +19,22 @@ namespace System.Security.Cryptography
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
}
- protected sealed override void HashCore(byte[] array, int ibStart, int cbSize)
- {
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
_hashProvider.AppendHashData(array, ibStart, cbSize);
- }
- protected sealed override byte[] HashFinal()
- {
- return _hashProvider.FinalizeHashAndReset();
- }
+ protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public sealed override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected sealed override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256.cs
index d8695c40c3..9fe667b55a 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256.cs
@@ -16,15 +16,9 @@ namespace System.Security.Cryptography
{
protected SHA256() { }
- public static new SHA256 Create()
- {
- return new Implementation();
- }
+ public static new SHA256 Create() => new Implementation();
- public static new SHA256 Create(string hashName)
- {
- return (SHA256)CryptoConfig.CreateFromName(hashName);
- }
+ public static new SHA256 Create(string hashName) => (SHA256)CryptoConfig.CreateFromName(hashName);
private sealed class Implementation : SHA256
{
@@ -36,21 +30,22 @@ namespace System.Security.Cryptography
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
}
- protected sealed override void HashCore(byte[] array, int ibStart, int cbSize)
- {
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
_hashProvider.AppendHashData(array, ibStart, cbSize);
- }
- protected sealed override byte[] HashFinal()
- {
- return _hashProvider.FinalizeHashAndReset();
- }
+ protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public sealed override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected sealed override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256Managed.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256Managed.cs
index 7ea4f77873..77496bed44 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256Managed.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256Managed.cs
@@ -19,21 +19,22 @@ namespace System.Security.Cryptography
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
}
- protected sealed override void HashCore(byte[] array, int ibStart, int cbSize)
- {
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
_hashProvider.AppendHashData(array, ibStart, cbSize);
- }
- protected sealed override byte[] HashFinal()
- {
- return _hashProvider.FinalizeHashAndReset();
- }
+ protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public sealed override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected sealed override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384.cs
index 2311d7b25e..f5e6b80c52 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384.cs
@@ -16,15 +16,9 @@ namespace System.Security.Cryptography
{
protected SHA384() { }
- public static new SHA384 Create()
- {
- return new Implementation();
- }
+ public static new SHA384 Create() => new Implementation();
- public static new SHA384 Create(string hashName)
- {
- return (SHA384)CryptoConfig.CreateFromName(hashName);
- }
+ public static new SHA384 Create(string hashName) => (SHA384)CryptoConfig.CreateFromName(hashName);
private sealed class Implementation : SHA384
{
@@ -36,21 +30,22 @@ namespace System.Security.Cryptography
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
}
- protected sealed override void HashCore(byte[] array, int ibStart, int cbSize)
- {
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
_hashProvider.AppendHashData(array, ibStart, cbSize);
- }
- protected sealed override byte[] HashFinal()
- {
- return _hashProvider.FinalizeHashAndReset();
- }
+ protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public sealed override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected sealed override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384Managed.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384Managed.cs
index d9c1aff058..6c7780fce8 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384Managed.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA384Managed.cs
@@ -19,21 +19,22 @@ namespace System.Security.Cryptography
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
}
- protected sealed override void HashCore(byte[] array, int ibStart, int cbSize)
- {
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
_hashProvider.AppendHashData(array, ibStart, cbSize);
- }
- protected sealed override byte[] HashFinal()
- {
- return _hashProvider.FinalizeHashAndReset();
- }
+ protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public sealed override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected sealed override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512.cs
index 584dd0553c..1c62d97cc5 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512.cs
@@ -16,15 +16,9 @@ namespace System.Security.Cryptography
{
protected SHA512() { }
- public static new SHA512 Create()
- {
- return new Implementation();
- }
+ public static new SHA512 Create() => new Implementation();
- public static new SHA512 Create(string hashName)
- {
- return (SHA512)CryptoConfig.CreateFromName(hashName);
- }
+ public static new SHA512 Create(string hashName) => (SHA512)CryptoConfig.CreateFromName(hashName);
private sealed class Implementation : SHA512
{
@@ -36,21 +30,22 @@ namespace System.Security.Cryptography
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
}
- protected sealed override void HashCore(byte[] array, int ibStart, int cbSize)
- {
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
_hashProvider.AppendHashData(array, ibStart, cbSize);
- }
- protected sealed override byte[] HashFinal()
- {
- return _hashProvider.FinalizeHashAndReset();
- }
+ protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public sealed override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected sealed override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512Managed.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512Managed.cs
index cd88bd422e..95435ebe90 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512Managed.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA512Managed.cs
@@ -19,21 +19,22 @@ namespace System.Security.Cryptography
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
}
- protected sealed override void HashCore(byte[] array, int ibStart, int cbSize)
- {
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
_hashProvider.AppendHashData(array, ibStart, cbSize);
- }
- protected sealed override byte[] HashFinal()
- {
- return _hashProvider.FinalizeHashAndReset();
- }
+ protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
public sealed override void Initialize()
{
// Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
// reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
- return;
}
protected sealed override void Dispose(bool disposing)
diff --git a/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.cs b/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.cs
index e626bd6340..249e6b6c56 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.cs
@@ -9,7 +9,7 @@ using Xunit;
namespace System.Security.Cryptography.Hashing.Algorithms.Tests
{
- public abstract class HashAlgorithmTest
+ public abstract partial class HashAlgorithmTest
{
protected abstract HashAlgorithm Create();
@@ -208,6 +208,12 @@ namespace System.Security.Cryptography.Hashing.Algorithms.Tests
protected void Verify(byte[] input, string output)
{
+ Verify_Array(input, output);
+ Verify_Span(input, output);
+ }
+
+ private void Verify_Array(byte[] input, string output)
+ {
byte[] expected = ByteUtils.HexToByteArray(output);
byte[] actual;
@@ -223,6 +229,8 @@ namespace System.Security.Cryptography.Hashing.Algorithms.Tests
}
}
+ partial void Verify_Span(byte[] input, string output);
+
protected void VerifyRepeating(string input, int repeatCount, string output)
{
using (Stream stream = new DataRepeatingStream(input, repeatCount))
diff --git a/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.netcoreapp.cs b/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.netcoreapp.cs
new file mode 100644
index 0000000000..c76951d8dc
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.netcoreapp.cs
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Hashing.Algorithms.Tests
+{
+ public abstract partial class HashAlgorithmTest
+ {
+ partial void Verify_Span(byte[] input, string output)
+ {
+ byte[] expected = ByteUtils.HexToByteArray(output);
+ byte[] actual;
+ int bytesWritten;
+
+ using (HashAlgorithm hash = Create())
+ {
+ // Too small
+ actual = new byte[expected.Length - 1];
+ Assert.False(hash.TryComputeHash(input, actual, out bytesWritten));
+ Assert.Equal(0, bytesWritten);
+
+ // Just right
+ actual = new byte[expected.Length];
+ Assert.True(hash.TryComputeHash(input, actual, out bytesWritten));
+ Assert.Equal(expected.Length, bytesWritten);
+ Assert.Equal(expected, actual);
+
+ // Bigger than needed
+ actual = new byte[expected.Length + 1];
+ actual[actual.Length - 1] = 42;
+ Assert.True(hash.TryComputeHash(input, actual, out bytesWritten));
+ Assert.Equal(expected.Length, bytesWritten);
+ Assert.Equal(expected, actual.AsSpan().Slice(0, expected.Length).ToArray());
+ Assert.Equal(42, actual[actual.Length - 1]);
+ }
+ }
+
+ [Fact]
+ public void ComputeHash_TryComputeHash_HashSetExplicitlyByBoth()
+ {
+ using (HashAlgorithm hash = Create())
+ {
+ byte[] input = Enumerable.Range(0, 100).Select(i => (byte)i).ToArray();
+
+ byte[] computeHashResult = hash.ComputeHash(input);
+ Assert.NotNull(computeHashResult);
+ Assert.NotNull(hash.Hash);
+ Assert.NotSame(computeHashResult, hash.Hash);
+ Assert.Equal(computeHashResult, hash.Hash);
+
+ Assert.True(hash.TryComputeHash(input, computeHashResult, out int bytesWritten));
+ Assert.Equal(computeHashResult.Length, bytesWritten);
+ Assert.Null(hash.Hash);
+ }
+ }
+
+ [Fact]
+ public void Dispose_TryComputeHash_ThrowsException()
+ {
+ HashAlgorithm hash = Create();
+ hash.Dispose();
+ Assert.Throws<ObjectDisposedException>(() => hash.ComputeHash(new byte[1]));
+ Assert.Throws<ObjectDisposedException>(() => hash.TryComputeHash(new byte[1], new byte[1], out int bytesWritten));
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs b/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs
index e9926220e3..ee0e6cd5d0 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs
@@ -8,7 +8,7 @@ using Xunit;
namespace System.Security.Cryptography.Algorithms.Tests
{
- public class IncrementalHashTests
+ public partial class IncrementalHashTests
{
// Some arbitrarily chosen OID segments
private static readonly byte[] s_hmacKey = { 2, 5, 29, 54, 1, 2, 84, 113, 54, 91, 1, 1, 2, 5, 29, 10, };
@@ -38,6 +38,31 @@ namespace System.Security.Cryptography.Algorithms.Tests
};
}
+ [Fact]
+ public static void InvalidArguments_Throw()
+ {
+ AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => IncrementalHash.CreateHash(new HashAlgorithmName(null)));
+ AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => IncrementalHash.CreateHash(new HashAlgorithmName("")));
+
+ AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => IncrementalHash.CreateHMAC(new HashAlgorithmName(null), new byte[1]));
+ AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => IncrementalHash.CreateHMAC(new HashAlgorithmName(""), new byte[1]));
+
+ AssertExtensions.Throws<ArgumentNullException>("key", () => IncrementalHash.CreateHMAC(HashAlgorithmName.SHA512, null));
+
+ using (IncrementalHash incrementalHash = IncrementalHash.CreateHash(HashAlgorithmName.SHA512))
+ {
+ AssertExtensions.Throws<ArgumentNullException>("data", () => incrementalHash.AppendData(null));
+ AssertExtensions.Throws<ArgumentNullException>("data", () => incrementalHash.AppendData(null, 0, 0));
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => incrementalHash.AppendData(new byte[1], -1, 1));
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => incrementalHash.AppendData(new byte[1], 0, -1));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => incrementalHash.AppendData(new byte[1], 0, 2));
+
+ Assert.Throws<ArgumentException>(() => incrementalHash.AppendData(new byte[2], 1, 2));
+ }
+ }
+
[Theory]
[MemberData(nameof(GetHashAlgorithms))]
public static void VerifyIncrementalHash(HashAlgorithm referenceAlgorithm, HashAlgorithmName hashAlgorithm)
@@ -45,6 +70,7 @@ namespace System.Security.Cryptography.Algorithms.Tests
using (referenceAlgorithm)
using (IncrementalHash incrementalHash = IncrementalHash.CreateHash(hashAlgorithm))
{
+ Assert.Equal(hashAlgorithm, incrementalHash.AlgorithmName);
VerifyIncrementalResult(referenceAlgorithm, incrementalHash);
}
}
@@ -86,8 +112,8 @@ namespace System.Security.Cryptography.Algorithms.Tests
while (position < s_inputBytes.Length - StepB)
{
- incrementalHash.AppendData(s_inputBytes, position, StepA);
- position += StepA;
+ incrementalHash.AppendData(s_inputBytes, position, StepB);
+ position += StepB;
}
incrementalHash.AppendData(s_inputBytes, position, s_inputBytes.Length - position);
diff --git a/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.netcoreapp.cs b/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.netcoreapp.cs
new file mode 100644
index 0000000000..a4372f0846
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.netcoreapp.cs
@@ -0,0 +1,184 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Algorithms.Tests
+{
+ public partial class IncrementalHashTests
+ {
+ [Theory]
+ [MemberData(nameof(GetHashAlgorithms))]
+ public static void VerifyIncrementalHash_Span(HashAlgorithm referenceAlgorithm, HashAlgorithmName hashAlgorithm)
+ {
+ using (referenceAlgorithm)
+ using (IncrementalHash incrementalHash = IncrementalHash.CreateHash(hashAlgorithm))
+ {
+ VerifyIncrementalResult_Span(referenceAlgorithm, incrementalHash);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(GetHMACs))]
+ public static void VerifyIncrementalHMAC_Span(HMAC referenceAlgorithm, HashAlgorithmName hashAlgorithm)
+ {
+ using (referenceAlgorithm)
+ using (IncrementalHash incrementalHash = IncrementalHash.CreateHMAC(hashAlgorithm, s_hmacKey))
+ {
+ referenceAlgorithm.Key = s_hmacKey;
+ VerifyIncrementalResult_Span(referenceAlgorithm, incrementalHash);
+ }
+ }
+
+ private static void VerifyIncrementalResult_Span(HashAlgorithm referenceAlgorithm, IncrementalHash incrementalHash)
+ {
+ int referenceHashLength;
+ byte[] referenceHash = new byte[1];
+ while (!referenceAlgorithm.TryComputeHash(s_inputBytes, referenceHash, out referenceHashLength))
+ {
+ referenceHash = new byte[referenceHash.Length * 2];
+ }
+
+ const int StepA = 13;
+ const int StepB = 7;
+ int position = 0;
+
+ while (position < s_inputBytes.Length - StepA)
+ {
+ incrementalHash.AppendData(new ReadOnlySpan<byte>(s_inputBytes, position, StepA));
+ position += StepA;
+ }
+
+ incrementalHash.AppendData(new ReadOnlySpan<byte>(s_inputBytes, position, s_inputBytes.Length - position));
+
+ byte[] incrementalA = new byte[referenceHashLength];
+ int bytesWritten;
+ Assert.True(incrementalHash.TryGetHashAndReset(incrementalA, out bytesWritten));
+ Assert.Equal(referenceHashLength, bytesWritten);
+ Assert.Equal<byte>(new Span<byte>(referenceHash, 0, referenceHashLength).ToArray(), new Span<byte>(incrementalA).Slice(0, bytesWritten).ToArray());
+
+ // Now try again, verifying both immune to step size behaviors, and that GetHashAndReset resets.
+ position = 0;
+
+ while (position < s_inputBytes.Length - StepB)
+ {
+ incrementalHash.AppendData(new ReadOnlySpan<byte>(s_inputBytes, position, StepB));
+ position += StepB;
+ }
+
+ incrementalHash.AppendData(new ReadOnlySpan<byte>(s_inputBytes, position, s_inputBytes.Length - position));
+
+ byte[] incrementalB = new byte[referenceHashLength];
+ Assert.True(incrementalHash.TryGetHashAndReset(incrementalB, out bytesWritten));
+ Assert.Equal(referenceHashLength, bytesWritten);
+ Assert.Equal<byte>(new Span<byte>(referenceHash, 0, referenceHashLength).ToArray(), incrementalB);
+ }
+
+ [Theory]
+ [MemberData(nameof(GetHashAlgorithms))]
+ public static void VerifyEmptyHash_Span(HashAlgorithm referenceAlgorithm, HashAlgorithmName hashAlgorithm)
+ {
+ using (referenceAlgorithm)
+ using (IncrementalHash incrementalHash = IncrementalHash.CreateHash(hashAlgorithm))
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ incrementalHash.AppendData(ReadOnlySpan<byte>.Empty);
+ }
+
+ byte[] referenceHash = referenceAlgorithm.ComputeHash(Array.Empty<byte>());
+ byte[] incrementalResult = new byte[referenceHash.Length];
+ Assert.True(incrementalHash.TryGetHashAndReset(incrementalResult, out int bytesWritten));
+ Assert.Equal(referenceHash.Length, bytesWritten);
+ Assert.Equal(referenceHash, incrementalResult);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(GetHMACs))]
+ public static void VerifyEmptyHMAC_Span(HMAC referenceAlgorithm, HashAlgorithmName hashAlgorithm)
+ {
+ using (referenceAlgorithm)
+ using (IncrementalHash incrementalHash = IncrementalHash.CreateHMAC(hashAlgorithm, s_hmacKey))
+ {
+ referenceAlgorithm.Key = s_hmacKey;
+
+ for (int i = 0; i < 10; i++)
+ {
+ incrementalHash.AppendData(ReadOnlySpan<byte>.Empty);
+ }
+
+ byte[] referenceHash = referenceAlgorithm.ComputeHash(Array.Empty<byte>());
+ byte[] incrementalResult = new byte[referenceHash.Length];
+ Assert.True(incrementalHash.TryGetHashAndReset(incrementalResult, out int bytesWritten));
+ Assert.Equal(referenceHash.Length, bytesWritten);
+ Assert.Equal(referenceHash, incrementalResult);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(GetHashAlgorithms))]
+ public static void VerifyTrivialHash_Span(HashAlgorithm referenceAlgorithm, HashAlgorithmName hashAlgorithm)
+ {
+ using (referenceAlgorithm)
+ using (IncrementalHash incrementalHash = IncrementalHash.CreateHash(hashAlgorithm))
+ {
+ byte[] referenceHash = referenceAlgorithm.ComputeHash(Array.Empty<byte>());
+ byte[] incrementalResult = new byte[referenceHash.Length];
+ Assert.True(incrementalHash.TryGetHashAndReset(incrementalResult, out int bytesWritten));
+ Assert.Equal(referenceHash.Length, bytesWritten);
+ Assert.Equal(referenceHash, incrementalResult);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(GetHMACs))]
+ public static void VerifyTrivialHMAC_Span(HMAC referenceAlgorithm, HashAlgorithmName hashAlgorithm)
+ {
+ using (referenceAlgorithm)
+ using (IncrementalHash incrementalHash = IncrementalHash.CreateHMAC(hashAlgorithm, s_hmacKey))
+ {
+ referenceAlgorithm.Key = s_hmacKey;
+
+ byte[] referenceHash = referenceAlgorithm.ComputeHash(Array.Empty<byte>());
+ byte[] incrementalResult = new byte[referenceHash.Length];
+ Assert.True(incrementalHash.TryGetHashAndReset(incrementalResult, out int bytesWritten));
+ Assert.Equal(referenceHash.Length, bytesWritten);
+ Assert.Equal(referenceHash, incrementalResult);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(GetHashAlgorithms))]
+ public static void Dispose_HashAlgorithm_ThrowsException(HashAlgorithm referenceAlgorithm, HashAlgorithmName hashAlgorithm)
+ {
+ referenceAlgorithm.Dispose();
+ var incrementalHash = IncrementalHash.CreateHash(hashAlgorithm);
+ incrementalHash.Dispose();
+
+ Assert.Throws<ObjectDisposedException>(() => incrementalHash.AppendData(new byte[1]));
+ Assert.Throws<ObjectDisposedException>(() => incrementalHash.AppendData(new ReadOnlySpan<byte>(new byte[1])));
+
+ Assert.Throws<ObjectDisposedException>(() => incrementalHash.GetHashAndReset());
+ Assert.Throws<ObjectDisposedException>(() => incrementalHash.TryGetHashAndReset(new byte[1], out int _));
+ }
+
+ [Theory]
+ [MemberData(nameof(GetHMACs))]
+ public static void Dispose_HMAC_ThrowsException(HMAC referenceAlgorithm, HashAlgorithmName hashAlgorithm)
+ {
+ referenceAlgorithm.Dispose();
+ var incrementalHash = IncrementalHash.CreateHMAC(hashAlgorithm, s_hmacKey);
+ incrementalHash.Dispose();
+
+ Assert.Throws<ObjectDisposedException>(() => incrementalHash.AppendData(new byte[1]));
+ Assert.Throws<ObjectDisposedException>(() => incrementalHash.AppendData(new ReadOnlySpan<byte>(new byte[1])));
+
+ Assert.Throws<ObjectDisposedException>(() => incrementalHash.GetHashAndReset());
+ Assert.Throws<ObjectDisposedException>(() => incrementalHash.TryGetHashAndReset(new byte[1], out int _));
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj b/src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj
index ee62be88a2..8aaea4acbe 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj
+++ b/src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj
@@ -149,6 +149,8 @@
<Compile Include="DSACreateTests.cs" />
<Compile Include="DSASignatureFormatterTests.cs" />
<Compile Include="ECDiffieHellmanPublicKeyTests.cs" />
+ <Compile Include="HashAlgorithmTest.netcoreapp.cs" />
+ <Compile Include="IncrementalHashTests.netcoreapp.cs" />
<Compile Include="PaddingModeTests.cs" />
<Compile Include="PKCS1MaskGenerationMethodTest.cs" />
<Compile Include="RandomNumberGeneratorTests.netcoreapp.cs" />