File: src\runtime\src\libraries\Common\src\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.manual.cs
Web Access
Project: src\src\runtime\src\libraries\System.Security.Cryptography.Pkcs\src\System.Security.Cryptography.Pkcs.csproj (System.Security.Cryptography.Pkcs)
// 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.Security.Cryptography.Pkcs;

#if BUILDING_PKCS
using Helpers = Internal.Cryptography.PkcsHelpers;
#endif

namespace System.Security.Cryptography.Asn1.Pkcs12
{
    internal partial struct PfxAsn
    {
        internal unsafe bool VerifyMac(
            ReadOnlySpan<char> macPassword,
            ReadOnlySpan<byte> authSafeContents)
        {
            Debug.Assert(MacData.HasValue);

            HashAlgorithmName hashAlgorithm;
            int expectedOutputSize;

            string algorithmValue = MacData.Value.Mac.DigestAlgorithm.Algorithm;

            switch (algorithmValue)
            {
                case Oids.Md5:
                    expectedOutputSize = 128 >> 3;
                    hashAlgorithm = HashAlgorithmName.MD5;
                    break;
                case Oids.Sha1:
                    expectedOutputSize = 160 >> 3;
                    hashAlgorithm = HashAlgorithmName.SHA1;
                    break;
                case Oids.Sha256:
                    expectedOutputSize = 256 >> 3;
                    hashAlgorithm = HashAlgorithmName.SHA256;
                    break;
                case Oids.Sha384:
                    expectedOutputSize = 384 >> 3;
                    hashAlgorithm = HashAlgorithmName.SHA384;
                    break;
                case Oids.Sha512:
                    expectedOutputSize = 512 >> 3;
                    hashAlgorithm = HashAlgorithmName.SHA512;
                    break;
                default:
                    throw new CryptographicException(
                        SR.Format(SR.Cryptography_UnknownHashAlgorithm, algorithmValue));
            }

            if (MacData.Value.Mac.Digest.Length != expectedOutputSize)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

#if NET
            Debug.Assert((uint)expectedOutputSize <= 64); // SHA512 is the largest digest size we know about
            Span<byte> derived = stackalloc byte[expectedOutputSize];
#else
            byte[] derived = new byte[expectedOutputSize];
#endif


            int iterationCount =
                PasswordBasedEncryption.NormalizeIterationCount(MacData.Value.IterationCount);

            Pkcs12Kdf.DeriveMacKey(
                macPassword,
                hashAlgorithm,
                iterationCount,
                MacData.Value.MacSalt.Span,
                derived);

            using (IncrementalHash hmac = IncrementalHash.CreateHMAC(hashAlgorithm, derived))
            {
                hmac.AppendData(authSafeContents);

                if (!hmac.TryGetHashAndReset(derived, out int bytesWritten) || bytesWritten != expectedOutputSize)
                {
                    Debug.Fail($"TryGetHashAndReset wrote {bytesWritten} bytes when {expectedOutputSize} was expected");
                    throw new CryptographicException();
                }

                return CryptographicOperations.FixedTimeEquals(
                    derived,
                    MacData.Value.Mac.Digest.Span);
            }
        }
    }
}