/// <summary>
        /// Create a Kpassword Request
        /// </summary>
        /// <param name="newPwd">The new password to change</param>
        /// <returns></returns>
        public KpasswordRequest CreateKpasswordRequest(string newPwd)
        {
            //Generate the subkey, which will be used to encrypt/decrypt KRB-PRIV message
            EncryptionKey subkey = KerberosUtility.MakeKey((EncryptionType)this.Context.Ticket.SessionKey.keytype.Value, "Password01!", "This is a salt");
            Context.Subkey = subkey;

            Authenticator authenticator = CreateAuthenticator(this.Context.Ticket, null, subkey);
            KpasswordRequest request = new KpasswordRequest(this.Context.Ticket, authenticator, newPwd);
            return request;
        }
        //Get the expected Kerberos PDU from byte array
        private KerberosPdu getExpectedPduFromBytes(
            byte[] receivedBytes,
            out int consumedLength,
            out int expectedLength)
        {
            // initialize lengths
            consumedLength = 0;
            expectedLength = 0;

            if (null == receivedBytes || 0 == receivedBytes.Length)
            {
                return(null);
            }

            // TCP has a 4 bytes length header, while UDP has not
            byte[] pduBytes = receivedBytes;

            if ((this.Context.TransportType == TransportType.TCP))
            {
                // insufficient data, needs to receive more
                if (receivedBytes.Length < sizeof(int))
                {
                    return(null);
                }

                // get pdu data length
                byte[] lengthBytes = ArrayUtility.SubArray(receivedBytes, 0, sizeof(int));
                Array.Reverse(lengthBytes);
                int pduLength = BitConverter.ToInt32(lengthBytes, 0);

                // insufficient data, needs to receive more
                expectedLength = sizeof(int) + pduLength;
                if (receivedBytes.Length < expectedLength)
                {
                    return(null);
                }

                // remove length header from pdu bytes
                pduBytes = ArrayUtility.SubArray <byte>(receivedBytes, sizeof(int), pduLength);
            }
            else
            {
                // UDP has no length header
                expectedLength = pduBytes.Length;
            }

            consumedLength = expectedLength;
            KerberosPdu pdu = null;

            //Get AP data in message to judge the kpassword type
            byte[] apLengthBytes = ArrayUtility.SubArray <byte>(pduBytes, 2 * sizeof(ushort), sizeof(ushort));
            Array.Reverse(apLengthBytes);
            ushort apLength = BitConverter.ToUInt16(apLengthBytes, 0);

            //If the length is zero, then the last field contains a KRB-ERROR message instead of a KRB-PRIV message.
            if (apLength == 0)
            {
                pdu = new KerberosKrbError();
                pdu.FromBytes(ArrayUtility.SubArray <byte>(pduBytes, 3 * sizeof(ushort)));
                return(pdu);
            }

            // get message type
            // (the lower 5 bits indicates its message type)
            byte[]  apBytes      = ArrayUtility.SubArray <byte>(pduBytes, 3 * sizeof(ushort), apLength);
            MsgType kpassMsgType = (MsgType)(apBytes[0] & 0x1f);

            if (kpassMsgType == MsgType.KRB_AP_REQ)
            {
                pdu = new KpasswordRequest();
            }
            else
            {
                pdu = new KpasswordResponse();
                pdu.FromBytes(pduBytes);
            }

            return(pdu);
        }
        //Get the expected Kerberos PDU from byte array
        private KerberosPdu getExpectedPduFromBytes(
            byte[] receivedBytes,
            out int consumedLength,
            out int expectedLength)
        {
            // initialize lengths
            consumedLength = 0;
            expectedLength = 0;

            if (null == receivedBytes || 0 == receivedBytes.Length)
            {
                return null;
            }

            // TCP has a 4 bytes length header, while UDP has not
            byte[] pduBytes = receivedBytes;

            if ((this.Context.TransportType == TransportType.TCP))
            {
                // insufficient data, needs to receive more
                if (receivedBytes.Length < sizeof(int))
                {
                    return null;
                }

                // get pdu data length
                byte[] lengthBytes = ArrayUtility.SubArray(receivedBytes, 0, sizeof(int));
                Array.Reverse(lengthBytes);
                int pduLength = BitConverter.ToInt32(lengthBytes, 0);

                // insufficient data, needs to receive more
                expectedLength = sizeof(int) + pduLength;
                if (receivedBytes.Length < expectedLength)
                {
                    return null;
                }

                // remove length header from pdu bytes
                pduBytes = ArrayUtility.SubArray<byte>(receivedBytes, sizeof(int), pduLength);
            }
            else
            {
                // UDP has no length header
                expectedLength = pduBytes.Length;
            }

            consumedLength = expectedLength;
            KerberosPdu pdu = null;

            //Get AP data in message to judge the kpassword type
            byte[] apLengthBytes = ArrayUtility.SubArray<byte>(pduBytes, 2 * sizeof(ushort), sizeof(ushort));
            Array.Reverse(apLengthBytes);
            ushort apLength = BitConverter.ToUInt16(apLengthBytes, 0);

            //If the length is zero, then the last field contains a KRB-ERROR message instead of a KRB-PRIV message.
            if (apLength == 0)
            {
                pdu = new KerberosKrbError();
                pdu.FromBytes(ArrayUtility.SubArray<byte>(pduBytes, 3 * sizeof(ushort)));
                return pdu;
            }

            // get message type
            // (the lower 5 bits indicates its message type)
            byte[] apBytes = ArrayUtility.SubArray<byte>(pduBytes, 3 * sizeof(ushort), apLength);
            MsgType kpassMsgType = (MsgType)(apBytes[0] & 0x1f);
            if (kpassMsgType == MsgType.KRB_AP_REQ)
            {
                pdu = new KpasswordRequest();
            }
            else
            {
                pdu = new KpasswordResponse();
                pdu.FromBytes(pduBytes);
            }

            return pdu;
        }