/// <summary>
        ///  The NetrServerTrustPasswordsGet method Supported in windows_2000_server_sp4,
        ///  windows_xp, and windows_server_2003, windows_vista,
        ///  windows_server_2008, windows_7, and windows_server_7.
        ///  returns the encrypted current and previous passwords
        ///  for an account in the domain. This method is called
        ///  by a client to retrieve the current and previous account
        ///  passwords from a domain controller. The account name
        ///  requested MUST be the name used when the secure channel
        ///  was created, unless the method is called on a PDC by
        ///  a DC, in which case it can be any valid account name.
        ///  Opnum: 42 
        /// </summary>
        /// <param name="TrustedDcName">
        ///  The custom RPC binding handle, as specified in section
        ///  .
        /// </param>
        /// <param name="AccountName">
        ///  The null-terminated Unicode string that contains the
        ///  name of the client account in the domain for which
        ///  the trust password MUST be returned. In windows, all
        ///  machine account names are the name of the machine with
        ///  a $ (dollar sign) appended.
        /// </param>
        /// <param name="SecureChannelType">
        ///  A NETLOGON_SECURE_CHANNEL_TYPE enumerated value, as
        ///  specified in section , that indicates the type of the
        ///  secure channel being established by this call.
        /// </param>
        /// <param name="ComputerName">
        ///  The null-terminated Unicode string that contains the
        ///  NetBIOS name of the client computer.
        /// </param>
        /// <param name="Authenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, as
        ///  specified in section , that contains the client authenticator.
        /// </param>
        /// <param name="ReturnAuthenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, as
        ///  specified in section , that contains the server return
        ///  authenticator.
        /// </param>
        /// <param name="EncryptedNewOwfPassword">
        ///  A pointer to an ENCRYPTED_NT_OWF_PASSWORD structure,
        ///  as specified in section , that contains the NTOWFv1
        ///  (as specified in NTLM v1 Authentication in [MS-NLMP]
        ///  section) of the current password, encrypted as specified
        ///  in [MS-SAMR] section , Encrypting an NT Hash or LM
        ///  Hash Value with a Specified Key. The session key is
        ///  the specified 16-byte key that is used to derive the
        ///  password's keys. The specified 16-byte key uses the
        ///  16-byte value process, as specified in [MS-SAMR] section
        ///  .
        /// </param>
        /// <param name="EncryptedOldOwfPassword">
        ///  A pointer to an ENCRYPTED_NT_OWF_PASSWORD structure,
        ///  as specified in section , that contains the NTOWFv1
        ///  (as specified in NTLM v1 Authentication in [MS-NLMP]
        ///  section) of the previous password, encrypted as specified
        ///  in [MS-SAMR] section , Encrypting an NT Hash or LM
        ///  Hash Value with a Specified Key. The session key is
        ///  the specified 16-byte key that is used to derive the
        ///  password's keys. The specified 16-byte key uses the
        ///  16-byte value process, as specified in [MS-SAMR] section
        ///  .
        /// </param>
        public NtStatus NetrServerTrustPasswordsGet(
            string TrustedDcName,
            string AccountName,
            _NETLOGON_SECURE_CHANNEL_TYPE SecureChannelType,
            string ComputerName,
            _NETLOGON_AUTHENTICATOR? Authenticator,
            out _NETLOGON_AUTHENTICATOR? ReturnAuthenticator,
            out _NT_OWF_PASSWORD? EncryptedNewOwfPassword,
            out _NT_OWF_PASSWORD? EncryptedOldOwfPassword)
        {
            const ushort opnum = 42;

            byte[] requestStub;
            byte[] responseStub;
            Int3264[] paramList;
            int retVal;

            SafeIntPtr pTrustedDcName = Marshal.StringToHGlobalUni(TrustedDcName);
            SafeIntPtr pAccountName = Marshal.StringToHGlobalUni(AccountName);
            SafeIntPtr pComputerName = Marshal.StringToHGlobalUni(ComputerName);
            SafeIntPtr pAuthenticator = TypeMarshal.ToIntPtr(Authenticator);

            paramList = new Int3264[] {
                pTrustedDcName,
                pAccountName,
                (uint)SecureChannelType,
                pComputerName,
                pAuthenticator,
                IntPtr.Zero,
                IntPtr.Zero,
                IntPtr.Zero,
                0 // retVal
            };

            requestStub = RpceStubEncoder.ToBytes(
                     RpceStubHelper.GetPlatform(),
                    NrpcRpcStubFormatString.TypeFormatString,
                    new RpceStubExprEval[] { new RpceStubExprEval(logon__NETLOGON_DELTA_USERExprEval_0000) },
                    NrpcRpcStubFormatString.ProcFormatString,
                    NrpcRpcStubFormatString.ProcFormatStringOffsetTable[opnum],
                    true,
                    paramList);

            rpceClientTransport.Call(opnum, requestStub, rpceTimeout, out responseStub);

            using (RpceInt3264Collection outParamList = RpceStubDecoder.ToParamList(
                     RpceStubHelper.GetPlatform(),
                    NrpcRpcStubFormatString.TypeFormatString,
                    new RpceStubExprEval[] { new RpceStubExprEval(logon__NETLOGON_DELTA_USERExprEval_0000) },
                    NrpcRpcStubFormatString.ProcFormatString,
                    NrpcRpcStubFormatString.ProcFormatStringOffsetTable[opnum],
                    true,
                    responseStub,
                    paramList))
            {
                IntPtr pReturnAuthenticator = outParamList[5];
                ReturnAuthenticator = TypeMarshal.ToNullableStruct<_NETLOGON_AUTHENTICATOR>(pReturnAuthenticator);

                IntPtr pEncryptedNewOwfPassword = outParamList[6];
                EncryptedNewOwfPassword = TypeMarshal.ToNullableStruct<_NT_OWF_PASSWORD>(pEncryptedNewOwfPassword);

                IntPtr pEncryptedOldOwfPassword = outParamList[7];
                EncryptedOldOwfPassword = TypeMarshal.ToNullableStruct<_NT_OWF_PASSWORD>(pEncryptedOldOwfPassword);

                retVal = outParamList[8].ToInt32();
            }

            pTrustedDcName.Dispose();
            pAccountName.Dispose();
            pComputerName.Dispose();
            pAuthenticator.Dispose();

            return (NtStatus)retVal;
        }
        /// <summary>
        /// compute _NT_OWF_PASSWORD that is an ENCRYPTED_NT_OWF_PASSWORD structure, contains the NTOWFv1 (as specified
        /// in NTLM v1 
        /// Authentication in [MS-NLMP] section 3.3.1) of the current password, encrypted as specified in 
        /// [MS-SAMR] section 2.2.11.1.1, Encrypting an NT Hash or LM Hash Value with a specified key. 
        /// The session key is the specified 16-byte key that is used to derive the password's keys. The 
        /// specified 16-byte key uses the 16-byte value process, as specified in [MS-SAMR] section 2.2.11.1.4.
        /// </summary>
        /// <param name="password">password used to do the compute </param>
        /// <param name="key">The key used to do encryption, here is sessionkey</param>
        /// <returns>_NT_OWF_PASSWORD that contains encrypted NTOWFv1 of password </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when password is null.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// Thrown when key is null.
        /// </exception>
        public static _NT_OWF_PASSWORD ComputeEncryptedNtOwfv1Password(string password, byte[] key)
        {
            if (password == null)
            {
                throw new ArgumentNullException("password");
            }

            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            byte[] ntowfv1Password = NlmpUtility.NtOWF(NlmpVersion.v1, null, null, password);

            byte[] encryptOwfPassword = EncryptOwfPassword(ntowfv1Password, key);

            _NT_OWF_PASSWORD ntowfPassword = new _NT_OWF_PASSWORD();
            ntowfPassword.data = CreateCypherBlocks(encryptOwfPassword);

            return ntowfPassword;
        }
        /// <summary>
        /// Encrypt LM_OWF_PASSWORD and NT_OWF_PASSWORD by RC4 and session key.
        /// </summary>
        /// <param name="lmOwfPassword">LM_OWF_PASSWORD</param>
        /// <param name="ntOwfPassword">NT_OWF_PASSWORD</param>
        /// <exception cref="InvalidOperationException">
        /// Thrown when the method is called before establishing a NRPC secure channel.<para/>
        /// Thrown when neither AES nore RC4 is negotiated.
        /// </exception>
        private void EncryptLmAndNtOwfPassword(
            ref _LM_OWF_PASSWORD lmOwfPassword,
            ref _NT_OWF_PASSWORD ntOwfPassword)
        {
            if (lmOwfPassword.data == null || lmOwfPassword.data.Length != 2)
            {
                throw new ArgumentException("lmOwfPassword is invalid", "lmOwfPassword");
            }
            if (ntOwfPassword.data == null || ntOwfPassword.data.Length != 2)
            {
                throw new ArgumentException("ntOwfPassword is invalid", "ntOwfPassword");
            }
            ValidateSecureChannelExists();

            //For all versions of Windows except Windows NT 3.1,
            //encrypt by using RC4 and the session key.
            byte[] lmOwf = ArrayUtility.ConcatenateArrays(
                lmOwfPassword.data[0].data,
                lmOwfPassword.data[1].data);
            byte[] ntOwf = ArrayUtility.ConcatenateArrays(
                ntOwfPassword.data[0].data,
                ntOwfPassword.data[1].data);

            bool isAesNegotiated = IsAesOrRc4Negotiated();

            lmOwf = NrpcUtility.EncryptBuffer(isAesNegotiated, context.SessionKey, lmOwf);
            ntOwf = NrpcUtility.EncryptBuffer(isAesNegotiated, context.SessionKey, ntOwf);

            lmOwfPassword.data = NrpcUtility.CreateCypherBlocks(lmOwf);
            ntOwfPassword.data = NrpcUtility.CreateCypherBlocks(ntOwf);
        }
        /// <summary>
        ///  The NetrServerTrustPasswordsGet method Supported in windows_2000_server_sp4,
        ///  windows_xp, and windows_server_2003, windows_vista,
        ///  windows_server_2008, windows_7, and windows_server_7.
        ///  returns the encrypted current and previous passwords
        ///  for an account in the domain. This method is called
        ///  by a client to retrieve the current and previous account
        ///  passwords from a domain controller. The account name
        ///  requested MUST be the name used when the secure channel
        ///  was created, unless the method is called on a PDC by
        ///  a DC, in which case it can be any valid account name.
        ///  Opnum: 42 
        /// </summary>
        /// <param name="trustedDcName">
        ///  The custom RPC binding handle.
        /// </param>
        /// <param name="accountName">
        ///  The null-terminated Unicode string that contains the
        ///  name of the client account in the domain for which
        ///  the trust password MUST be returned. In windows, all
        ///  machine account names are the name of the machine with
        ///  a $ (dollar sign) appended.
        /// </param>
        /// <param name="secureChannelType">
        ///  A NETLOGON_SECURE_CHANNEL_TYPE enumerated value, 
        ///  that indicates the type of the
        ///  secure channel being established by this call.
        /// </param>
        /// <param name="computerName">
        ///  The null-terminated Unicode string that contains the
        ///  NetBIOS name of the client computer.
        /// </param>
        /// <param name="authenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, 
        ///  that contains the client authenticator.
        /// </param>
        /// <param name="returnAuthenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, 
        ///  that contains the server return
        ///  authenticator.
        /// </param>
        /// <param name="encryptedNewOwfPassword">
        ///  A pointer to an ENCRYPTED_NT_OWF_PASSWORD structure,
        ///  that contains the NTOWFv1
        ///  (as specified in NTLM v1 Authentication in [MS-NLMP])
        ///  of the current password, encrypted as specified
        ///  in [MS-SAMR], Encrypting an NT Hash or LM
        ///  Hash Value with a Specified Key. The session key is
        ///  the specified 16-byte key that is used to derive the
        ///  password's keys. The specified 16-byte key uses the
        ///  16-byte value process, as specified in [MS-SAMR].
        /// </param>
        /// <param name="encryptedOldOwfPassword">
        ///  A pointer to an ENCRYPTED_NT_OWF_PASSWORD structure,
        ///  that contains the NTOWFv1
        ///  (as specified in NTLM v1 Authentication in [MS-NLMP])
        ///  of the previous password, encrypted as specified
        ///  in [MS-SAMR], Encrypting an NT Hash or LM
        ///  Hash Value with a Specified Key. The session key is
        ///  the specified 16-byte key that is used to derive the
        ///  password's keys. The specified 16-byte key uses the
        ///  16-byte value process, as specified in [MS-SAMR].
        /// </param>
        /// <returns>
        /// The method returns 0x00000000 on success; 
        /// otherwise, it returns a nonzero error code.
        /// </returns>
        public NtStatus NetrServerTrustPasswordsGet(
            string trustedDcName,
            string accountName,
            _NETLOGON_SECURE_CHANNEL_TYPE secureChannelType,
            string computerName,
            _NETLOGON_AUTHENTICATOR? authenticator,
            out _NETLOGON_AUTHENTICATOR? returnAuthenticator,
            out _NT_OWF_PASSWORD? encryptedNewOwfPassword,
            out _NT_OWF_PASSWORD? encryptedOldOwfPassword)
        {
            NtStatus status = rpc.NetrServerTrustPasswordsGet(
                trustedDcName,
                accountName,
                secureChannelType,
                computerName,
                authenticator,
                out returnAuthenticator,
                out encryptedNewOwfPassword,
                out encryptedOldOwfPassword);

            context.ConnectionStatus = status;
            return status;
        }
        /// <summary>
        ///  The NetrServerPasswordGet method Supported in windows_2000_server,
        ///  windows_xp, windows_server_2003, windows_vista, windows_server_2008,
        ///  windows_7, and windows_server_7. allows a domain controller
        ///  to get a machine account password from the DC with
        ///  the PDC role in the domain. Opnum: 31 
        /// </summary>
        /// <param name="primaryName">
        ///  The custom RPC binding handle.
        /// </param>
        /// <param name="accountName">
        ///  A null-terminated Unicode string that contains the name
        ///  of the account to retrieve the password for. For machine
        ///  accounts, the account name is the machine name appended
        ///  with a "$" character.
        /// </param>
        /// <param name="accountType">
        ///  A NETLOGON_SECURE_CHANNEL_TYPE enumerated value, 
        ///  that describes the secure channel
        ///  to be used for authentication.
        /// </param>
        /// <param name="computerName">
        ///  A null-terminated Unicode string that contains the NetBIOS
        ///  name of the BDC making the call.
        /// </param>
        /// <param name="authenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, 
        ///  that contains the encrypted
        ///  logon credential and a time stamp.
        /// </param>
        /// <param name="returnAuthenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, 
        ///  that contains the server return
        ///  authenticator.
        /// </param>
        /// <param name="encryptedNtOwfPassword">
        ///  A pointer to an ENCRYPTED_NT_OWF_PASSWORD structure,
        ///  as specified in [MS-SAMR], that contains the
        ///  OWF password of the account.
        /// </param>
        /// <returns>
        /// The method returns 0x00000000 on success; 
        /// otherwise, it returns a nonzero error code.
        /// </returns>
        public NtStatus NetrServerPasswordGet(
            string primaryName,
            string accountName,
            _NETLOGON_SECURE_CHANNEL_TYPE accountType,
            string computerName,
            _NETLOGON_AUTHENTICATOR? authenticator,
            out _NETLOGON_AUTHENTICATOR? returnAuthenticator,
            out _NT_OWF_PASSWORD? encryptedNtOwfPassword)
        {
            NtStatus status = rpc.NetrServerPasswordGet(
                primaryName,
                accountName,
                accountType,
                computerName,
                authenticator,
                out returnAuthenticator,
                out encryptedNtOwfPassword);

            context.ConnectionStatus = status;
            return status;
        }
        /// <summary>
        /// Decrypt password after calling NetrServerPasswordGet.
        /// </summary>
        /// <param name="ntOwfPassword">
        /// The password to be decrypted, both input and output.
        /// </param>
        /// <exception cref="ArgumentException">
        /// Thrown when ntOwfPassword is invalid.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when the method is called before establishing a NRPC secure channel.
        /// </exception>
        public void DecryptNtOwfPassword(ref _NT_OWF_PASSWORD ntOwfPassword)
        {
            if (ntOwfPassword.data == null
                || ntOwfPassword.data.Length != 2)
            {
                throw new ArgumentException("Invalid NT_OWF_PASSWORD", "ntOwfPassword");
            }
            ValidateSecureChannelExists();

            //The client MUST decrypt the EncryptedNtOwfPassword
            //return parameter using DES in ECB mode [FIPS81]
            //and the session key established as the decryption key.

            //TDI 49785, DES key is 8 bytes, but session key is 16 bytes.
            using (DES des = DES.Create())
            {
                des.Mode = CipherMode.ECB;
                des.Padding = PaddingMode.None;
                des.Key = ArrayUtility.SubArray(
                    context.SessionKey,
                    0,
                    NrpcUtility.NL_CREDENTIAL_LENGTH);

                ntOwfPassword.data[0].data = des.CreateDecryptor().TransformFinalBlock(
                    ntOwfPassword.data[0].data,
                    0,
                    ntOwfPassword.data[0].data.Length);
            }

            using (DES des = DES.Create())
            {
                des.Mode = CipherMode.ECB;
                des.Padding = PaddingMode.None;
                des.Key = ArrayUtility.SubArray(
                    context.SessionKey,
                    NrpcUtility.NL_CREDENTIAL_LENGTH,
                    NrpcUtility.NL_CREDENTIAL_LENGTH);

                ntOwfPassword.data[1].data = des.CreateDecryptor().TransformFinalBlock(
                    ntOwfPassword.data[1].data,
                    0,
                    ntOwfPassword.data[1].data.Length);
            }
        }