File: System\Security\Cryptography\DSA.cs
Web Access
Project: src\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Buffers;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Formats.Asn1;
using System.IO;
using System.Runtime.Versioning;
using Internal.Cryptography;
 
namespace System.Security.Cryptography
{
    public abstract partial class DSA : AsymmetricAlgorithm
    {
        // As of FIPS 186-4 the maximum Q size is 256 bits (32 bytes).
        // The DER signature format thus maxes out at 2 + 3 + 33 + 3 + 33 => 74 bytes.
        // So 128 should always work.
        private const int SignatureStackSize = 128;
        // The biggest supported hash algorithm is SHA-2-512, which is only 64 bytes.
        // One power of two bigger should cover most unknown algorithms, too.
        private const int HashBufferStackSize = 128;
 
        public abstract DSAParameters ExportParameters(bool includePrivateParameters);
 
        public abstract void ImportParameters(DSAParameters parameters);
 
        protected DSA() { }
 
        [Obsolete(Obsoletions.CryptoStringFactoryMessage, DiagnosticId = Obsoletions.CryptoStringFactoryDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        [RequiresUnreferencedCode(CryptoConfig.CreateFromNameUnreferencedCodeMessage)]
        public static new DSA? Create(string algName)
        {
            return (DSA?)CryptoConfig.CreateFromName(algName);
        }
 
        [UnsupportedOSPlatform("browser")]
        [UnsupportedOSPlatform("ios")]
        [UnsupportedOSPlatform("tvos")]
        public static new DSA Create()
        {
            return CreateCore();
        }
 
        [UnsupportedOSPlatform("browser")]
        [UnsupportedOSPlatform("ios")]
        [UnsupportedOSPlatform("tvos")]
        public static DSA Create(int keySizeInBits)
        {
            DSA dsa = CreateCore();
 
            try
            {
                dsa.KeySize = keySizeInBits;
                return dsa;
            }
            catch
            {
                dsa.Dispose();
                throw;
            }
        }
 
        [UnsupportedOSPlatform("browser")]
        [UnsupportedOSPlatform("ios")]
        [UnsupportedOSPlatform("tvos")]
        public static DSA Create(DSAParameters parameters)
        {
            var dsa = CreateCore();
 
            try
            {
                dsa.ImportParameters(parameters);
                return dsa;
            }
            catch
            {
                dsa.Dispose();
                throw;
            }
        }
 
        // DSA does not encode the algorithm identifier into the signature blob, therefore CreateSignature and
        // VerifySignature do not need the HashAlgorithmName value, only SignData and VerifyData do.
        public abstract byte[] CreateSignature(byte[] rgbHash);
 
        public abstract bool VerifySignature(byte[] rgbHash, byte[] rgbSignature);
 
        protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) =>
            CryptographicOperations.HashData(hashAlgorithm, new ReadOnlySpan<byte>(data, offset, count));
 
        protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) =>
            CryptographicOperations.HashData(hashAlgorithm, data);
 
        public byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm)
        {
            ArgumentNullException.ThrowIfNull(data);
 
            // hashAlgorithm is verified in the overload
 
            return SignData(data, 0, data.Length, hashAlgorithm);
        }
 
