/// <summary>
        /// Validates the client Netlogon authenticator by incrementing the Netlogon credential 
        /// in the Netlogon authenticator by one, performs the computation described in section 
        /// 3.1.4.4, Netlogon Credential Computation, and stores the new Netlogon credential. 
        /// The server returns a Netlogon authenticator that contains the new Netlogon credential 
        /// to the client.
        /// </summary>
        /// <param name="clientAuthenticator">
        /// Authenticator from client to validate.
        /// </param>
        /// <param name="algorithm">
        /// Algorithm to validate the authenticator.
        /// </param>
        /// <param name="serverStoredCredential">
        /// A byte array containing the credential that is maintained by 
        /// the server and that is used during computation and 
        /// verification of the Netlogon authenticator.
        /// </param>
        /// <param name="sessionKey">Session Key</param>
        /// <returns>Return true if validate successfully; otherwise, false.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when serverStoredCredential or sessionKey is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when Credential.data field of clientAuthenticator is null. 
        /// Thrown when session key length is incorrect.
        /// </exception>
        public static bool ValidateClientNetlogonAuthenticator(
            _NETLOGON_AUTHENTICATOR clientAuthenticator,
            NrpcComputeNetlogonCredentialAlgorithm algorithm,
            ref byte[] serverStoredCredential,
            byte[] sessionKey)
        {
            if (serverStoredCredential == null)
            {
                throw new ArgumentNullException("serverStoredCredential");
            }
            if (sessionKey == null)
            {
                throw new ArgumentNullException("sessionKey");
            }
            if (sessionKey.Length != NETLOGON_SESSION_KEY_LENGTH)
            {
                throw new ArgumentException("Session key length is incorrect.", "sessionKey");
            }
            if (clientAuthenticator.Credential.data == null)
            {
                throw new ArgumentException("clientAuthenticator is invalid.", "clientAuthenticator");
            }

            //SET ServerStoredCredential = ServerStoredCredential +
            //      ClientAuthenticator.Timestamp;
            //CALL ComputeNetlogonCredential(ServerStoredCredential,
            //      Session-Key, TempCredential);
            //IF TempCredential != ClientAuthenticator.Credential
            //THEN return access denied error

            //In each of the addition operations previously performed,
            //the least-significant 4 bytes of the credential are added
            //with the 4-byte time stamp value (or the constant 1),
            //and overflow is ignored. This leaves the most-significant
            //4 bytes of the credential unmodified.
            uint credential = BitConverter.ToUInt32(serverStoredCredential, 0);
            credential += clientAuthenticator.Timestamp;
            byte[] buf = BitConverter.GetBytes(credential);
            Array.Copy(buf, serverStoredCredential, buf.Length);

            byte[] tempCredential = ComputeNetlogonCredential(
                algorithm,
                serverStoredCredential,
                sessionKey);

            return ArrayUtility.CompareArrays(tempCredential, clientAuthenticator.Credential.data);
        }
        /// <summary>
        /// Compute the Netlogon Credential.
        /// </summary>
        /// <param name="algorithm">
        /// Algorithm to compute the Netlogon authenticator. 
        /// </param>
        /// <param name="input">
        /// A byte array that contains the input.
        /// </param>
        /// <param name="sessionKey">
        /// Session Key.
        /// </param>
        /// <returns>Netlogon Credential</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when input or sessionKey parameter 
        /// passed to the method is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when computation algorithm is not supported. 
        /// Thrown when session key length is incorrect.
        /// </exception>
        public static byte[] ComputeNetlogonCredential(
            NrpcComputeNetlogonCredentialAlgorithm algorithm,
            byte[] input,
            byte[] sessionKey)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }
            if (sessionKey == null)
            {
                throw new ArgumentNullException("sessionKey");
            }
            if (sessionKey.Length != NETLOGON_SESSION_KEY_LENGTH)
            {
                throw new ArgumentException("Session key length is incorrect.", "sessionKey");
            }

            byte[] credential;

            switch (algorithm)
            {
                case NrpcComputeNetlogonCredentialAlgorithm.AES128:
                    //ComputeNetlogonCredential(Input, Sk, Output)
                    //SET IV = 0
                    //CALL AesEncrypt(Input, Sk, IV, Output)

                    using (BCryptAlgorithm aes = new BCryptAlgorithm("AES"))
                    {
                        aes.Mode = BCryptCipherMode.CFB;
                        aes.Key = sessionKey;
                        aes.IV = new byte[aes.BlockSize]; //AES128's IV is 128 bits.
                        credential = aes.Encrypt(input);
                    }

                    break;

                case NrpcComputeNetlogonCredentialAlgorithm.DESECB:
                    //ComputeNetlogonCredential(Input, Sk, Output)
                    //SET k1 to bytes(0, 6, Sk)
                    //CALL InitLMKey(k1, k3)
                    //SET k2 to bytes(7, 13, Sk)
                    //CALL InitLMKey(k2, k4)
                    //CALL DES_ECB(Input, k3, &output1)
                    //CALL DES_ECB(output1, k4, &output2)
                    //SET Output to output2

                    byte[] k1 = ArrayUtility.SubArray(sessionKey, 0, 7);
                    byte[] k2 = ArrayUtility.SubArray(sessionKey, 7, 7);

                    using (DES des = DES.Create())
                    {
                        des.Mode = CipherMode.ECB;
                        des.Padding = PaddingMode.None;

                        des.Key = InitLMKey(k1);
                        byte[] output1 = des.CreateEncryptor().TransformFinalBlock(input, 0, input.Length);

                        des.Key = InitLMKey(k2);
                        byte[] output2 = des.CreateEncryptor().TransformFinalBlock(output1, 0, output1.Length);

                        credential = output2;
                    }

                    break;

                default:
                    throw new ArgumentException(
                        "Specified netlogon credential computation algorithm is not valid.",
                        "algorithm");
            }

            return credential;
        }
        /// <summary>
        /// Compute the Netlogon Authenticator at server-side.
        /// </summary>
        /// <param name="algorithm">
        /// Algorithm to compute the authenticator.
        /// </param>
        /// <param name="serverStoredCredential">
        /// A byte array containing the credential that is created by the server and 
        /// received by the client and that is used during computation and 
        /// verification of the Netlogon authenticator.
        /// </param>
        /// <param name="sessionKey">
        /// Session Key.
        /// </param>
        /// <returns>Netlogon Authenticator</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when serverStoredCredential or sessionKey is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when session key length is incorrect.
        /// </exception>
        public static _NETLOGON_AUTHENTICATOR ComputeServerNetlogonAuthenticator(
            NrpcComputeNetlogonCredentialAlgorithm algorithm,
            ref byte[] serverStoredCredential,
            byte[] sessionKey)
        {
            if (serverStoredCredential == null)
            {
                throw new ArgumentNullException("serverStoredCredential");
            }
            if (sessionKey == null)
            {
                throw new ArgumentNullException("sessionKey");
            }
            if (sessionKey.Length != NETLOGON_SESSION_KEY_LENGTH)
            {
                throw new ArgumentException("Session key length is incorrect.", "sessionKey");
            }

            //SET ServerStoredCredential = ServerStoredCredential + 1;
            //CALL ComputeNetlogonCredential(ServerStoredCredential,
            //Session-Key, ServerAuthenticator.Credential);

            _NETLOGON_AUTHENTICATOR authenticator = new _NETLOGON_AUTHENTICATOR();

            //In each of the addition operations previously performed,
            //the least-significant 4 bytes of the credential are added
            //with the 4-byte time stamp value (or the constant 1),
            //and overflow is ignored. This leaves the most-significant
            //4 bytes of the credential unmodified.
            uint credential = BitConverter.ToUInt32(serverStoredCredential, 0);
            credential += 1;
            byte[] buf = BitConverter.GetBytes(credential);
            Array.Copy(buf, serverStoredCredential, buf.Length);

            authenticator.Credential = new _NETLOGON_CREDENTIAL();
            authenticator.Credential.data = ComputeNetlogonCredential(
                algorithm,
                serverStoredCredential,
                sessionKey);

            return authenticator;
        }
        /// <summary>
        /// Compute the Netlogon Authenticator at client-side.
        /// </summary>
        /// <param name="algorithm">
        /// Algorithm to compute the authenticator.
        /// </param>
        /// <param name="time">
        /// Current time on client.
        /// </param>
        /// <param name="clientStoredCredential">
        /// A byte array containing the credential that is created by the client and 
        /// received by the server and that is used during computation and 
        /// verification of the Netlogon authenticator.
        /// </param>
        /// <param name="sessionKey">
        /// Session Key.
        /// </param>
        /// <returns>Netlogon Authenticator</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when clientStoredCredential or sessionKey is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when session key length is incorrect.
        /// </exception>
        public static _NETLOGON_AUTHENTICATOR ComputeClientNetlogonAuthenticator(
            NrpcComputeNetlogonCredentialAlgorithm algorithm,
            DateTime time,
            ref byte[] clientStoredCredential,
            byte[] sessionKey)
        {
            if (clientStoredCredential == null)
            {
                throw new ArgumentNullException("clientStoredCredential");
            }
            if (sessionKey == null)
            {
                throw new ArgumentNullException("sessionKey");
            }
            if (sessionKey.Length != NETLOGON_SESSION_KEY_LENGTH)
            {
                throw new ArgumentException("Session key length is incorrect.", "sessionKey");
            }

            //SET TimeNow = current time;
            //SET ClientAuthenticator.Timestamp = TimeNow;
            //SET ClientStoredCredential = ClientStoredCredential + TimeNow;
            //CALL ComputeNetlogonCredential(ClientStoredCredential, Session-Key, ClientAuthenticator.Credential);

            //Timestamp is an integer value that contains the time of day at
            //which the client constructed this authentication credential,
            //represented as the number of elapsed seconds since 00:00:00 of January 1, 1970 (UTC).

            DateTime time19700101 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            _NETLOGON_AUTHENTICATOR authenticator = new _NETLOGON_AUTHENTICATOR();

            authenticator.Timestamp = (uint)(
                (time.ToUniversalTime() - time19700101).Ticks / TimeSpan.TicksPerSecond);

            //In each of the addition operations previously performed,
            //the least-significant 4 bytes of the credential are added
            //with the 4-byte time stamp value (or the constant 1),
            //and overflow is ignored. This leaves the most-significant
            //4 bytes of the credential unmodified.
            uint credential = BitConverter.ToUInt32(clientStoredCredential, 0);
            credential += authenticator.Timestamp;
            byte[] buf = BitConverter.GetBytes(credential);
            Array.Copy(buf, clientStoredCredential, buf.Length);

            authenticator.Credential = new _NETLOGON_CREDENTIAL();
            authenticator.Credential.data = ComputeNetlogonCredential(
                algorithm,
                clientStoredCredential,
                sessionKey);

            return authenticator;
        }