From 56979871c772e19e9498f7eba4afd9f92d0e1a63 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Thu, 24 Mar 2022 17:09:22 -0400 Subject: [PATCH] Implement {Try}HashData on asymmetric algorithms Historically, the asymmetric algorithm base classes have had the hashing routines as abstract (or virtual+throw). Now the base classes provide an implementation for these methods, reducing the amount of redundant effort on the part of derived types. --- .../System/Security/Cryptography/DSACng.cs | 12 +- .../Security/Cryptography/DSAOpenSsl.cs | 19 +- .../Cryptography/DSASecurityTransforms.cs | 8 +- .../Security/Cryptography/ECDsaAndroid.cs | 11 +- .../Cryptography/ECDsaCng.HashData.cs | 21 -- .../System/Security/Cryptography/ECDsaCng.cs | 2 +- .../Security/Cryptography/ECDsaOpenSsl.cs | 11 +- .../Cryptography/ECDsaSecurityTransforms.cs | 11 +- .../Cryptography/IRuntimeAlgorithm.cs | 14 + .../Security/Cryptography/RSAAndroid.cs | 11 +- .../System/Security/Cryptography/RSACng.cs | 11 +- .../Security/Cryptography/RSAOpenSsl.cs | 11 +- .../Cryptography/RSASecurityTransforms.cs | 11 +- .../tests/AesCryptoServiceProviderTests.cs | 4 +- .../tests/DESCryptoServiceProviderTests.cs | 4 +- .../tests/DSACryptoServiceProviderTests.cs | 4 +- .../tests/RC2CryptoServiceProviderTests.cs | 4 +- .../tests/RSACryptoServiceProviderTests.cs | 4 +- .../tests/ShimHelpers.cs | 4 +- .../TripleDESCryptoServiceProviderTests.cs | 4 +- .../src/System.Security.Cryptography.csproj | 4 +- .../src/System/Security/Cryptography/DSA.cs | 20 +- .../src/System/Security/Cryptography/ECDsa.cs | 20 +- .../src/System/Security/Cryptography/RSA.cs | 15 +- .../RSACryptoServiceProvider.Unix.cs | 11 +- .../RSACryptoServiceProvider.Windows.cs | 41 +-- .../tests/DSATests.cs | 8 - .../tests/ECDsaTests.cs | 2 - .../tests/RSATests.cs | 2 - .../tests/SignatureAlgorithmHashTests.cs | 273 ++++++++++++++++++ .../System.Security.Cryptography.Tests.csproj | 1 + 31 files changed, 355 insertions(+), 223 deletions(-) delete mode 100644 src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.HashData.cs create mode 100644 src/libraries/Common/src/System/Security/Cryptography/IRuntimeAlgorithm.cs create mode 100644 src/libraries/System.Security.Cryptography/tests/SignatureAlgorithmHashTests.cs diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSACng.cs b/src/libraries/Common/src/System/Security/Cryptography/DSACng.cs index 3055b53fcc629..200b33d018ab0 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSACng.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSACng.cs @@ -9,7 +9,7 @@ namespace System.Security.Cryptography { - public sealed partial class DSACng : DSA + public sealed partial class DSACng : DSA, IRuntimeAlgorithm { /// /// Create a DSACng algorithm with a random 2048 bit key pair. @@ -45,16 +45,6 @@ public override KeySizes[] LegalKeySizes public override string SignatureAlgorithm => "DSA"; public override string? KeyExchangeAlgorithm => null; - // Need to override since base methods throw a "override me" exception: makes SignData/VerifyData function. - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan source, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, source, destination, out bytesWritten); - private void ForceSetKeySize(int newKeySize) { // Our LegalKeySizes value stores the values that we encoded as being the correct diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs index 6a3758d551cb9..3f2479b27ec2c 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs @@ -9,7 +9,7 @@ namespace System.Security.Cryptography { - public sealed partial class DSAOpenSsl : DSA + public sealed partial class DSAOpenSsl : DSA, IRuntimeAlgorithm { // The biggest key allowed by FIPS 186-4 has N=256 (bit), which // maximally produces a 72-byte DER signature. @@ -193,23 +193,6 @@ private SafeDsaHandle GenerateKey() return key; } - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) - { - // we're sealed and the base should have checked this already - Debug.Assert(data != null); - Debug.Assert(offset >= 0 && offset <= data.Length); - Debug.Assert(count >= 0 && count <= data.Length); - Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); - - return HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - } - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); - public override byte[] CreateSignature(byte[] rgbHash!!) { SafeDsaHandle key = GetKey(); diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs index b44810253c3e8..4fc9783a92b49 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs @@ -9,7 +9,7 @@ namespace System.Security.Cryptography { internal static partial class DSAImplementation { - public sealed partial class DSASecurityTransforms : DSA + public sealed partial class DSASecurityTransforms : DSA, IRuntimeAlgorithm { private SecKeyPair? _keys; private bool _disposed; @@ -118,12 +118,6 @@ protected override byte[] HashData(byte[] data, int offset, int count, HashAlgor return HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); } - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); - protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDsaAndroid.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDsaAndroid.cs index 6ababd3cfc2dc..95b7b5c0422f7 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDsaAndroid.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDsaAndroid.cs @@ -10,7 +10,7 @@ namespace System.Security.Cryptography { internal static partial class ECDsaImplementation { - public sealed partial class ECDsaAndroid : ECDsa + public sealed partial class ECDsaAndroid : ECDsa, IRuntimeAlgorithm { // secp521r1 maxes out at 139 bytes, so 256 should always be enough private const int SignatureStackBufSize = 256; @@ -240,15 +240,6 @@ protected override bool VerifyHashCore( return verifyResult == 1; } - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); - protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.HashData.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.HashData.cs deleted file mode 100644 index 21a13cfd1459b..0000000000000 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.HashData.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; - -using Internal.Cryptography; - -namespace System.Security.Cryptography -{ - public sealed partial class ECDsaCng : ECDsa - { - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan source, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, source, destination, out bytesWritten); - } -} diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.cs index 082608c735dc3..17e6a19687f99 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.cs @@ -5,7 +5,7 @@ namespace System.Security.Cryptography { - public sealed partial class ECDsaCng : ECDsa + public sealed partial class ECDsaCng : ECDsa, IRuntimeAlgorithm { /// /// Create an ECDsaCng algorithm with a named curve. diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs index b6ccb862a5489..a405efcca5960 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs @@ -9,7 +9,7 @@ namespace System.Security.Cryptography { - public sealed partial class ECDsaOpenSsl : ECDsa + public sealed partial class ECDsaOpenSsl : ECDsa, IRuntimeAlgorithm { // secp521r1 maxes out at 139 bytes, so 256 should always be enough private const int SignatureStackBufSize = 256; @@ -250,15 +250,6 @@ protected override bool VerifyHashCore( return verifyResult == 1; } - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); - protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs index 430d8a5366081..e988595931f71 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs @@ -9,7 +9,7 @@ namespace System.Security.Cryptography { internal static partial class ECDsaImplementation { - public sealed partial class ECDsaSecurityTransforms : ECDsa + public sealed partial class ECDsaSecurityTransforms : ECDsa, IRuntimeAlgorithm { private readonly EccSecurityTransforms _ecc = new EccSecurityTransforms(nameof(ECDsa)); @@ -135,15 +135,6 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign Interop.AppleCrypto.PAL_SignatureAlgorithm.EC); } - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan source, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, source, destination, out bytesWritten); - private void ThrowIfDisposed() { _ecc.ThrowIfDisposed(); diff --git a/src/libraries/Common/src/System/Security/Cryptography/IRuntimeAlgorithm.cs b/src/libraries/Common/src/System/Security/Cryptography/IRuntimeAlgorithm.cs new file mode 100644 index 0000000000000..05ebd26b1e74c --- /dev/null +++ b/src/libraries/Common/src/System/Security/Cryptography/IRuntimeAlgorithm.cs @@ -0,0 +1,14 @@ +// 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.Formats.Asn1; +using System.Numerics; + +namespace System.Security.Cryptography +{ + // Marker interface that goes on runtime-provided algorithms. + internal interface IRuntimeAlgorithm + { + } +} diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs index 563741049973c..ce28ddb440e86 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs @@ -13,7 +13,7 @@ namespace System.Security.Cryptography { internal static partial class RSAImplementation { - public sealed partial class RSAAndroid : RSA + public sealed partial class RSAAndroid : RSA, IRuntimeAlgorithm { private const int BitsPerByte = 8; @@ -647,15 +647,6 @@ private SafeRsaHandle GenerateKey() return key; } - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); - public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { ArgumentNullException.ThrowIfNull(hash); diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSACng.cs b/src/libraries/Common/src/System/Security/Cryptography/RSACng.cs index 29491d6f121f8..2c75b69dbde43 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSACng.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSACng.cs @@ -7,7 +7,7 @@ namespace System.Security.Cryptography { - public sealed partial class RSACng : RSA + public sealed partial class RSACng : RSA, IRuntimeAlgorithm { /// /// Create an RSACng algorithm with a random 2048 bit key pair. @@ -45,15 +45,6 @@ public override KeySizes[] LegalKeySizes } } - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - private void ForceSetKeySize(int newKeySize) { // Our LegalKeySizes value stores the values that we encoded as being the correct diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index 4fbb3948ead84..962afe991a197 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -12,7 +12,7 @@ namespace System.Security.Cryptography { - public sealed partial class RSAOpenSsl : RSA + public sealed partial class RSAOpenSsl : RSA, IRuntimeAlgorithm { private const int BitsPerByte = 8; @@ -717,15 +717,6 @@ private SafeEvpPKeyHandle GenerateKey() return Interop.Crypto.RsaGenerateKey(KeySize); } - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); - public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { ArgumentNullException.ThrowIfNull(hash); diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs index d9ccae5395a4a..56cf48bc9703a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs @@ -14,7 +14,7 @@ namespace System.Security.Cryptography { internal static partial class RSAImplementation { - public sealed partial class RSASecurityTransforms : RSA + public sealed partial class RSASecurityTransforms : RSA, IRuntimeAlgorithm { private SecKeyPair? _keys; @@ -555,15 +555,6 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - - protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); - protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/AesCryptoServiceProviderTests.cs b/src/libraries/System.Security.Cryptography.Csp/tests/AesCryptoServiceProviderTests.cs index 4c87e707ba4d4..a3920c0324311 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/AesCryptoServiceProviderTests.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/AesCryptoServiceProviderTests.cs @@ -79,9 +79,9 @@ public static void TestShimProperties() } [Fact] - public static void TestShimOverloads() + public static void TestShimOverrides() { - ShimHelpers.VerifyAllBaseMembersOverloaded(typeof(AesCryptoServiceProvider)); + ShimHelpers.VerifyAllBaseMembersOverridden(typeof(AesCryptoServiceProvider)); } } } diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/DESCryptoServiceProviderTests.cs b/src/libraries/System.Security.Cryptography.Csp/tests/DESCryptoServiceProviderTests.cs index ef71ca8ba8918..a95c38c8c3785 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/DESCryptoServiceProviderTests.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/DESCryptoServiceProviderTests.cs @@ -23,9 +23,9 @@ public static void TestShimProperties() [Fact] [PlatformSpecific(TestPlatforms.AnyUnix)] // Only Unix has _impl shim pattern - public static void TestShimOverloads_Unix() + public static void TestShimOverrides_Unix() { - ShimHelpers.VerifyAllBaseMembersOverloaded(typeof(DESCryptoServiceProvider)); + ShimHelpers.VerifyAllBaseMembersOverridden(typeof(DESCryptoServiceProvider)); } } } diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/DSACryptoServiceProviderTests.cs b/src/libraries/System.Security.Cryptography.Csp/tests/DSACryptoServiceProviderTests.cs index 8a703c33d1d25..ee39a1d91ee80 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/DSACryptoServiceProviderTests.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/DSACryptoServiceProviderTests.cs @@ -353,9 +353,9 @@ public static void SignatureAlgorithm_Success() [Fact] [PlatformSpecific(TestPlatforms.AnyUnix)] // Only Unix has _impl shim pattern - public static void TestShimOverloads_Unix() + public static void TestShimOverrides_Unix() { - ShimHelpers.VerifyAllBaseMembersOverloaded(typeof(DSACryptoServiceProvider)); + ShimHelpers.VerifyAllBaseMembersOverridden(typeof(DSACryptoServiceProvider)); } private sealed class DsaKeyLifetime : IDisposable diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/RC2CryptoServiceProviderTests.cs b/src/libraries/System.Security.Cryptography.Csp/tests/RC2CryptoServiceProviderTests.cs index 10e8882415f61..24902bf08c839 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/RC2CryptoServiceProviderTests.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/RC2CryptoServiceProviderTests.cs @@ -68,9 +68,9 @@ public static void TestShimProperties() [Fact] [PlatformSpecific(TestPlatforms.AnyUnix)] // Only Unix has _impl shim pattern - public static void TestShimOverloads_Unix() + public static void TestShimOverrides_Unix() { - ShimHelpers.VerifyAllBaseMembersOverloaded(typeof(RC2CryptoServiceProvider)); + ShimHelpers.VerifyAllBaseMembersOverridden(typeof(RC2CryptoServiceProvider)); } } } diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs index 083565c3ca990..b16d5e66d39ee 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs @@ -392,9 +392,9 @@ public static void SignData_VerifyHash_CaseInsensitive_Success() [Fact] [PlatformSpecific(TestPlatforms.AnyUnix)] // Only Unix has _impl shim pattern - public static void TestShimOverloads_Unix() + public static void TestShimOverrides_Unix() { - ShimHelpers.VerifyAllBaseMembersOverloaded(typeof(RSACryptoServiceProvider)); + ShimHelpers.VerifyAllBaseMembersOverridden(typeof(RSACryptoServiceProvider)); } private sealed class RsaKeyLifetime : IDisposable diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/ShimHelpers.cs b/src/libraries/System.Security.Cryptography.Csp/tests/ShimHelpers.cs index bf8d40dcf4ee1..ff21106b225d4 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/ShimHelpers.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/ShimHelpers.cs @@ -42,7 +42,7 @@ public static void TestSymmetricAlgorithmProperties(SymmetricAlgorithm alg, int } // Shims should override all virtual members and forward to their _impl. - public static void VerifyAllBaseMembersOverloaded(Type shimType) + public static void VerifyAllBaseMembersOverridden(Type shimType) { string[] namesToNotVerify = { @@ -65,6 +65,8 @@ public static void VerifyAllBaseMembersOverloaded(Type shimType) "ExportPkcs8PrivateKey", "ExportEncryptedPkcs8PrivateKey", "ExportRSAPrivateKey", + "HashData", + "TryHashData", "TryExportRSAPrivateKey", "TryExportRSAPublicKey", "TryExportSubjectPublicKeyInfo", diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/TripleDESCryptoServiceProviderTests.cs b/src/libraries/System.Security.Cryptography.Csp/tests/TripleDESCryptoServiceProviderTests.cs index b358bf44a8653..fef52ac1f6cbc 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/TripleDESCryptoServiceProviderTests.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/TripleDESCryptoServiceProviderTests.cs @@ -66,9 +66,9 @@ public static void TestShimProperties() } [Fact] - public static void TestShimOverloads() + public static void TestShimOverrides() { - ShimHelpers.VerifyAllBaseMembersOverloaded(typeof(TripleDESCryptoServiceProvider)); + ShimHelpers.VerifyAllBaseMembersOverridden(typeof(TripleDESCryptoServiceProvider)); } } } diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index d2026dd1b5fcc..53d2243ff1da6 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -232,6 +232,8 @@ Link="Common\System\Security\Cryptography\KeyBlobHelpers.cs" /> + - + HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) - { - throw DerivedClassMustOverride(); - } + protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => + HashOneShotHelpers.HashData(hashAlgorithm, data); public byte[] SignData(byte[] data!!, HashAlgorithmName hashAlgorithm) { @@ -499,6 +495,14 @@ protected virtual bool TryHashData( HashAlgorithmName hashAlgorithm, out int bytesWritten) { + // If this is an algorithm that we ship, then we can use the hash one-shot. + if (this is IRuntimeAlgorithm) + { + return HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); + } + + // If this is not our algorithm implementation, for compatibility purposes we need to + // call out to the HashData virtual. byte[] hash = HashSpanToArray(data, hashAlgorithm); return Helpers.TryCopyToDestination(hash, destination, out bytesWritten); } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECDsa.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECDsa.cs index bfeb7d190f5d2..e590ec853c6fa 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECDsa.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECDsa.cs @@ -672,18 +672,22 @@ protected virtual bool VerifyDataCore( public override string? KeyExchangeAlgorithm => null; public override string SignatureAlgorithm => "ECDsa"; - protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) - { - throw new NotSupportedException(SR.NotSupported_SubclassOverride); - } + protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => + HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) - { - throw new NotSupportedException(SR.NotSupported_SubclassOverride); - } + protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => + HashOneShotHelpers.HashData(hashAlgorithm, data); protected virtual bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { + // If this is an algorithm that we ship, then we can use the hash one-shot. + if (this is IRuntimeAlgorithm) + { + return HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); + } + + // If this is not our algorithm implementation, for compatibility purposes we need to + // call out to the HashData virtual. // Use ArrayPool.Shared instead of CryptoPool because the array is passed out. byte[] array = ArrayPool.Shared.Rent(data.Length); bool returnArray = false; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs index eb09a9d09f759..beac03aad08e5 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs @@ -64,8 +64,11 @@ public static RSA Create(RSAParameters parameters) public virtual byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) => throw DerivedClassMustOverride(); public virtual bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) => throw DerivedClassMustOverride(); - protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => throw DerivedClassMustOverride(); - protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => throw DerivedClassMustOverride(); + protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => + HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); + + protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => + HashOneShotHelpers.HashData(hashAlgorithm, data); public virtual bool TryDecrypt(ReadOnlySpan data, Span destination, RSAEncryptionPadding padding, out int bytesWritten) { @@ -99,6 +102,14 @@ public virtual bool TryEncrypt(ReadOnlySpan data, Span destination, protected virtual bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { + // If this is an algorithm that we ship, then we can use the hash one-shot. + if (this is IRuntimeAlgorithm) + { + return HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); + } + + // If this is not our algorithm implementation, for compatibility purposes we need to + // call out to the HashData virtual. byte[] result; // Use ArrayPool.Shared instead of CryptoPool because the array is passed out. byte[] array = ArrayPool.Shared.Rent(data.Length); diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs index ed7e0dc8743a3..1f598cdbd8312 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs @@ -7,7 +7,7 @@ namespace System.Security.Cryptography { - public sealed partial class RSACryptoServiceProvider : RSA, ICspAsymmetricAlgorithm + public sealed partial class RSACryptoServiceProvider : RSA, ICspAsymmetricAlgorithm, IRuntimeAlgorithm { private const int DefaultKeySize = 1024; @@ -106,15 +106,6 @@ public byte[] ExportCspBlob(bool includePrivateParameters) public override RSAParameters ExportParameters(bool includePrivateParameters) => _impl.ExportParameters(includePrivateParameters); - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, new ReadOnlySpan(data, offset, count)); - - protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => - HashOneShotHelpers.TryHashData(hashAlgorithm, data, destination, out bytesWritten); - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => - HashOneShotHelpers.HashData(hashAlgorithm, data); - public override void FromXmlString(string xmlString) => _impl.FromXmlString(xmlString); public void ImportCspBlob(byte[] keyBlob) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Windows.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Windows.cs index ba10764a98a22..d938cb355d344 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Windows.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Windows.cs @@ -9,7 +9,7 @@ namespace System.Security.Cryptography { - public sealed partial class RSACryptoServiceProvider : RSA, ICspAsymmetricAlgorithm + public sealed partial class RSACryptoServiceProvider : RSA, ICspAsymmetricAlgorithm, IRuntimeAlgorithm { private int _keySize; private readonly CspParameters _parameters; @@ -559,45 +559,6 @@ private static bool IsPublic(byte[] keyBlob!!) return true; } - protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) - { - // we're sealed and the base should have checked this already - Debug.Assert(data != null); - Debug.Assert(count >= 0 && count <= data.Length); - Debug.Assert(offset >= 0 && offset <= data.Length - count); - Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); - - using (HashAlgorithm hash = GetHashAlgorithm(hashAlgorithm)) - { - return hash.ComputeHash(data, offset, count); - } - } - - protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) - { - // we're sealed and the base should have checked this already - Debug.Assert(data != null); - Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); - - using (HashAlgorithm hash = GetHashAlgorithm(hashAlgorithm)) - { - return hash.ComputeHash(data); - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5351", Justification = "MD5 is used when the user asks for it.")] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 is used when the user asks for it.")] - private static HashAlgorithm GetHashAlgorithm(HashAlgorithmName hashAlgorithm) => - hashAlgorithm.Name switch - { - "MD5" => MD5.Create(), - "SHA1" => SHA1.Create(), - "SHA256" => SHA256.Create(), - "SHA384" => SHA384.Create(), - "SHA512" => SHA512.Create(), - _ => throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name), - }; - private static int GetAlgorithmId(HashAlgorithmName hashAlgorithm) => hashAlgorithm.Name switch { diff --git a/src/libraries/System.Security.Cryptography/tests/DSATests.cs b/src/libraries/System.Security.Cryptography/tests/DSATests.cs index 2e3bdc2e5e768..aea5a05b84ac6 100644 --- a/src/libraries/System.Security.Cryptography/tests/DSATests.cs +++ b/src/libraries/System.Security.Cryptography/tests/DSATests.cs @@ -13,14 +13,6 @@ public class DSATests { public static bool SupportsKeyGeneration => DSAFactory.SupportsKeyGeneration; - [Fact] - public void BaseVirtualsNotImplementedException() - { - var dsa = new EmptyDSA(); - Assert.Throws(() => dsa.HashData(null, HashAlgorithmName.SHA1)); - Assert.Throws(() => dsa.HashData(null, 0, 0, HashAlgorithmName.SHA1)); - } - [ConditionalFact(nameof(SupportsKeyGeneration))] public void TryCreateSignature_UsesCreateSignature() { diff --git a/src/libraries/System.Security.Cryptography/tests/ECDsaTests.cs b/src/libraries/System.Security.Cryptography/tests/ECDsaTests.cs index 7851ef4f7b4fe..f0219338241a1 100644 --- a/src/libraries/System.Security.Cryptography/tests/ECDsaTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/ECDsaTests.cs @@ -35,8 +35,6 @@ public void NotSupportedBaseMethods_Throw() Assert.Throws(() => ecdsa.ExportExplicitParameters(false)); Assert.Throws(() => ecdsa.ImportParameters(default(ECParameters))); Assert.Throws(() => ecdsa.GenerateKey(default(ECCurve))); - Assert.Throws(() => ecdsa.BaseHashData(null, HashAlgorithmName.SHA256)); - Assert.Throws(() => ecdsa.BaseHashData(null, 0, 0, HashAlgorithmName.SHA256)); Assert.Throws(() => ecdsa.FromXmlString(null)); Assert.Throws(() => ecdsa.ToXmlString(false)); diff --git a/src/libraries/System.Security.Cryptography/tests/RSATests.cs b/src/libraries/System.Security.Cryptography/tests/RSATests.cs index 17911da7f1b59..0932cd8053aa6 100644 --- a/src/libraries/System.Security.Cryptography/tests/RSATests.cs +++ b/src/libraries/System.Security.Cryptography/tests/RSATests.cs @@ -18,8 +18,6 @@ public void BaseVirtualsNotImplementedException() Assert.Throws(() => rsa.Encrypt(null, null)); Assert.Throws(() => rsa.SignHash(null, HashAlgorithmName.SHA256, null)); Assert.Throws(() => rsa.VerifyHash(null, null, HashAlgorithmName.SHA256, null)); - Assert.Throws(() => rsa.HashData(null, 0, 0, HashAlgorithmName.SHA256)); - Assert.Throws(() => rsa.HashData(null, HashAlgorithmName.SHA256)); } [Fact] diff --git a/src/libraries/System.Security.Cryptography/tests/SignatureAlgorithmHashTests.cs b/src/libraries/System.Security.Cryptography/tests/SignatureAlgorithmHashTests.cs new file mode 100644 index 0000000000000..ae2c2191f90b1 --- /dev/null +++ b/src/libraries/System.Security.Cryptography/tests/SignatureAlgorithmHashTests.cs @@ -0,0 +1,273 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.IO; +using Xunit; + +namespace System.Security.Cryptography.Tests +{ + public abstract class SignatureAlgorithmHashTests where TAlgorithm : IHashSigningAlgorithm, new() + { + [Theory] + [InlineData(nameof(HashAlgorithmName.MD5))] + [InlineData(nameof(HashAlgorithmName.SHA1))] + [InlineData(nameof(HashAlgorithmName.SHA256))] + [InlineData(nameof(HashAlgorithmName.SHA384))] + [InlineData(nameof(HashAlgorithmName.SHA512))] + public void TryHashData_UserDerived_UsesHashData(string hashAlgorithmName) + { + HashAlgorithmName hashAlgorithm = new HashAlgorithmName(hashAlgorithmName); + byte[] destination = new byte[SHA512.HashSizeInBytes]; + + using (TAlgorithm algorithm = new TAlgorithm()) + { + byte[] data = new byte[1]; + bool result = algorithm.TryHashDataImpl(data, destination, hashAlgorithm, out _); + Assert.True(result, nameof(algorithm.TryHashDataImpl)); + Assert.Equal(1, algorithm.HashDataByteCount); + } + } + + [Theory] + [MemberData(nameof(HashTheoryData))] + public void HashData_Simple(byte[] data, byte[] expectedHash, HashAlgorithmName hashAlgorithmName) + { + using (TAlgorithm algorithm = new TAlgorithm()) + { + byte[] hash = algorithm.HashDataImpl(data, 0, data.Length, hashAlgorithmName); + Assert.Equal(expectedHash, hash); + } + } + + [Theory] + [MemberData(nameof(HashTheoryData))] + public void HashData_Offsets(byte[] data, byte[] expectedHash, HashAlgorithmName hashAlgorithmName) + { + using (TAlgorithm algorithm = new TAlgorithm()) + { + byte[] padded = new byte[data.Length + 2]; + data.CopyTo(padded, 1); + byte[] hash = algorithm.HashDataImpl(padded, 1, data.Length, hashAlgorithmName); + Assert.Equal(expectedHash, hash); + } + } + + [Theory] + [MemberData(nameof(HashTheoryData))] + public void TryHashData_Success(byte[] data, byte[] expectedHash, HashAlgorithmName hashAlgorithmName) + { + using (TAlgorithm algorithm = new TAlgorithm()) + { + byte[] destination = new byte[expectedHash.Length]; + bool success = algorithm.TryHashDataImpl(data, destination, hashAlgorithmName, out int written); + Assert.True(success, nameof(algorithm.TryHashDataImpl)); + Assert.Equal(expectedHash, destination); + Assert.Equal(expectedHash.Length, written); + } + } + + public static IEnumerable HashTheoryData + { + get + { + yield return new object[] + { + new byte[] { 0x01, 0x02, 0x03, 0x04, 0xFC, 0xFD, 0xFE, 0xFF }, + new byte[] + { + 0x59, 0x85, 0xC6, 0xC0, 0x33, 0x93, 0xC1, 0xF2, + 0x62, 0x7B, 0xBF, 0x23, 0xC4, 0x5E, 0x42, 0x8B, + }, + HashAlgorithmName.MD5, + }; + yield return new object[] + { + new byte[] { 0x01, 0x02, 0x03, 0x04, 0xFC, 0xFD, 0xFE, 0xFF }, + new byte[] + { + 0xB6, 0xF2, 0x12, 0x87, 0x45, 0x32, 0xB4, 0xCA, + 0xB2, 0xC1, 0x03, 0x3C, 0x6D, 0xE4, 0x01, 0x61, + 0xEB, 0x7F, 0x6F, 0x11, + }, + HashAlgorithmName.SHA1, + }; + yield return new object[] + { + new byte[] { 0x01, 0x02, 0x03, 0x04, 0xFC, 0xFD, 0xFE, 0xFF }, + new byte[] + { + 0x54, 0x21, 0xB4, 0x8E, 0xCD, 0xC4, 0x64, 0x29, + 0xFB, 0x52, 0xBC, 0x35, 0x2C, 0xA7, 0xCF, 0xE6, + 0xE5, 0x48, 0xD9, 0x67, 0x93, 0x1D, 0x84, 0xF8, + 0xFC, 0x78, 0xCD, 0xAF, 0x30, 0x24, 0x9D, 0x2F, + }, + HashAlgorithmName.SHA256, + }; + yield return new object[] + { + new byte[] { 0x01, 0x02, 0x03, 0x04, 0xFC, 0xFD, 0xFE, 0xFF }, + new byte[] + { + 0xB6, 0x30, 0x80, 0x3F, 0x9A, 0xFD, 0x60, 0x2F, + 0xB5, 0x81, 0x65, 0x95, 0xC5, 0x14, 0xBC, 0x04, + 0xFA, 0x8F, 0x30, 0xC1, 0x48, 0xD3, 0xEF, 0xE3, + 0x02, 0xDA, 0x6D, 0x65, 0x41, 0x13, 0xBE, 0x71, + 0xB2, 0xE4, 0x1A, 0xA0, 0x2B, 0xD5, 0x59, 0x02, + 0x35, 0x64, 0x88, 0x0B, 0xC6, 0xCD, 0xDB, 0xCC, + }, + HashAlgorithmName.SHA384, + }; + yield return new object[] + { + new byte[] { 0x01, 0x02, 0x03, 0x04, 0xFC, 0xFD, 0xFE, 0xFF }, + new byte[] + { + 0xD2, 0x28, 0x6E, 0x35, 0xF8, 0x57, 0xEF, 0x9E, + 0x7E, 0xD2, 0x5D, 0xA7, 0xAB, 0xD1, 0x58, 0x1C, + 0x33, 0xF2, 0x76, 0x0F, 0x49, 0xED, 0x60, 0x1A, + 0x66, 0x93, 0x36, 0x67, 0x33, 0x16, 0xC0, 0x87, + 0x35, 0xBC, 0xC7, 0xA6, 0xB3, 0xBC, 0x51, 0x7A, + 0x42, 0xCE, 0xF4, 0x81, 0x8C, 0x51, 0x36, 0xA7, + 0xE2, 0x51, 0x86, 0x02, 0xBA, 0x5B, 0xC5, 0xEB, + 0x31, 0x86, 0xBD, 0x45, 0xBA, 0x05, 0x59, 0x06, + }, + HashAlgorithmName.SHA512, + }; + } + } + + } + + [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] + public class ECDsaAlgorithmHashTests : SignatureAlgorithmHashTests + { + public sealed class ECDsaUserDerivedImplementation : ECDsa, IHashSigningAlgorithm + { + public int HashDataStreamCount { get; set; } + public int HashDataByteCount { get; set; } + public int TryHashDataCount { get; set; } + + public override byte[] SignHash(byte[] hash) => throw new NotImplementedException(); + public override bool VerifyHash(byte[] hash, byte[] signature) => throw new NotImplementedException(); + + public byte[] HashDataImpl(Stream data, HashAlgorithmName hashAlgorithm) => HashData(data, hashAlgorithm); + + public byte[] HashDataImpl(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => + HashData(data, offset, count, hashAlgorithm); + + public bool TryHashDataImpl(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => + TryHashData(data, destination, hashAlgorithm, out bytesWritten); + + protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) + { + HashDataStreamCount++; + return base.HashData(data, hashAlgorithm); + } + + protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) + { + HashDataByteCount++; + return base.HashData(data, offset, count, hashAlgorithm); + } + + protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) + { + TryHashDataCount++; + return base.TryHashData(data, destination, hashAlgorithm, out bytesWritten); + } + } + } + + [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] + public class DSAAlgorithmHashTests : SignatureAlgorithmHashTests + { + public sealed class DSAUserDerivedImplementation : DSA, IHashSigningAlgorithm + { + public int HashDataStreamCount { get; set; } + public int HashDataByteCount { get; set; } + public int TryHashDataCount { get; set; } + + public override DSAParameters ExportParameters(bool includePrivate) => throw new NotImplementedException(); + public override void ImportParameters(DSAParameters parameters) => throw new NotImplementedException(); + public override byte[] CreateSignature(byte[] data) => throw new NotImplementedException(); + public override bool VerifySignature(byte[] data, byte[] signature) => throw new NotImplementedException(); + + public byte[] HashDataImpl(Stream data, HashAlgorithmName hashAlgorithm) => HashData(data, hashAlgorithm); + + public byte[] HashDataImpl(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => + HashData(data, offset, count, hashAlgorithm); + + public bool TryHashDataImpl(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => + TryHashData(data, destination, hashAlgorithm, out bytesWritten); + + protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) + { + HashDataStreamCount++; + return base.HashData(data, hashAlgorithm); + } + + protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) + { + HashDataByteCount++; + return base.HashData(data, offset, count, hashAlgorithm); + } + + protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) + { + TryHashDataCount++; + return base.TryHashData(data, destination, hashAlgorithm, out bytesWritten); + } + } + } + + [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] + public class RSAAlgorithmHashTests : SignatureAlgorithmHashTests + { + public sealed class RSAUserDerivedImplementation : RSA, IHashSigningAlgorithm + { + public int HashDataStreamCount { get; set; } + public int HashDataByteCount { get; set; } + public int TryHashDataCount { get; set; } + + public override RSAParameters ExportParameters(bool includePrivate) => throw new NotImplementedException(); + public override void ImportParameters(RSAParameters parameters) => throw new NotImplementedException(); + + public byte[] HashDataImpl(Stream data, HashAlgorithmName hashAlgorithm) => HashData(data, hashAlgorithm); + + public byte[] HashDataImpl(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => + HashData(data, offset, count, hashAlgorithm); + + public bool TryHashDataImpl(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) => + TryHashData(data, destination, hashAlgorithm, out bytesWritten); + + protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) + { + HashDataStreamCount++; + return base.HashData(data, hashAlgorithm); + } + + protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) + { + HashDataByteCount++; + return base.HashData(data, offset, count, hashAlgorithm); + } + + protected override bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) + { + TryHashDataCount++; + return base.TryHashData(data, destination, hashAlgorithm, out bytesWritten); + } + } + } + + public interface IHashSigningAlgorithm : IDisposable + { + int HashDataStreamCount { get; set; } + int HashDataByteCount { get; set; } + int TryHashDataCount { get; set; } + byte[] HashDataImpl(Stream data, HashAlgorithmName hashAlgorithm); + byte[] HashDataImpl(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm); + bool TryHashDataImpl(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten); + } +} diff --git a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj index f869165548023..b672db1d9ecd1 100644 --- a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj +++ b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj @@ -269,6 +269,7 @@ +