/// <summary>
        /// Create a Gss_Wrap [RFC4121] token.
        /// </summary>
        /// <param name="isEncrypted">If encrypt the message.</param>
        /// <param name="message">The message to be wrapped. This argument can be null.</param>
        /// <param name="isInitiator">If the sender is initiator.</param>
        /// <returns>The created Gss_Wrap token.</returns>
        private Token4121 GssWrap4121(bool isEncrypted, byte[] message, bool isInitiator)
        {
            var token       = new Token4121(Context);
            var tokenHeader = new TokenHeader4121();

            tokenHeader.tok_id = TOK_ID.Wrap4121;
            tokenHeader.flags  = isEncrypted ? WrapFlag.Sealed : WrapFlag.None;
            if (!isInitiator)
            {
                tokenHeader.flags |= WrapFlag.SentByAcceptor;
            }

            if (Context.AcceptorSubKey != null)
            {
                tokenHeader.flags |= WrapFlag.AcceptorSubkey;
            }

            tokenHeader.filler = KerberosConstValue.TOKEN_FILLER_1_BYTE;
            tokenHeader.ec     = 16;
            // [MS-KILE] The RRC field ([RFC4121] section 4.2.5) is 12 if no encryption is requested or 28 if encryption is requested.
            tokenHeader.rrc     = isEncrypted ? (ushort)28 : (ushort)12;
            tokenHeader.snd_seq = Context.CurrentLocalSequenceNumber;

            token.TokenHeader = tokenHeader;
            token.Data        = message;

            return(token);
        }
        /// <summary>
        /// Create a Gss_GetMic [RFC4121] token.
        /// </summary>
        /// <param name="message">The message to be wrapped. This argument can be null.</param>
        /// <param name="isInitiator">If the sender is initiator.</param>
        /// <returns>The created Gss_GetMic token.</returns>
        private Token4121 GssGetMic4121(byte[] message, bool isInitiator)
        {
            var token       = new Token4121(Context);
            var tokenHeader = new TokenHeader4121();

            tokenHeader.tok_id = TOK_ID.Mic4121;
            tokenHeader.flags  = WrapFlag.None;
            if (!isInitiator)
            {
                tokenHeader.flags |= WrapFlag.SentByAcceptor;
            }

            if (Context.AcceptorSubKey != null)
            {
                tokenHeader.flags |= WrapFlag.AcceptorSubkey;
            }

            tokenHeader.filler  = KerberosConstValue.TOKEN_FILLER_1_BYTE;
            tokenHeader.ec      = KerberosConstValue.TOKEN_FILLER_2_BYTE;
            tokenHeader.rrc     = KerberosConstValue.TOKEN_FILLER_2_BYTE;
            tokenHeader.snd_seq = Context.CurrentLocalSequenceNumber;

            token.TokenHeader = tokenHeader;
            token.Data        = message;

            return(token);
        }
        /// <summary>
        /// Decode a Gss_Wrap token from security buffers
        /// </summary>
        /// <param name="context">The context of decoding</param>
        /// <param name="securityBuffers">Security buffers</param>
        /// <returns>The decoded Gss_Wrap token.</returns>
        internal static KerberosPdu GssUnWrapEx(KerberosContext context, SecurityBuffer[] securityBuffers)
        {
            KerberosPdu   pdu = null;
            EncryptionKey key = context.ContextKey;

            switch ((EncryptionType)key.keytype.Value)
            {
            case EncryptionType.AES128_CTS_HMAC_SHA1_96:
            case EncryptionType.AES256_CTS_HMAC_SHA1_96:
                var token4121Pdu = new Token4121(context);
                token4121Pdu.FromSecurityBuffers(securityBuffers);
                pdu = token4121Pdu;
                break;

            case EncryptionType.DES_CBC_CRC:
            case EncryptionType.DES_CBC_MD5:
            case EncryptionType.RC4_HMAC:
            case EncryptionType.RC4_HMAC_EXP:
                var token1964or4757Pdu = new Token1964_4757(context);
                token1964or4757Pdu.FromSecurityBuffers(securityBuffers);
                pdu = token1964or4757Pdu;
                break;

            default:
                throw new NotSupportedException("The Encryption Type can only be AES128_CTS_HMAC_SHA1_96, "
                                                + "AES256_CTS_HMAC_SHA1_96, DES_CBC_CRC, DES_CBC_MD5, RC4_HMAC or RC4_HMAC_EXP.");
            }

            return(pdu);
        }
        internal static bool GssVerifyMicEx(KerberosContext context, SecurityBuffer[] securityBuffers, out KerberosPdu pdu)
        {
            pdu = null;
            bool          isVerified = true;
            EncryptionKey key        = context.ContextKey;

            switch ((EncryptionType)key.keytype.Value)
            {
            case EncryptionType.AES128_CTS_HMAC_SHA1_96:
            case EncryptionType.AES256_CTS_HMAC_SHA1_96:
                var micPdu4121 = new Token4121(context);
                try
                {
                    micPdu4121.FromSecurityBuffers(securityBuffers);
                }
                catch (FormatException)
                {
                    isVerified = false;
                }
                pdu = micPdu4121;
                break;

            case EncryptionType.DES_CBC_CRC:
            case EncryptionType.DES_CBC_MD5:
            case EncryptionType.RC4_HMAC:
            case EncryptionType.RC4_HMAC_EXP:
                var micPdu1964_4757 = new Token1964_4757(context);
                try
                {
                    micPdu1964_4757.FromSecurityBuffers(securityBuffers);
                }
                catch (FormatException)
                {
                    isVerified = false;
                }
                pdu = micPdu1964_4757;
                break;

            default:
                throw new NotSupportedException("The Encryption Type can only be AES128_CTS_HMAC_SHA1_96, "
                                                + "AES256_CTS_HMAC_SHA1_96, DES_CBC_CRC, DES_CBC_MD5, RC4_HMAC or RC4_HMAC_EXP.");
            }

            return(isVerified);
        }
        /// <summary>
        /// Decrypt a request or response
        /// </summary>
        /// <param name="token">A token containing encrypted data.</param>
        /// <param name="sentFromClient">True if the token is a request, false is a response</param>
        /// <returns>Plain-text data.</returns>
        private byte[] Decrypt(byte[] token, bool sentFromClient)
        {
            KileContext context = sentFromClient ? (KileContext)kileDecoder.serverContext : (KileContext)kileDecoder.clientContext;
            KilePdu     pdu     = KileRole.GssUnWrap(context, token);

            Token4121 token4121Pdu = pdu as Token4121;

            if (token4121Pdu != null)
            {
                return(token4121Pdu.Data);
            }

            Token1964_4757 token1964or4757Pdu = pdu as Token1964_4757;

            if (token1964or4757Pdu != null)
            {
                return(token1964or4757Pdu.Data);
            }

            throw new InvalidOperationException("Token type is not supported.");
        }