/// <summary>
        /// Verify the signature of a Smb2SinglePacket
        /// </summary>
        /// <param name="packet">The packet to be verified</param>
        /// <param name="cryptoInfo">The cryptoInfo of smb2client</param>
        /// <returns>True when signature verification succeeds and false when fails</returns>
        private bool VerifySignature(Smb2SinglePacket packet, Smb2CryptoInfo cryptoInfo)
        {
            if (cryptoInfo.DisableVerifySignature)
            {
                // Skip the verification.
                return(true);
            }

            try
            {
                if (IsErrorPacket(packet.Header))
                {
                    packet = packet.Error;
                }
                //save the 16-byte signature from the Signature field in the SMB2 Header
                byte[] originalSignature = packet.Header.Signature;

                //zero out the 16-byte signature field in the SMB2 Header of the incoming message.
                packet.Header.Signature = new byte[Smb2Consts.SignatureSize];
                byte[] bytesToCompute = packet.ToBytes();

                //Compute the message with signing key
                byte[] computedSignature = new byte[] { };
                if (Smb2Utility.IsSmb3xFamily(cryptoInfo.Dialect))
                {
                    //[MS-SMB2] 3.1.5.1
                    //If Session.Connection.Dialect belongs to the SMB 3.x dialect family,
                    //the receiver MUST compute a 16-byte hash by using AES-128-CMAC over the entire message,
                    //beginning with the SMB2 Header from step 2, and using the key provided.
                    //The AES-128-CMAC is specified in [RFC4493].

                    //TD has mentioned to use Session.SigningKey for SESSION_SETUP Response and Channel.SigningKey for other responses
                    //In the current SDK, the SigningKey is the Channel.SigningKey
                    computedSignature = AesCmac128.ComputeHash(cryptoInfo.SigningKey, bytesToCompute);
                }
                else
                {
                    //[MS-SMB2] 3.1.5.1
                    //If Session.Connection.Dialect is "2.002" or "2.100", the receiver MUST compute a 32-byte hash by using HMAC-SHA256 over the entire message,
                    //beginning with the SMB2 Header from step 2, and using the key provided.
                    //The HMAC-SHA256 hash is specified in [FIPS180-2] and [RFC2104].

                    HMACSHA256 hmacSha = new HMACSHA256(cryptoInfo.SigningKey);
                    computedSignature = hmacSha.ComputeHash(bytesToCompute);
                }
                packet.Header.Signature = originalSignature;

                //[MS-SMB2] 3.1.5.1
                //If the first 16 bytes (the high-order portion) of the computed signature from step 3 or step 4 matches the saved signature from step 1, the message is signed correctly
                // compare the first 16 bytes of the originalSignature and computedSignature
                return(originalSignature.SequenceEqual(computedSignature.Take(16)));
            }
            catch (Exception ex)
            {
                throw new Exception("Error happened during signature verification of packet: " + packet.ToString() + ". Exception message: " + ex.Message);
            }
        }
        /// <summary>
        /// Update the context from a SessioinSetup request and response messages.
        /// The caller should ensure the messages are input in the right order.
        /// </summary>
        /// <param name="packet">The packet used to update this context. It must be the one of the following types:
        /// Smb2SessionSetupRequestPacket, Smb2SessionSetupResponsePacket</param>
        public void UpdateSessionState(ulong sessionId, Smb2SinglePacket packet)
        {
            //Check the packet type
            if (!(packet is Smb2SessionSetupRequestPacket) &&
                !(packet is Smb2SessionSetupResponsePacket))
            {
                throw new InvalidCastException("packet must be one of the types: Smb2SessionSetupRequestPacket, Smb2SessionSetupResponsePacket.");
            }

            if (completedSessionSet.Contains(sessionId))
            {
                return; // Don't update session hash value for reauthetication
            }

            //Refer to [MS-SMB2] 3.2.5.3	Receiving an SMB2 SESSION_SETUP Response
            if (packet is Smb2SessionSetupRequestPacket)
            {
                if (!sessionPreauthIntegrityHashValueTable.ContainsKey(sessionId))
                {
                    sessionPreauthIntegrityHashValueTable.Add(sessionId, connectionPreauthIntegrityHashValue);
                }
                byte[] messageBytes = packet.ToBytes();
                byte[] hashData     = sessionPreauthIntegrityHashValueTable[sessionId].Concat(messageBytes).ToArray();
                sessionPreauthIntegrityHashValueTable[sessionId] = CreateHashAlgorithm().ComputeHash(hashData);
            }
            else if (packet is Smb2SessionSetupResponsePacket)
            {
                if (packet.Header.Status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED)
                {
                    byte[] messageBytes = packet.ToBytes();
                    byte[] hashData     = sessionPreauthIntegrityHashValueTable[sessionId].Concat(messageBytes).ToArray();
                    sessionPreauthIntegrityHashValueTable[sessionId] = CreateHashAlgorithm().ComputeHash(hashData);
                }
                else if (packet.Header.Status == Smb2Status.STATUS_SUCCESS)
                {
                    completedSessionSet.Add(sessionId);
                }
            }
        }
        /// <summary>
        /// Update the context from a Negotiate Request or Response messages.
        /// The caller should ensure the messages are input in the right order.
        /// </summary>
        /// <param name="packet">The packet used to update this context. It must be the one of the following types:
        /// Smb2NegotiateRequestPacket, Smb2NegotiateResponsePacket</param>
        public void UpdateConnectionState(Smb2SinglePacket packet)
        {
            //Check the packet type
            if (!(packet is Smb2NegotiateRequestPacket) &&
                !(packet is Smb2NegotiateResponsePacket))
            {
                throw new InvalidCastException("packet must be one of the types: Smb2NegotiateRequestPacket, Smb2NegotiateResponsePacket.");
            }

            //Refer to [MS-SMB2] 3.2.5.2	Receiving an SMB2 NEGOTIATE Response
            if (packet is Smb2NegotiateRequestPacket)
            {
                connectionPreauthIntegrityHashValue = ZeroHashValue;
                byte[] messageBytes = packet.ToBytes();
                byte[] hashData     = connectionPreauthIntegrityHashValue.Concat(messageBytes).ToArray();
                connectionPreauthIntegrityHashValue = CreateHashAlgorithm().ComputeHash(hashData);
            }
            else if (packet is Smb2NegotiateResponsePacket)
            {
                byte[] messageBytes = packet.ToBytes();
                byte[] hashData     = connectionPreauthIntegrityHashValue.Concat(messageBytes).ToArray();
                connectionPreauthIntegrityHashValue = CreateHashAlgorithm().ComputeHash(hashData);
            }
        }
        /// <summary>
        /// Update the context from a SessioinSetup request and response messages.
        /// The caller should ensure the messages are input in the right order.
        /// </summary>
        /// <param name="packet">The packet used to update this context. It must be the one of the following types:
        /// Smb2SessionSetupRequestPacket, Smb2SessionSetupResponsePacket</param>
        public void UpdateSessionState(ulong sessionId, Smb2SinglePacket packet)
        {
            //Check the packet type
            if (!(packet is Smb2SessionSetupRequestPacket) &&
                !(packet is Smb2SessionSetupResponsePacket))
            {
                throw new InvalidCastException("packet must be one of the types: Smb2SessionSetupRequestPacket, Smb2SessionSetupResponsePacket.");
            }

            if (completedSessionSet.Contains(sessionId))
            {
                return; // Don't update session hash value for reauthetication
            }

            //Refer to [MS-SMB2] 3.2.5.3	Receiving an SMB2 SESSION_SETUP Response
            if (packet is Smb2SessionSetupRequestPacket)
            {
                if (!sessionPreauthIntegrityHashValueTable.ContainsKey(sessionId))
                {
                    sessionPreauthIntegrityHashValueTable.Add(sessionId, connectionPreauthIntegrityHashValue);
                }
                byte[] messageBytes = packet.ToBytes();
                byte[] hashData = sessionPreauthIntegrityHashValueTable[sessionId].Concat(messageBytes).ToArray();
                sessionPreauthIntegrityHashValueTable[sessionId] = CreateHashAlgorithm().ComputeHash(hashData);
            }
            else if (packet is Smb2SessionSetupResponsePacket)
            {
                if (packet.Header.Status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED)
                {
                    byte[] messageBytes = packet.ToBytes();
                    byte[] hashData = sessionPreauthIntegrityHashValueTable[sessionId].Concat(messageBytes).ToArray();
                    sessionPreauthIntegrityHashValueTable[sessionId] = CreateHashAlgorithm().ComputeHash(hashData);
                }
                else if (packet.Header.Status == Smb2Status.STATUS_SUCCESS)
                {
                    completedSessionSet.Add(sessionId);
                }
            }
        }
        /// <summary>
        /// Update the context from a Negotiate Request or Response messages.
        /// The caller should ensure the messages are input in the right order.
        /// </summary>
        /// <param name="packet">The packet used to update this context. It must be the one of the following types:
        /// Smb2NegotiateRequestPacket, Smb2NegotiateResponsePacket</param>
        public void UpdateConnectionState(Smb2SinglePacket packet)
        {
            //Check the packet type
            if (!(packet is Smb2NegotiateRequestPacket) &&
                !(packet is Smb2NegotiateResponsePacket))
            {
                throw new InvalidCastException("packet must be one of the types: Smb2NegotiateRequestPacket, Smb2NegotiateResponsePacket.");
            }

            //Refer to [MS-SMB2] 3.2.5.2	Receiving an SMB2 NEGOTIATE Response
            if (packet is Smb2NegotiateRequestPacket)
            {
                connectionPreauthIntegrityHashValue = ZeroHashValue;
                byte[] messageBytes = packet.ToBytes();
                byte[] hashData = connectionPreauthIntegrityHashValue.Concat(messageBytes).ToArray();
                connectionPreauthIntegrityHashValue = CreateHashAlgorithm().ComputeHash(hashData);
            }
            else if (packet is Smb2NegotiateResponsePacket)
            {
                byte[] messageBytes = packet.ToBytes();
                byte[] hashData = connectionPreauthIntegrityHashValue.Concat(messageBytes).ToArray();
                connectionPreauthIntegrityHashValue = CreateHashAlgorithm().ComputeHash(hashData);
            }
        }
        /// <summary>
        /// Verify the signature of a Smb2SinglePacket
        /// </summary>
        /// <param name="packet">The packet to be verified</param>
        /// <param name="cryptoInfo">The cryptoInfo of smb2client</param>        
        /// <returns>True when signature verification succeeds and false when fails</returns>
        private bool VerifySignature(Smb2SinglePacket packet, Smb2CryptoInfo cryptoInfo)
        {
            if (cryptoInfo.DisableVerifySignature)
            {
                // Skip the verification.
                return true;
            }

            try
            {
                if (IsErrorPacket(packet.Header))
                {
                    packet = packet.Error;
                }
                //save the 16-byte signature from the Signature field in the SMB2 Header
                byte[] originalSignature = packet.Header.Signature;

                //zero out the 16-byte signature field in the SMB2 Header of the incoming message.
                packet.Header.Signature = new byte[Smb2Consts.SignatureSize];
                byte[] bytesToCompute = packet.ToBytes();

                //Compute the message with signing key
                byte[] computedSignature = new byte[] { };
                if (Smb2Utility.IsSmb3xFamily(cryptoInfo.Dialect))
                {
                    //[MS-SMB2] 3.1.5.1
                    //If Session.Connection.Dialect belongs to the SMB 3.x dialect family,
                    //the receiver MUST compute a 16-byte hash by using AES-128-CMAC over the entire message,
                    //beginning with the SMB2 Header from step 2, and using the key provided.
                    //The AES-128-CMAC is specified in [RFC4493].

                    //TD has mentioned to use Session.SigningKey for SESSION_SETUP Response and Channel.SigningKey for other responses
                    //In the current SDK, the SigningKey is the Channel.SigningKey
                    computedSignature = AesCmac128.ComputeHash(cryptoInfo.SigningKey, bytesToCompute);
                }
                else
                {
                    //[MS-SMB2] 3.1.5.1
                    //If Session.Connection.Dialect is "2.002" or "2.100", the receiver MUST compute a 32-byte hash by using HMAC-SHA256 over the entire message,
                    //beginning with the SMB2 Header from step 2, and using the key provided.
                    //The HMAC-SHA256 hash is specified in [FIPS180-2] and [RFC2104].

                    HMACSHA256 hmacSha = new HMACSHA256(cryptoInfo.SigningKey);
                    computedSignature = hmacSha.ComputeHash(bytesToCompute);
                }
                packet.Header.Signature = originalSignature;

                //[MS-SMB2] 3.1.5.1
                //If the first 16 bytes (the high-order portion) of the computed signature from step 3 or step 4 matches the saved signature from step 1, the message is signed correctly
                // compare the first 16 bytes of the originalSignature and computedSignature
                return originalSignature.SequenceEqual(computedSignature.Take(16));
            }
            catch (Exception ex)
            {
                throw new Exception("Error happened during signature verification of packet: " + packet.ToString() + ". Exception message: " + ex.Message);
            }
        }