// 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); } } } } |