/// <summary>
        /// Sign and encrypt for Single or Compound packet.
        /// </summary>
        public static byte[] SignAndEncrypt(Smb2Packet originalPacket, Dictionary<ulong, Smb2CryptoInfo> cryptoInfoTable, Smb2Role role)
        {
            ulong sessionId;
            bool isCompound = false;

            if (originalPacket is Smb2SinglePacket)
            {
                sessionId = (originalPacket as Smb2SinglePacket).Header.SessionId;
            }
            else if (originalPacket is Smb2CompoundPacket)
            {
                isCompound = true;
                // The subsequent request in compound packet should use the SessionId of the first request for encryption
                sessionId = (originalPacket as Smb2CompoundPacket).Packets[0].Header.SessionId;
            }
            else
            {
                throw new NotImplementedException(string.Format("Signing and encryption are not implemented for packet: {0}", originalPacket.ToString()));
            }

            // Signing and encryption not required if session id is not available yet
            if (sessionId == 0 || !cryptoInfoTable.ContainsKey(sessionId))
                return originalPacket.ToBytes();

            Smb2CryptoInfo cryptoInfo = cryptoInfoTable[sessionId];

            #region Encrypt
            // Try to encrypt the message whenever the encryption is supported or not.
            // If it's not supported, do it for negative test.
            // For compound packet, the encryption is done for the entire message.
            byte[] encryptedBinary = Encrypt(sessionId, cryptoInfo, role, originalPacket);
            if (encryptedBinary != null)
                return encryptedBinary;
            #endregion

            #region Sign
            if (cryptoInfo.EnableSessionSigning)
            {
                if (isCompound)
                {
                    // Calculate signature for every packet in the chain
                    foreach (Smb2SinglePacket packet in (originalPacket as Smb2CompoundPacket).Packets)
                    {
                        // If the packet is the first one in the chain or the unralated one, use its own SessionId for sign and encrypt
                        // If it's not the first one and it's the related one, use the SessionId of the first request for sign and encrypt
                        if (!packet.Header.Flags.HasFlag(Packet_Header_Flags_Values.FLAGS_RELATED_OPERATIONS))
                        {
                            sessionId = packet.Header.SessionId;
                            cryptoInfo = cryptoInfoTable[sessionId];
                        }

                        packet.Header.Signature = Sign(cryptoInfo, packet.ToBytes());
                    }
                }
                else
                {
                    (originalPacket as Smb2SinglePacket).Header.Signature = Sign(cryptoInfo, originalPacket.ToBytes());
                }
            }
            #endregion

            return originalPacket.ToBytes();
        }
        /// <summary>
        /// Sign, compress and encrypt for Single or Compound packet.
        /// </summary>
        public static Smb2Packet SignCompressAndEncrypt(Smb2Packet originalPacket, Dictionary <ulong, Smb2CryptoInfo> cryptoInfoTable, Smb2CompressionInfo compressioninfo, Smb2Role role)
        {
            ulong sessionId;
            bool  isCompound        = false;
            bool  notEncryptNotSign = false;
            bool  notEncrypt        = false;
            var   compressedPacket  = originalPacket;

            if (originalPacket is Smb2SinglePacket)
            {
                Smb2SinglePacket singlePacket = originalPacket as Smb2SinglePacket;
                sessionId = singlePacket.Header.SessionId;
                // [MS-SMB2] Section 3.2.4.1.8, the request being sent is SMB2 NEGOTIATE,
                // or the request being sent is SMB2 SESSION_SETUP with the SMB2_SESSION_FLAG_BINDING bit set in the Flags field,
                // the client MUST NOT encrypt the message
                if (sessionId == 0 ||
                    (singlePacket.Header.Command == Smb2Command.NEGOTIATE && (singlePacket is Smb2NegotiateRequestPacket)))
                {
                    notEncryptNotSign = true;
                }
                else if ((singlePacket.Header.Command == Smb2Command.SESSION_SETUP && (singlePacket is Smb2SessionSetupRequestPacket) &&
                          (singlePacket as Smb2SessionSetupRequestPacket).PayLoad.Flags == SESSION_SETUP_Request_Flags.SESSION_FLAG_BINDING))
                {
                    notEncrypt = true;
                }
            }
            else if (originalPacket is Smb2CompoundPacket)
            {
                isCompound = true;
                // The subsequent request in compound packet should use the SessionId of the first request for encryption
                sessionId = (originalPacket as Smb2CompoundPacket).Packets[0].Header.SessionId;
            }
            else
            {
                throw new NotImplementedException(string.Format("Signing and encryption are not implemented for packet: {0}", originalPacket.ToString()));
            }

            if (sessionId == 0 || notEncryptNotSign || !cryptoInfoTable.ContainsKey(sessionId))
            {
                if (originalPacket is Smb2CompressiblePacket)
                {
                    compressedPacket = Smb2Compression.Compress(originalPacket as Smb2CompressiblePacket, compressioninfo, role);
                }
                return(compressedPacket);
            }

            Smb2CryptoInfo cryptoInfo = cryptoInfoTable[sessionId];

            #region Encrypt
            // Try to encrypt the message whenever the encryption is supported or not except for sesstion setup.
            // If it's not supported, do it for negative test.
            // For compound packet, the encryption is done for the entire message.
            if (!notEncrypt)
            {
                if (originalPacket is Smb2CompressiblePacket)
                {
                    compressedPacket = Smb2Compression.Compress(originalPacket as Smb2CompressiblePacket, compressioninfo, role);
                }
                var encryptedPacket = Encrypt(sessionId, cryptoInfo, role, compressedPacket, originalPacket);
                if (encryptedPacket != null)
                {
                    return(encryptedPacket);
                }
            }
            #endregion

            #region Sign
            if (cryptoInfo.EnableSessionSigning)
            {
                if (isCompound)
                {
                    // Calculate signature for every packet in the chain
                    foreach (Smb2SinglePacket packet in (originalPacket as Smb2CompoundPacket).Packets)
                    {
                        // If the packet is the first one in the chain or the unralated one, use its own SessionId for sign and encrypt
                        // If it's not the first one and it's the related one, use the SessionId of the first request for sign and encrypt
                        if (!packet.Header.Flags.HasFlag(Packet_Header_Flags_Values.FLAGS_RELATED_OPERATIONS))
                        {
                            sessionId  = packet.Header.SessionId;
                            cryptoInfo = cryptoInfoTable[sessionId];
                        }

                        packet.Header.Signature = Sign(cryptoInfo, packet.ToBytes());
                    }
                }
                else
                {
                    (originalPacket as Smb2SinglePacket).Header.Signature = Sign(cryptoInfo, originalPacket.ToBytes());
                }
            }
            #endregion
            if (originalPacket is Smb2CompressiblePacket)
            {
                compressedPacket = Smb2Compression.Compress(originalPacket as Smb2CompressiblePacket, compressioninfo, role);
            }
            return(compressedPacket);
        }
        /// <summary>
        /// Sign and encrypt for Single or Compound packet.
        /// </summary>
        public static byte[] SignAndEncrypt(Smb2Packet originalPacket, Dictionary <ulong, Smb2CryptoInfo> cryptoInfoTable, Smb2Role role)
        {
            ulong sessionId;
            bool  isCompound = false;

            if (originalPacket is Smb2SinglePacket)
            {
                sessionId = (originalPacket as Smb2SinglePacket).Header.SessionId;
            }
            else if (originalPacket is Smb2CompoundPacket)
            {
                isCompound = true;
                // The subsequent request in compound packet should use the SessionId of the first request for encryption
                sessionId = (originalPacket as Smb2CompoundPacket).Packets[0].Header.SessionId;
            }
            else
            {
                throw new NotImplementedException(string.Format("Signing and encryption are not implemented for packet: {0}", originalPacket.ToString()));
            }

            // Signing and encryption not required if session id is not available yet
            if (sessionId == 0 || !cryptoInfoTable.ContainsKey(sessionId))
            {
                return(originalPacket.ToBytes());
            }

            Smb2CryptoInfo cryptoInfo = cryptoInfoTable[sessionId];

            #region Encrypt
            // Try to encrypt the message whenever the encryption is supported or not.
            // If it's not supported, do it for negative test.
            // For compound packet, the encryption is done for the entire message.
            byte[] encryptedBinary = Encrypt(sessionId, cryptoInfo, role, originalPacket);
            if (encryptedBinary != null)
            {
                return(encryptedBinary);
            }
            #endregion

            #region Sign
            if (cryptoInfo.EnableSessionSigning)
            {
                if (isCompound)
                {
                    // Calculate signature for every packet in the chain
                    foreach (Smb2SinglePacket packet in (originalPacket as Smb2CompoundPacket).Packets)
                    {
                        // If the packet is the first one in the chain or the unralated one, use its own SessionId for sign and encrypt
                        // If it's not the first one and it's the related one, use the SessionId of the first request for sign and encrypt
                        if (!packet.Header.Flags.HasFlag(Packet_Header_Flags_Values.FLAGS_RELATED_OPERATIONS))
                        {
                            sessionId  = packet.Header.SessionId;
                            cryptoInfo = cryptoInfoTable[sessionId];
                        }

                        packet.Header.Signature = Sign(cryptoInfo, packet.ToBytes());
                    }
                }
                else
                {
                    (originalPacket as Smb2SinglePacket).Header.Signature = Sign(cryptoInfo, originalPacket.ToBytes());
                }
            }
            #endregion

            return(originalPacket.ToBytes());
        }