Exemple #1
0
 private void CalculateSignature(
     ReadOnlySpan <byte> message,
     uint sequenceNumber,
     ReadOnlySpan <byte> signingKey,
     RC4 seal,
     Span <byte> signature)
 {
     BinaryPrimitives.WriteInt32LittleEndian(signature, 1);
     BinaryPrimitives.WriteUInt32LittleEndian(signature.Slice(12), sequenceNumber);
     using (var hmac = IncrementalHash.CreateHMAC(HashAlgorithmName.MD5, signingKey))
     {
         hmac.AppendData(signature.Slice(12, 4));
         hmac.AppendData(message);
         Span <byte> hmacResult = stackalloc byte[hmac.HashLengthInBytes];
         hmac.GetHashAndReset(hmacResult);
         if (_negotiatedFlags.HasFlag(Flags.NegotiateKeyExchange))
         {
             seal.Transform(hmacResult.Slice(0, 8), signature.Slice(4, 8));
         }
         else
         {
             hmacResult.Slice(0, 8).CopyTo(signature.Slice(4, 8));
         }
     }
 }
Exemple #2
0
        private void ValidateAuthentication(byte[] incomingBlob)
        {
            ReadOnlySpan <byte> lmChallengeResponse       = GetField(incomingBlob, 12);
            ReadOnlySpan <byte> ntChallengeResponse       = GetField(incomingBlob, 20);
            ReadOnlySpan <byte> encryptedRandomSessionKey = GetField(incomingBlob, 52);
            ReadOnlySpan <byte> mic = incomingBlob.AsSpan(72, 16);

            Flags flags = (Flags)BinaryPrimitives.ReadUInt32LittleEndian(incomingBlob.AsSpan(60));

            Assert.Equal(_requiredFlags, (flags & _requiredFlags));

            // Only one encoding can be selected by the client
            Assert.True((flags & (Flags.NegotiateOEM | Flags.NegotiateUnicode)) != 0);
            Assert.True((flags & (Flags.NegotiateOEM | Flags.NegotiateUnicode)) != (Flags.NegotiateOEM | Flags.NegotiateUnicode));
            Encoding encoding = flags.HasFlag(Flags.NegotiateUnicode) ? Encoding.Unicode : Encoding.ASCII;

            string domainName  = encoding.GetString(GetField(incomingBlob, 28));
            string userName    = encoding.GetString(GetField(incomingBlob, 36));
            string workstation = encoding.GetString(GetField(incomingBlob, 44));

            Assert.Equal(_expectedCredential.UserName, userName);
            Assert.Equal(_expectedCredential.Domain, domainName);

            byte[]      ntlm2hash      = MakeNtlm2Hash();
            Span <byte> sessionBaseKey = stackalloc byte[16];

            using (IncrementalHash hmac = IncrementalHash.CreateHMAC(HashAlgorithmName.MD5, ntlm2hash))
            {
                hmac.AppendData(_serverChallenge);
                hmac.AppendData(ntChallengeResponse.Slice(16));
                // If this matches then the password matched
                IsAuthenticated = hmac.GetHashAndReset().AsSpan().SequenceEqual(ntChallengeResponse.Slice(0, 16));

                if (!IsAuthenticated)
                {
                    // Bail out
                    return;
                }

                // Compute sessionBaseKey
                hmac.AppendData(ntChallengeResponse.Slice(0, 16));
                hmac.GetHashAndReset(sessionBaseKey);
            }

            ReadOnlySpan <byte> avPairs = ntChallengeResponse.Slice(16 + 28);
            AvFlags             avFlags = 0;

            while (avPairs[0] != (byte)AvId.EOL)
            {
                AvId id = (AvId)avPairs[0];
                Assert.Equal(0, avPairs[1]);
                ushort length = BinaryPrimitives.ReadUInt16LittleEndian(avPairs.Slice(2, 2));

                if (id == AvId.Flags)
                {
                    Assert.Equal(4, length);
                    avFlags = (AvFlags)BinaryPrimitives.ReadUInt32LittleEndian(avPairs.Slice(4, 4));
                }
                else if (id == AvId.TargetName)
                {
                    ClientSpecifiedSpn = Encoding.Unicode.GetString(avPairs.Slice(4, length));
                }

                avPairs = avPairs.Slice(length + 4);
            }

            // Decrypt exportedSessionKey with sessionBaseKey
            Span <byte> exportedSessionKey = stackalloc byte[16];

            if (flags.HasFlag(Flags.NegotiateKeyExchange) &&
                (flags.HasFlag(Flags.NegotiateSeal) || flags.HasFlag(Flags.NegotiateSign)))
            {
                using (RC4 rc4 = new RC4(sessionBaseKey))
                {
                    rc4.Transform(encryptedRandomSessionKey, exportedSessionKey);
                }
            }
            else
            {
                sessionBaseKey.CopyTo(exportedSessionKey);
            }

            // Calculate and verify message integrity if enabled
            if (avFlags.HasFlag(AvFlags.MICPresent))
            {
                IsMICPresent = true;

                Assert.NotNull(_negotiateMessage);
                Assert.NotNull(_challengeMessage);
                byte[] calculatedMic = new byte[16];
                using (var hmacMic = IncrementalHash.CreateHMAC(HashAlgorithmName.MD5, exportedSessionKey))
                {
                    hmacMic.AppendData(_negotiateMessage);
                    hmacMic.AppendData(_challengeMessage);
                    // Authenticate message with the MIC erased
                    hmacMic.AppendData(incomingBlob.AsSpan(0, 72));
                    hmacMic.AppendData(new byte[16]);
                    hmacMic.AppendData(incomingBlob.AsSpan(72 + 16));
                    hmacMic.GetHashAndReset(calculatedMic);
                }
                Assert.Equal(mic.ToArray(), calculatedMic);
            }

            // Derive signing keys
            _clientSigningKey = DeriveKey(exportedSessionKey, ClientSigningKeyMagic);
            _serverSigningKey = DeriveKey(exportedSessionKey, ServerSigningKeyMagic);
            _clientSealingKey = DeriveKey(exportedSessionKey, ClientSealingKeyMagic);
            _serverSealingKey = DeriveKey(exportedSessionKey, ServerSealingKeyMagic);
            ResetKeys();
            _negotiatedFlags = flags;
            CryptographicOperations.ZeroMemory(exportedSessionKey);
        }