private static unsafe byte[] MacAndEncode( AsnWriter tmpWriter, ReadOnlyMemory <byte> encodedAuthSafe, ReadOnlySpan <char> passwordSpan) { const int MacSize = 160 / 8; // HMAC-SHA1 is 160 bits. Span <byte> macKey = stackalloc byte[MacSize]; Span <byte> macSalt = stackalloc byte[MacSize]; Span <byte> macSpan = stackalloc byte[MacSize]; RandomNumberGenerator.Fill(macSalt); Pkcs12Kdf.DeriveMacKey( passwordSpan, HashAlgorithmName.SHA1, s_windowsPbe.IterationCount, macSalt, macKey); int bytesWritten = HMACSHA1.HashData(macKey, encodedAuthSafe.Span, macSpan); if (bytesWritten != MacSize) { Debug.Fail($"HMACSHA1.HashData wrote {bytesWritten} of {MacSize} bytes"); throw new CryptographicException(); } CryptographicOperations.ZeroMemory(macKey); // https://tools.ietf.org/html/rfc7292#section-4 // // PFX ::= SEQUENCE { // version INTEGER {v3(3)}(v3,...), // authSafe ContentInfo, // macData MacData OPTIONAL // } Debug.Assert(tmpWriter.GetEncodedLength() == 0); tmpWriter.PushSequence(); tmpWriter.WriteInteger(3); tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data); tmpWriter.PushSequence(s_contextSpecific0); { tmpWriter.WriteOctetString(encodedAuthSafe.Span); tmpWriter.PopSequence(s_contextSpecific0); } tmpWriter.PopSequence(); } // https://tools.ietf.org/html/rfc7292#section-4 // // MacData ::= SEQUENCE { // mac DigestInfo, // macSalt OCTET STRING, // iterations INTEGER DEFAULT 1 // -- Note: The default is for historical reasons and its use is // -- deprecated. // } tmpWriter.PushSequence(); { tmpWriter.PushSequence(); { tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Sha1); tmpWriter.PopSequence(); } tmpWriter.WriteOctetString(macSpan); tmpWriter.PopSequence(); } tmpWriter.WriteOctetString(macSalt); tmpWriter.WriteInteger(s_windowsPbe.IterationCount); tmpWriter.PopSequence(); } tmpWriter.PopSequence(); return(tmpWriter.Encode()); }
internal 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 NETCOREAPP Debug.Assert(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)); } }
private static unsafe byte[] MacAndEncode( AsnWriter tmpWriter, ReadOnlyMemory <byte> encodedAuthSafe, ReadOnlySpan <char> passwordSpan) { // Windows/macOS compatibility: Use HMAC-SHA-1, // other algorithms may not be understood byte[] macKey = new byte[20]; Span <byte> macSalt = stackalloc byte[20]; Span <byte> macSpan = stackalloc byte[20]; HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; RandomNumberGenerator.Fill(macSalt); fixed(byte *macKeyPtr = macKey) { Span <byte> macKeySpan = macKey; Pkcs12Kdf.DeriveMacKey( passwordSpan, hashAlgorithm, s_windowsPbe.IterationCount, macSalt, macKeySpan); using (IncrementalHash mac = IncrementalHash.CreateHMAC(hashAlgorithm, macKey)) { mac.AppendData(encodedAuthSafe.Span); if (!mac.TryGetHashAndReset(macSpan, out int bytesWritten) || bytesWritten != macSpan.Length) { Debug.Fail($"TryGetHashAndReset wrote {bytesWritten} of {macSpan.Length} bytes"); throw new CryptographicException(); } } CryptographicOperations.ZeroMemory(macKeySpan); } // https://tools.ietf.org/html/rfc7292#section-4 // // PFX ::= SEQUENCE { // version INTEGER {v3(3)}(v3,...), // authSafe ContentInfo, // macData MacData OPTIONAL // } Debug.Assert(tmpWriter.GetEncodedLength() == 0); tmpWriter.PushSequence(); tmpWriter.WriteInteger(3); tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data); tmpWriter.PushSequence(s_contextSpecific0); { tmpWriter.WriteOctetString(encodedAuthSafe.Span); tmpWriter.PopSequence(s_contextSpecific0); } tmpWriter.PopSequence(); } // https://tools.ietf.org/html/rfc7292#section-4 // // MacData ::= SEQUENCE { // mac DigestInfo, // macSalt OCTET STRING, // iterations INTEGER DEFAULT 1 // -- Note: The default is for historical reasons and its use is // -- deprecated. // } tmpWriter.PushSequence(); { tmpWriter.PushSequence(); { tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Sha1); tmpWriter.PopSequence(); } tmpWriter.WriteOctetString(macSpan); tmpWriter.PopSequence(); } tmpWriter.WriteOctetString(macSalt); tmpWriter.WriteInteger(s_windowsPbe.IterationCount); tmpWriter.PopSequence(); } tmpWriter.PopSequence(); return(tmpWriter.Encode()); }