        /// <summary>
        ///   Computes the hash value of the specified data and signs it using the specified signature format.
        /// </summary>
        /// <param name="data">The data to sign.</param>
        /// <param name="hashAlgorithm">The hash algorithm to use to create the hash value.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <returns>
        ///   The DSA signature for the specified data.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///   <paramref name="data"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="hashAlgorithm"/> has a <see langword="null"/> or empty <see cref="HashAlgorithmName.Name"/>.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or signing operation.
        /// </exception>
        public byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat)
        {
            ArgumentNullException.ThrowIfNull(data);
 
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return SignDataCore(data, hashAlgorithm, signatureFormat);
        }
 
        public virtual byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
        {
            ArgumentNullException.ThrowIfNull(data);
 
            ArgumentOutOfRangeException.ThrowIfNegative(offset);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, data.Length);
 
            ArgumentOutOfRangeException.ThrowIfNegative(count);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(count, data.Length - offset);
 
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
 
            byte[] hash = HashData(data, offset, count, hashAlgorithm);
            return CreateSignature(hash);
        }
 
        /// <summary>
        ///   Computes the hash value of the specified data and signs it using the specified signature format.
        /// </summary>
        /// <param name="data">The data to sign.</param>
        /// <param name="offset">The offset into <paramref name="data"/> at which to begin hashing.</param>
        /// <param name="count">The number of bytes to read from <paramref name="data"/>.</param>
        /// <param name="hashAlgorithm">The hash algorithm to use to create the hash value.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <returns>
        ///   The DSA signature for the specified data.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///   <paramref name="data"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        ///
        ///   -or-
        ///
        ///   <paramref name="offset" /> is less than zero.
        ///
        ///   -or-
        ///
        ///   <paramref name="count" /> is less than zero.
        ///
        ///   -or-
        ///
        ///   <paramref name="offset" /> + <paramref name="count"/> - 1 results in an index that is
        ///   beyond the upper bound of <paramref name="data"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="hashAlgorithm"/> has a <see langword="null"/> or empty <see cref="HashAlgorithmName.Name"/>.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or signing operation.
        /// </exception>
        public byte[] SignData(
            byte[] data,
            int offset,
            int count,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat)
        {
            ArgumentNullException.ThrowIfNull(data);
 
            ArgumentOutOfRangeException.ThrowIfNegative(offset);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, data.Length);
 
            ArgumentOutOfRangeException.ThrowIfNegative(count);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(count, data.Length - offset);
 
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return SignDataCore(new ReadOnlySpan<byte>(data, offset, count), hashAlgorithm, signatureFormat);
        }
 
        /// <summary>
        ///   Computes the hash value of the specified data and signs it using the specified signature format.
        /// </summary>
        /// <param name="data">The data to sign.</param>
        /// <param name="hashAlgorithm">The hash algorithm to use to create the hash value.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <returns>
        ///   The DSA signature for the specified data.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or signing operation.
        /// </exception>
        protected virtual byte[] SignDataCore(
            ReadOnlySpan<byte> data,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat)
        {
            Span<byte> signature = stackalloc byte[SignatureStackSize];
 
            if (TrySignDataCore(data, signature, hashAlgorithm, signatureFormat, out int bytesWritten))
            {
                return signature.Slice(0, bytesWritten).ToArray();
            }
 
            // If that didn't work, fall back on older approaches.
 
            byte[] hash = HashSpanToArray(data, hashAlgorithm);
            byte[] sig = CreateSignature(hash);
            return AsymmetricAlgorithmHelpers.ConvertFromIeeeP1363Signature(sig, signatureFormat);
        }
 
        public virtual byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
 
            byte[] hash = HashData(data, hashAlgorithm);
            return CreateSignature(hash);
        }
 
        /// <summary>
        ///   Computes the hash value of the specified data and signs it using the specified signature format.
        /// </summary>
        /// <param name="data">The data to sign.</param>
        /// <param name="hashAlgorithm">The hash algorithm to use to create the hash value.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <returns>
        ///   The DSA signature for the specified data.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///   <paramref name="data"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="hashAlgorithm"/> has a <see langword="null"/> or empty <see cref="HashAlgorithmName.Name"/>.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or signing operation.
        /// </exception>
        public byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return SignDataCore(data, hashAlgorithm, signatureFormat);
        }
 
        /// <summary>
        ///   Computes the hash value of the specified data and signs it using the specified signature format.
        /// </summary>
        /// <param name="data">The data to sign.</param>
        /// <param name="hashAlgorithm">The hash algorithm to use to create the hash value.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <returns>
        ///   The DSA signature for the specified data.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or signing operation.
        /// </exception>
        protected virtual byte[] SignDataCore(Stream data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat)
        {
            byte[] hash = HashData(data, hashAlgorithm);
            return CreateSignatureCore(hash, signatureFormat);
        }
 
        public bool VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm)
        {
            ArgumentNullException.ThrowIfNull(data);
 
            return VerifyData(data, 0, data.Length, signature, hashAlgorithm);
        }
 
        public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm)
        {
            ArgumentNullException.ThrowIfNull(data);
 
            ArgumentOutOfRangeException.ThrowIfNegative(offset);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, data.Length);
 
            ArgumentOutOfRangeException.ThrowIfNegative(count);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(count, data.Length - offset);
 
            ArgumentNullException.ThrowIfNull(signature);
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
 
            byte[] hash = HashData(data, offset, count, hashAlgorithm);
            return VerifySignature(hash, signature);
        }
 
        /// <summary>
        ///   Verifies that a digital signature is valid for the provided data.
        /// </summary>
        /// <param name="data">An array that contains the signed data.</param>
        /// <param name="offset">The starting index of the signed portion of <paramref name="data"/>.</param>
        /// <param name="count">The number of bytes in <paramref name="data"/> that were signed.</param>
        /// <param name="signature">The signature to verify.</param>
        /// <param name="hashAlgorithm">The hash algorithm used to hash the data for the verification process.</param>
        /// <param name="signatureFormat">The encoding format for <paramref name="signature"/>.</param>
        /// <returns>
        ///   <see langword="true"/> if the digital signature is valid for the provided data; otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///   <paramref name="data"/> or <paramref name="signature"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        ///
        ///   -or-
        ///
        ///   <paramref name="offset" /> is less than zero.
        ///
        ///   -or-
        ///
        ///   <paramref name="count" /> is less than zero.
        ///
        ///   -or-
        ///
        ///   <paramref name="offset" /> + <paramref name="count"/> - 1 results in an index that is
        ///   beyond the upper bound of <paramref name="data"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="hashAlgorithm"/> has a <see langword="null"/> or empty <see cref="HashAlgorithmName.Name"/>.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or verification operation.
        /// </exception>
        public bool VerifyData(
            byte[] data,
            int offset,
            int count,
            byte[] signature,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat)
        {
            ArgumentNullException.ThrowIfNull(data);
 
            ArgumentOutOfRangeException.ThrowIfNegative(offset);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, data.Length);
 
            ArgumentOutOfRangeException.ThrowIfNegative(count);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(count, data.Length - offset);
 
            ArgumentNullException.ThrowIfNull(signature);
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return VerifyDataCore(new ReadOnlySpan<byte>(data, offset, count), signature, hashAlgorithm, signatureFormat);
        }
 
        public virtual bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(signature);
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
 
            byte[] hash = HashData(data, hashAlgorithm);
            return VerifySignature(hash, signature);
        }
 
        /// <summary>
        ///   Creates the DSA signature for the specified hash value in the indicated format.
        /// </summary>
        /// <param name="rgbHash">The hash value to sign.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <returns>
        ///   The DSA signature for the specified data.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///   <paramref name="rgbHash"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the signing operation.
        /// </exception>
        public byte[] CreateSignature(byte[] rgbHash, DSASignatureFormat signatureFormat)
        {
            ArgumentNullException.ThrowIfNull(rgbHash);
 
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return CreateSignatureCore(rgbHash, signatureFormat);
        }
 
        /// <summary>
        ///   Creates the DSA signature for the specified hash value in the indicated format.
        /// </summary>
        /// <param name="hash">The hash value to sign.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <returns>
        ///   The DSA signature for the specified data.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the signing operation.
        /// </exception>
        protected virtual byte[] CreateSignatureCore(ReadOnlySpan<byte> hash, DSASignatureFormat signatureFormat)
        {
            Span<byte> signature = stackalloc byte[SignatureStackSize];
 
            if (TryCreateSignatureCore(hash, signature, signatureFormat, out int bytesWritten))
            {
                return signature.Slice(0, bytesWritten).ToArray();
            }
 
            // If that didn't work, fall back to the older overload and convert formats.
            byte[] sig = CreateSignature(hash.ToArray());
            return AsymmetricAlgorithmHelpers.ConvertFromIeeeP1363Signature(sig, signatureFormat);
        }
 
        public virtual bool TryCreateSignature(ReadOnlySpan<byte> hash, Span<byte> destination, out int bytesWritten)
            => TryCreateSignatureCore(hash, destination, DSASignatureFormat.IeeeP1363FixedFieldConcatenation, out bytesWritten);
 
        /// <summary>
        ///   Attempts to create the DSA signature for the specified hash value in the indicated format
        ///   into the provided buffer.
        /// </summary>
        /// <param name="hash">The hash value to sign.</param>
        /// <param name="destination">The buffer to receive the signature.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <param name="bytesWritten">
        ///   When this method returns, contains a value that indicates the number of bytes written to
        ///   <paramref name="destination"/>. This parameter is treated as uninitialized.
        /// </param>
        /// <returns>
        ///   <see langword="true"/> if <paramref name="destination"/> is big enough to receive the signature;
        ///   otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the signing operation.
        /// </exception>
        public bool TryCreateSignature(
            ReadOnlySpan<byte> hash,
            Span<byte> destination,
            DSASignatureFormat signatureFormat,
            out int bytesWritten)
        {
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return TryCreateSignatureCore(hash, destination, signatureFormat, out bytesWritten);
        }
 
        /// <summary>
        ///   Attempts to create the DSA signature for the specified hash value in the indicated format
        ///   into the provided buffer.
        /// </summary>
        /// <param name="hash">The hash value to sign.</param>
        /// <param name="destination">The buffer to receive the signature.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <param name="bytesWritten">
        ///   When this method returns, contains a value that indicates the number of bytes written to
        ///   <paramref name="destination"/>. This parameter is treated as uninitialized.
        /// </param>
        /// <returns>
        ///   <see langword="true"/> if <paramref name="destination"/> is big enough to receive the signature;
        ///   otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the signing operation.
        /// </exception>
        protected virtual bool TryCreateSignatureCore(
            ReadOnlySpan<byte> hash,
            Span<byte> destination,
            DSASignatureFormat signatureFormat,
            out int bytesWritten)
        {
            // This method is expected to be overridden with better implementation
 
            // The only available implementation here is abstract method, use it
            byte[] sig = CreateSignature(hash.ToArray());
 
            if (signatureFormat != DSASignatureFormat.IeeeP1363FixedFieldConcatenation)
            {
                sig = AsymmetricAlgorithmHelpers.ConvertFromIeeeP1363Signature(sig, signatureFormat);
            }
 
            return Helpers.TryCopyToDestination(sig, destination, out bytesWritten);
        }
 
        protected virtual bool TryHashData(
            ReadOnlySpan<byte> data,
            Span<byte> 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 CryptographicOperations.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);
        }
 
        public virtual bool TrySignData(
            ReadOnlySpan<byte> data,
            Span<byte> destination,
            HashAlgorithmName hashAlgorithm,
            out int bytesWritten)
        {
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
 
            if (TryHashData(data, destination, hashAlgorithm, out int hashLength) &&
                TryCreateSignature(destination.Slice(0, hashLength), destination, out bytesWritten))
            {
                return true;
            }
 
            bytesWritten = 0;
            return false;
        }
 
        /// <summary>
        ///   Attempts to create the DSA signature for the specified data in the indicated format
        ///   into the provided buffer.
        /// </summary>
        /// <param name="data">The data to hash and sign.</param>
        /// <param name="destination">The buffer to receive the signature.</param>
        /// <param name="hashAlgorithm">The hash algorithm to use to create the hash value.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <param name="bytesWritten">
        ///   When this method returns, contains a value that indicates the number of bytes written to
        ///   <paramref name="destination"/>. This parameter is treated as uninitialized.
        /// </param>
        /// <returns>
        ///   <see langword="true"/> if <paramref name="destination"/> is big enough to receive the signature;
        ///   otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="hashAlgorithm"/> has a <see langword="null"/> or empty <see cref="HashAlgorithmName.Name"/>.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the signing operation.
        /// </exception>
        public bool TrySignData(
            ReadOnlySpan<byte> data,
            Span<byte> destination,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat,
            out int bytesWritten)
        {
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return TrySignDataCore(data, destination, hashAlgorithm, signatureFormat, out bytesWritten);
        }
 
        /// <summary>
        ///   Attempts to create the DSA signature for the specified data in the indicated format
        ///   into the provided buffer.
        /// </summary>
        /// <param name="data">The data to hash and sign.</param>
        /// <param name="destination">The buffer to receive the signature.</param>
        /// <param name="hashAlgorithm">The hash algorithm to use to create the hash value.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <param name="bytesWritten">
        ///   When this method returns, contains a value that indicates the number of bytes written to
        ///   <paramref name="destination"/>. This parameter is treated as uninitialized.
        /// </param>
        /// <returns>
        ///   <see langword="true"/> if <paramref name="destination"/> is big enough to receive the signature;
        ///   otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the signing operation.
        /// </exception>
        protected virtual bool TrySignDataCore(
            ReadOnlySpan<byte> data,
            Span<byte> destination,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat,
            out int bytesWritten)
        {
            Span<byte> tmp = stackalloc byte[HashBufferStackSize];
            ReadOnlySpan<byte> hash = HashSpanToTmp(data, hashAlgorithm, tmp);
 
            return TryCreateSignatureCore(hash, destination, signatureFormat, out bytesWritten);
        }
 
        public virtual bool VerifyData(
            ReadOnlySpan<byte> data,
            ReadOnlySpan<byte> signature,
            HashAlgorithmName hashAlgorithm)
        {
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
 
            return VerifyDataCore(data, signature, hashAlgorithm, DSASignatureFormat.IeeeP1363FixedFieldConcatenation);
        }
 
        /// <summary>
        ///   Verifies that a digital signature is valid for the provided data.
        /// </summary>
        /// <param name="data">The signed data.</param>
        /// <param name="signature">The signature to verify.</param>
        /// <param name="hashAlgorithm">The hash algorithm used to hash the data for the verification process.</param>
        /// <param name="signatureFormat">The encoding format for <paramref name="signature"/>.</param>
        /// <returns>
        ///   <see langword="true"/> if the digital signature is valid for the provided data; otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///   <paramref name="data"/> or <paramref name="signature"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="hashAlgorithm"/> has a <see langword="null"/> or empty <see cref="HashAlgorithmName.Name"/>.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or verification operation.
        /// </exception>
        public bool VerifyData(
            byte[] data,
            byte[] signature,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(signature);
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return VerifyDataCore(data, signature, hashAlgorithm, signatureFormat);
        }
 
        /// <summary>
        ///   Verifies that a digital signature is valid for the provided data.
        /// </summary>
        /// <param name="data">The signed data.</param>
        /// <param name="signature">The signature to verify.</param>
        /// <param name="hashAlgorithm">The hash algorithm used to hash the data for the verification process.</param>
        /// <param name="signatureFormat">The encoding format for <paramref name="signature"/>.</param>
        /// <returns>
        ///   <see langword="true"/> if the digital signature is valid for the provided data; otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///   <paramref name="data"/> or <paramref name="signature"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="hashAlgorithm"/> has a <see langword="null"/> or empty <see cref="HashAlgorithmName.Name"/>.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or verification operation.
        /// </exception>
        public bool VerifyData(
            Stream data,
            byte[] signature,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(signature);
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return VerifyDataCore(data, signature, hashAlgorithm, signatureFormat);
        }
 
        /// <summary>
        ///   Verifies that a digital signature is valid for the provided data.
        /// </summary>
        /// <param name="data">The signed data.</param>
        /// <param name="signature">The signature to verify.</param>
        /// <param name="hashAlgorithm">The hash algorithm used to hash the data for the verification process.</param>
        /// <param name="signatureFormat">The encoding format for <paramref name="signature"/>.</param>
        /// <returns>
        ///   <see langword="true"/> if the digital signature is valid for the provided data; otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or verification operation.
        /// </exception>
        protected virtual bool VerifyDataCore(
            Stream data,
            ReadOnlySpan<byte> signature,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat)
        {
            byte[] hash = HashData(data, hashAlgorithm);
            return VerifySignatureCore(hash, signature, signatureFormat);
        }
 
        /// <summary>
        ///   Verifies that a digital signature is valid for the provided data.
        /// </summary>
        /// <param name="data">The signed data.</param>
        /// <param name="signature">The signature to verify.</param>
        /// <param name="hashAlgorithm">The hash algorithm used to hash the data for the verification process.</param>
        /// <param name="signatureFormat">The encoding format for <paramref name="signature"/>.</param>
        /// <returns>
        ///   <see langword="true"/> if the digital signature is valid for the provided data; otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or verification operation.
        /// </exception>
        public bool VerifyData(
            ReadOnlySpan<byte> data,
            ReadOnlySpan<byte> signature,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat)
        {
            ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return VerifyDataCore(data, signature, hashAlgorithm, signatureFormat);
        }
 
        /// <summary>
        ///   Verifies that a digital signature is valid for the provided data.
        /// </summary>
        /// <param name="data">The signed data.</param>
        /// <param name="signature">The signature to verify.</param>
        /// <param name="hashAlgorithm">The hash algorithm used to hash the data for the verification process.</param>
        /// <param name="signatureFormat">The encoding format for <paramref name="signature"/>.</param>
        /// <returns>
        ///   <see langword="true"/> if the digital signature is valid for the provided data; otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or verification operation.
        /// </exception>
        protected virtual bool VerifyDataCore(
            ReadOnlySpan<byte> data,
            ReadOnlySpan<byte> signature,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat)
        {
            Span<byte> tmp = stackalloc byte[HashBufferStackSize];
            ReadOnlySpan<byte> hash = HashSpanToTmp(data, hashAlgorithm, tmp);
 
            return VerifySignatureCore(hash, signature, signatureFormat);
        }
 
        /// <summary>
        ///   Verifies that a digital signature is valid for the provided hash.
        /// </summary>
        /// <param name="rgbHash">The signed hash.</param>
        /// <param name="rgbSignature">The signature to verify.</param>
        /// <param name="signatureFormat">The encoding format for <paramref name="rgbSignature"/>.</param>
        /// <returns>
        ///   <see langword="true"/> if the digital signature is valid for the provided data; otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///   <paramref name="rgbHash"/> or <paramref name="rgbSignature"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the verification operation.
        /// </exception>
        public bool VerifySignature(byte[] rgbHash, byte[] rgbSignature, DSASignatureFormat signatureFormat)
        {
            ArgumentNullException.ThrowIfNull(rgbHash);
            ArgumentNullException.ThrowIfNull(rgbSignature);
 
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return VerifySignatureCore(rgbHash, rgbSignature, signatureFormat);
        }
 
        public virtual bool VerifySignature(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature) =>
            VerifySignature(hash.ToArray(), signature.ToArray());
 
        /// <summary>
        ///   Verifies that a digital signature is valid for the provided hash.
        /// </summary>
        /// <param name="hash">The signed hash.</param>
        /// <param name="signature">The signature to verify.</param>
        /// <param name="signatureFormat">The encoding format for <paramref name="signature"/>.</param>
        /// <returns>
        ///   <see langword="true"/> if the digital signature is valid for the provided data; otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the verification operation.
        /// </exception>
        public bool VerifySignature(
            ReadOnlySpan<byte> hash,
            ReadOnlySpan<byte> signature,
            DSASignatureFormat signatureFormat)
        {
            if (!signatureFormat.IsKnownValue())
                throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat);
 
            return VerifySignatureCore(hash, signature, signatureFormat);
        }
 
        /// <summary>
        ///   Verifies that a digital signature is valid for the provided hash.
        /// </summary>
        /// <param name="hash">The signed hash.</param>
        /// <param name="signature">The signature to verify.</param>
        /// <param name="signatureFormat">The encoding format for <paramref name="signature"/>.</param>
        /// <returns>
        ///   <see langword="true"/> if the digital signature is valid for the provided data; otherwise, <see langword="false"/>.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the verification operation.
        /// </exception>
        protected virtual bool VerifySignatureCore(
            ReadOnlySpan<byte> hash,
            ReadOnlySpan<byte> signature,
            DSASignatureFormat signatureFormat)
        {
            // This method is expected to be overridden with better implementation
 
            byte[]? sig = this.ConvertSignatureToIeeeP1363(signatureFormat, signature);
 
            // If the signature failed normalization to IEEE P1363 then it
            // obviously doesn't verify.
            if (sig == null)
            {
                return false;
            }
 
            // The only available implementation here is abstract method, use it.
            // Since it requires an exactly-sized array, skip pooled arrays.
            return VerifySignature(hash, sig);
        }
 
        private ReadOnlySpan<byte> HashSpanToTmp(
            ReadOnlySpan<byte> data,
            HashAlgorithmName hashAlgorithm,
            Span<byte> tmp)
        {
            Debug.Assert(tmp.Length == HashBufferStackSize);
 
            if (TryHashData(data, tmp, hashAlgorithm, out int hashSize))
            {
                return tmp.Slice(0, hashSize);
            }
 
            // This is not expected, but a poor virtual implementation of TryHashData,
            // or an exotic new algorithm, will hit this fallback.
            return HashSpanToArray(data, hashAlgorithm);
        }
 
        private byte[] HashSpanToArray(ReadOnlySpan<byte> data, HashAlgorithmName hashAlgorithm)
        {
            // Use ArrayPool.Shared instead of CryptoPool because the array is passed out.
            byte[] array = ArrayPool<byte>.Shared.Rent(data.Length);
            bool returnArray = false;
            try
            {
                data.CopyTo(array);
                byte[] ret = HashData(array, 0, data.Length, hashAlgorithm);
                returnArray = true;
                return ret;
            }
            finally
            {
                Array.Clear(array, 0, data.Length);
 
                if (returnArray)
                {
                    ArrayPool<byte>.Shared.Return(array);
                }
            }
        }
 
        private static NotImplementedException DerivedClassMustOverride() =>
            new NotImplementedException(SR.NotSupported_SubclassOverride);
 
        public override bool TryExportEncryptedPkcs8PrivateKey(
            ReadOnlySpan<byte> passwordBytes,
            PbeParameters pbeParameters,
            Span<byte> destination,
            out int bytesWritten)
        {
            ArgumentNullException.ThrowIfNull(pbeParameters);
 
            PasswordBasedEncryption.ValidatePbeParameters(
                pbeParameters,
                ReadOnlySpan<char>.Empty,
                passwordBytes);
 
            AsnWriter pkcs8PrivateKey = WritePkcs8();
 
            AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
                passwordBytes,
                pkcs8PrivateKey,
                pbeParameters);
 
            return writer.TryEncode(destination, out bytesWritten);
        }
 
        public override bool TryExportEncryptedPkcs8PrivateKey(
            ReadOnlySpan<char> password,
            PbeParameters pbeParameters,
            Span<byte> destination,
            out int bytesWritten)
        {
            ArgumentNullException.ThrowIfNull(pbeParameters);
 
            PasswordBasedEncryption.ValidatePbeParameters(
                pbeParameters,
                password,
                ReadOnlySpan<byte>.Empty);
 
            AsnWriter pkcs8PrivateKey = WritePkcs8();
            AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
                password,
                pkcs8PrivateKey,
                pbeParameters);
 
            return writer.TryEncode(destination, out bytesWritten);
        }
 
        public override bool TryExportPkcs8PrivateKey(
            Span<byte> destination,
            out int bytesWritten)
        {
            AsnWriter writer = WritePkcs8();
            return writer.TryEncode(destination, out bytesWritten);
        }
 
        public override bool TryExportSubjectPublicKeyInfo(
            Span<byte> destination,
            out int bytesWritten)
        {
            AsnWriter writer = WriteSubjectPublicKeyInfo();
            return writer.TryEncode(destination, out bytesWritten);
        }
 
        private unsafe AsnWriter WritePkcs8()
        {
            DSAParameters dsaParameters = ExportParameters(true);
 
            fixed (byte* privPin = dsaParameters.X)
            {
                try
                {
                    return DSAKeyFormatHelper.WritePkcs8(dsaParameters);
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(dsaParameters.X);
                }
            }
        }
 
        private AsnWriter WriteSubjectPublicKeyInfo()
        {
            DSAParameters dsaParameters = ExportParameters(false);
            return DSAKeyFormatHelper.WriteSubjectPublicKeyInfo(dsaParameters);
        }
 
        public override unsafe void ImportEncryptedPkcs8PrivateKey(
            ReadOnlySpan<byte> passwordBytes,
            ReadOnlySpan<byte> source,
            out int bytesRead)
        {
            DSAKeyFormatHelper.ReadEncryptedPkcs8(
                source,
                passwordBytes,
                out int localRead,
                out DSAParameters ret);
 
            fixed (byte* privPin = ret.X)
            {
                try
                {
                    ImportParameters(ret);
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(ret.X);
                }
            }
 
            bytesRead = localRead;
        }
 
        public override unsafe void ImportEncryptedPkcs8PrivateKey(
            ReadOnlySpan<char> password,
            ReadOnlySpan<byte> source,
            out int bytesRead)
        {
            DSAKeyFormatHelper.ReadEncryptedPkcs8(
                source,
                password,
                out int localRead,
                out DSAParameters ret);
 
            fixed (byte* privPin = ret.X)
            {
                try
                {
                    ImportParameters(ret);
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(ret.X);
                }
            }
 
            bytesRead = localRead;
        }
 
        public override unsafe void ImportPkcs8PrivateKey(
            ReadOnlySpan<byte> source,
            out int bytesRead)
        {
            DSAKeyFormatHelper.ReadPkcs8(
                source,
                out int localRead,
                out DSAParameters key);
 
            fixed (byte* privPin = key.X)
            {
                try
                {
                    ImportParameters(key);
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(key.X);
                }
            }
 
            bytesRead = localRead;
        }
 
        public override void ImportSubjectPublicKeyInfo(
            ReadOnlySpan<byte> source,
            out int bytesRead)
        {
            DSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
                source,
                out int localRead,
                out DSAParameters key);
 
            ImportParameters(key);
            bytesRead = localRead;
        }
 
        /// <summary>
        ///   Gets the largest size, in bytes, for a signature produced by this key in the indicated format.
        /// </summary>
        /// <param name="signatureFormat">The encoding format for a signature.</param>
        /// <returns>
        ///   The largest size, in bytes, for a signature produced by this key in the indicated format.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        public int GetMaxSignatureSize(DSASignatureFormat signatureFormat)
        {
            DSAParameters dsaParameters = ExportParameters(false);
            int qLength = dsaParameters.Q!.Length;
 
            switch (signatureFormat)
            {
                case DSASignatureFormat.IeeeP1363FixedFieldConcatenation:
                    return qLength * 2;
                case DSASignatureFormat.Rfc3279DerSequence:
                    return AsymmetricAlgorithmHelpers.GetMaxDerSignatureSize(fieldSizeBits: qLength * 8);
                default:
                    throw new ArgumentOutOfRangeException(nameof(signatureFormat));
            }
        }
 
        /// <summary>
        /// Imports an RFC 7468 PEM-encoded key, replacing the keys for this object.
        /// </summary>
        /// <param name="input">The PEM text of the key to import.</param>
        /// <exception cref="ArgumentException">
        /// <para>
        ///   <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
        /// </para>
        /// <para>
        ///   -or-
        /// </para>
        /// <para>
        ///   <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
        /// </para>
        /// <para>
        ///     -or-
        /// </para>
        /// <para>
        ///   <paramref name="input"/> contains an encrypted PEM-encoded key.
        /// </para>
        /// </exception>
        /// <remarks>
        ///   <para>
        ///   Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
        ///   are found, an exception is raised to prevent importing a key when
        ///   the key is ambiguous.
        ///   </para>
        ///   <para>
        ///   This method supports the following PEM labels:
        ///   <list type="bullet">
        ///     <item><description>PUBLIC KEY</description></item>
        ///     <item><description>PRIVATE KEY</description></item>
        ///   </list>
        ///   </para>
        /// </remarks>
        public override void ImportFromPem(ReadOnlySpan<char> input)
        {
            // Implementation has been pushed down to AsymmetricAlgorithm. The
            // override remains for compatibility.
            base.ImportFromPem(input);
        }
 
        /// <summary>
        /// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
        /// </summary>
        /// <param name="input">The PEM text of the encrypted key to import.</param>
        /// <param name="password">
        /// The password to use for decrypting the key material.
        /// </param>
        /// <exception cref="ArgumentException">
        /// <para>
        ///   <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
        /// </para>
        /// <para>
        ///    -or-
        /// </para>
        /// <para>
        ///   <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
        /// </para>
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   <para>
        ///   The password is incorrect.
        ///   </para>
        ///   <para>
        ///       -or-
        ///   </para>
        ///   <para>
        ///   The base-64 decoded contents of the PEM text from <paramref name="input" />
        ///   do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
        ///   </para>
        ///   <para>
        ///       -or-
        ///   </para>
        ///   <para>
        ///   The base-64 decoded contents of the PEM text from <paramref name="input" />
        ///   indicate the key is for an algorithm other than the algorithm
        ///   represented by this instance.
        ///   </para>
        ///   <para>
        ///       -or-
        ///   </para>
        ///   <para>
        ///   The base-64 decoded contents of the PEM text from <paramref name="input" />
        ///   represent the key in a format that is not supported.
        ///   </para>
        ///   <para>
        ///       -or-
        ///   </para>
        ///   <para>
        ///   The algorithm-specific key import failed.
        ///   </para>
        /// </exception>
        /// <remarks>
        ///   <para>
        ///   When the base-64 decoded contents of <paramref name="input" /> indicate an algorithm that uses PBKDF1
        ///   (Password-Based Key Derivation Function 1) or PBKDF2 (Password-Based Key Derivation Function 2),
        ///   the password is converted to bytes via the UTF-8 encoding.
        ///   </para>
        ///   <para>
        ///   Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
        ///   are found, an exception is thrown to prevent importing a key when
        ///   the key is ambiguous.
        ///   </para>
        ///   <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
        /// </remarks>
        public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<char> password)
        {
            // Implementation has been pushed down to AsymmetricAlgorithm. The
            // override remains for compatibility.
            base.ImportFromEncryptedPem(input, password);
        }
 
        /// <summary>
        /// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
        /// </summary>
        /// <param name="input">The PEM text of the encrypted key to import.</param>
        /// <param name="passwordBytes">
        /// The bytes to use as a password when decrypting the key material.
        /// </param>
        /// <exception cref="ArgumentException">
        ///   <para>
        ///     <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
        ///   </para>
        ///   <para>
        ///       -or-
        ///   </para>
        ///   <para>
        ///     <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
        ///   </para>
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   <para>
        ///   The password is incorrect.
        ///   </para>
        ///   <para>
        ///       -or-
        ///   </para>
        ///   <para>
        ///   The base-64 decoded contents of the PEM text from <paramref name="input" />
        ///   do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
        ///   </para>
        ///   <para>
        ///       -or-
        ///   </para>
        ///   <para>
        ///   The base-64 decoded contents of the PEM text from <paramref name="input" />
        ///   indicate the key is for an algorithm other than the algorithm
        ///   represented by this instance.
        ///   </para>
        ///   <para>
        ///       -or-
        ///   </para>
        ///   <para>
        ///   The base-64 decoded contents of the PEM text from <paramref name="input" />
        ///   represent the key in a format that is not supported.
        ///   </para>
        ///   <para>
        ///       -or-
        ///   </para>
        ///   <para>
        ///   The algorithm-specific key import failed.
        ///   </para>
        /// </exception>
        /// <remarks>
        ///   <para>
        ///   The password bytes are passed directly into the Key Derivation Function (KDF)
        ///   used by the algorithm indicated by <c>pbeParameters</c>. This enables compatibility
        ///   with other systems which use a text encoding other than UTF-8 when processing
        ///   passwords with PBKDF2 (Password-Based Key Derivation Function 2).
        ///   </para>
        ///   <para>
        ///   Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
        ///   are found, an exception is thrown to prevent importing a key when
        ///   the key is ambiguous.
        ///   </para>
        ///   <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
        /// </remarks>
        public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<byte> passwordBytes)
        {
            // Implementation has been pushed down to AsymmetricAlgorithm. The
            // override remains for compatibility.
            base.ImportFromEncryptedPem(input, passwordBytes);
        }
    }
}