Example #1
0
 public TransferBuffer(TransferBuffer rhs)
 {
     lock (rhs.m_lock)
     {
         m_buffer = new byte[rhs.m_buffer.Length];
         System.Buffer.BlockCopy(rhs.m_buffer, 0, m_buffer, 0, m_buffer.Length);
         m_offset = rhs.m_offset;
         m_size = rhs.m_size;
         m_lock = new object();
     }
 }
Example #2
0
        private KeyValuePair<TransferBuffer, Packet> GetPacketToSend()
        {
            if (m_outgoing_packets.Count == 0)
            {
                throw (new Exception("[SecurityAPI::GetPacketToSend] No packets are avaliable to send."));
            }

            Packet packet = m_outgoing_packets[0];
            m_outgoing_packets.RemoveAt(0);

            if (packet.Massive)
            {
                ushort parts = 0;

                PacketWriter final = new PacketWriter();
                PacketWriter final_data = new PacketWriter();

                byte[] input_data = packet.GetBytes();
                PacketReader input_reader = new PacketReader(input_data);

                TransferBuffer workspace = new TransferBuffer(4089, 0, (int)input_data.Length);

                while (workspace.Size > 0)
                {
                    PacketWriter part_data = new PacketWriter();

                    int cur_size = workspace.Size > 4089 ? 4089 : workspace.Size; // Max buffer size is 4kb for the client

                    part_data.Write((byte)0); // Data flag

                    part_data.Write(input_data, workspace.Offset, cur_size);

                    workspace.Offset += cur_size;
                    workspace.Size -= cur_size; // Update the size

                    final_data.Write(FormatPacket(0x600D, part_data.GetBytes(), false));

                    ++parts; // Track how many parts there are
                }

                // Write the final header packet to the front of the packet
                PacketWriter final_header = new PacketWriter();
                final_header.Write((byte)1); // Header flag
                final_header.Write((short)parts);
                final_header.Write(packet.Opcode);
                final.Write(FormatPacket(0x600D, final_header.GetBytes(), false));

                // Finish the large packet of all the data
                final.Write(final_data.GetBytes());

                // Return the collated data
                byte[] raw_bytes = final.GetBytes();
                packet.Lock();
                return new KeyValuePair<TransferBuffer, Packet>(new TransferBuffer(raw_bytes, 0, raw_bytes.Length, true), packet);
            }
            else
            {
                bool encrypted = packet.Encrypted;
                if (!m_client_security)
                {
                    if (m_enc_opcodes.Contains(packet.Opcode))
                    {
                        encrypted = true;
                    }
                }
                byte[] raw_bytes = FormatPacket(packet.Opcode, packet.GetBytes(), encrypted);
                packet.Lock();
                return new KeyValuePair<TransferBuffer, Packet>(new TransferBuffer(raw_bytes, 0, raw_bytes.Length, true), packet);
            }
        }
Example #3
0
        // Default constructor
        public SecurityManager()
        {
            m_value_x = 0;
            m_value_g = 0;
            m_value_p = 0;
            m_value_A = 0;
            m_value_B = 0;
            m_value_K = 0;
            m_seed_count = 0;
            m_crc_seed = 0;
            m_initial_blowfish_key = 0;
            m_handshake_blowfish_key = 0;
            m_count_byte_seeds = new byte[3];
            m_count_byte_seeds[0] = 0;
            m_count_byte_seeds[1] = 0;
            m_count_byte_seeds[2] = 0;
            m_client_key = 0;
            m_challenge_key = 0;

            m_client_security = false;
            m_security_flag = 0;
            m_security_flags = new SecurityFlags();
            m_accepted_handshake = false;
            m_started_handshake = false;
            m_identity_flag = 0;
            m_identity_name = "<None>";

            m_outgoing_packets = new List<Packet>();
            m_incoming_packets = new List<Packet>();

            m_enc_opcodes = new List<ushort>();
            m_enc_opcodes.Add(0x2001);
            m_enc_opcodes.Add(0x6100);
            m_enc_opcodes.Add(0x6101);
            m_enc_opcodes.Add(0x6102);
            m_enc_opcodes.Add(0x6103);
            m_enc_opcodes.Add(0x6107);

            m_blowfish = new Blowfish();

            m_recv_buffer = new TransferBuffer(8192); // must be at minimal 2 bytes!
            m_current_buffer = null;

            m_massive_count = 0;
            m_massive_packet = null;

            m_class_lock = new object();
        }
Example #4
0
        // Transfers raw incoming data into the security object. Call TransferIncoming to
        // obtain a list of ready to process packets.
        public void Recv(TransferBuffer raw_buffer)
        {
            List<TransferBuffer> incoming_buffers_tmp = new List<TransferBuffer>();
            lock (m_class_lock)
            {
                int length = raw_buffer.Size - raw_buffer.Offset;
                int index = 0;
                while (length > 0)
                {
                    int max_length = length;
                    int calc_length = m_recv_buffer.Buffer.Length - m_recv_buffer.Size;

                    if (max_length > calc_length)
                    {
                        max_length = calc_length;
                    }
                    length -= max_length;

                    Buffer.BlockCopy(raw_buffer.Buffer, raw_buffer.Offset + index, m_recv_buffer.Buffer, m_recv_buffer.Size, max_length);

                    m_recv_buffer.Size += max_length;
                    index += max_length;

                    // Loop while we have data to process
                    while (m_recv_buffer.Size > 0)
                    {
                        // If we do not have a current packet object, try to allocate one.
                        if (m_current_buffer == null)
                        {
                            // We need at least two bytes to allocate a packet.
                            if (m_recv_buffer.Size < 2)
                            {
                                break;
                            }

                            // Calculate the packet size.
                            int packet_size = m_recv_buffer.Buffer[1] << 8 | m_recv_buffer.Buffer[0];

                            // Check to see if this packet is encrypted.
                            if ((packet_size & 0x8000) > 0)
                            {
                                // If so, calculate the total payload size.
                                packet_size &= 0x7FFF; // Mask off the encryption.
                                if (m_security_flags.blowfish == 1)
                                {
                                    packet_size = 2 + m_blowfish.GetOutputLength(packet_size + 4);
                                }
                                else
                                {
                                    packet_size += 6;
                                }
                            }
                            else
                            {
                                // The packet is unencrypted. The final size is simply
                                // header size + payload size.
                                packet_size += 6;
                            }

                            // Allocate the final buffer the packet will be written to
                            m_current_buffer = new TransferBuffer(packet_size, 0, packet_size);
                        }

                        // Calculate how many bytes are left to receive in the packet.
                        int max_copy_count = m_current_buffer.Size - m_current_buffer.Offset;

                        // If we need more bytes than we currently have, update the size.
                        if (max_copy_count > m_recv_buffer.Size)
                        {
                            max_copy_count = m_recv_buffer.Size;
                        }

                        // Copy the buffer data to the packet buffer
                        Buffer.BlockCopy(m_recv_buffer.Buffer, 0, m_current_buffer.Buffer, m_current_buffer.Offset, max_copy_count);

                        // Update how many bytes we now have
                        m_current_buffer.Offset += max_copy_count;
                        m_recv_buffer.Size -= max_copy_count;

                        // If there is data remaining in the buffer, copy it over the data
                        // we just removed (sliding buffer).
                        if (m_recv_buffer.Size > 0)
                        {
                            Buffer.BlockCopy(m_recv_buffer.Buffer, max_copy_count, m_recv_buffer.Buffer, 0, m_recv_buffer.Size);
                        }

                        // Check to see if the current packet is now complete.
                        if (m_current_buffer.Size == m_current_buffer.Offset)
                        {
                            // If so, dispatch it to the manager class for processing by the system.
                            m_current_buffer.Offset = 0;
                            incoming_buffers_tmp.Add(m_current_buffer);

                            // Set the current packet to null so we can process the next packet
                            // in the stream.
                            m_current_buffer = null;
                        }
                        else
                        {
                            // Otherwise, we are done with this loop, since we need more
                            // data for the current packet.
                            break;
                        }
                    }
                }

                if (incoming_buffers_tmp.Count > 0)
                {
                    foreach (TransferBuffer buffer in incoming_buffers_tmp)
                    {
                        bool packet_encrypted = false;

                        int packet_size = buffer.Buffer[1] << 8 | buffer.Buffer[0];
                        if ((packet_size & 0x8000) > 0)
                        {
                            if (m_security_flags.blowfish == 1)
                            {
                                packet_size &= 0x7FFF;
                                packet_encrypted = true;
                            }
                            else
                            {
                                packet_size &= 0x7FFF;
                            }
                        }

                        if (packet_encrypted)
                        {
                            byte[] decrypted = m_blowfish.Decode(buffer.Buffer, 2, buffer.Size - 2);
                            byte[] new_buffer = new byte[6 + packet_size];
                            Buffer.BlockCopy(BitConverter.GetBytes((ushort)packet_size), 0, new_buffer, 0, 2);
                            Buffer.BlockCopy(decrypted, 0, new_buffer, 2, 4 + packet_size);
                            buffer.Buffer = null;
                            buffer.Buffer = new_buffer;
                        }

                        PacketReader packet_data = new PacketReader(buffer.Buffer);
                        packet_size = packet_data.ReadUInt16();
                        ushort packet_opcode = packet_data.ReadUInt16();
                        byte packet_security_count = packet_data.ReadByte();
                        byte packet_security_crc = packet_data.ReadByte();

                        // Client object whose bytes the server might need to verify
                        if (m_client_security)
                        {
                            if (m_security_flags.security_bytes == 1)
                            {
                                byte expected_count = GenerateCountByte(true);
                                if (packet_security_count != expected_count)
                                {
                                    //throw (new Exception("[SecurityAPI::Recv] Count byte mismatch on {packet_opcode.ToString("X4")}."));
                                    StaticLogger.Instance.Warn($"[SecurityAPI::Recv] Count byte mismatch on {packet_opcode.ToString("X4")}. (Expected: {expected_count}, Packet: {packet_security_count})");
                                }

                                if (packet_encrypted || (m_security_flags.security_bytes == 1 && m_security_flags.blowfish == 0))
                                {
                                    if (packet_encrypted || m_enc_opcodes.Contains(packet_opcode))
                                    {
                                        packet_size |= 0x8000;
                                        Buffer.BlockCopy(BitConverter.GetBytes((ushort)packet_size), 0, buffer.Buffer, 0, 2);
                                    }
                                }

                                buffer.Buffer[5] = 0;

                                byte expected_crc = GenerateCheckByte(buffer.Buffer);
                                if (packet_security_crc != expected_crc)
                                {
                                    //throw (new Exception("[SecurityAPI::Recv] CRC byte mismatch."));
                                    StaticLogger.Instance.Warn($"[SecurityAPI::Recv] CRC byte mismatch on {packet_opcode.ToString("X4")}. (Expected: {expected_crc}, Packet: {packet_security_crc})");
                                }

                                buffer.Buffer[4] = 0;

                                if (packet_encrypted || (m_security_flags.security_bytes == 1 && m_security_flags.blowfish == 0))
                                {
                                    if (packet_encrypted || m_enc_opcodes.Contains(packet_opcode))
                                    {
                                        packet_size &= 0x7FFF;
                                        Buffer.BlockCopy(BitConverter.GetBytes((ushort)packet_size), 0, buffer.Buffer, 0, 2);
                                    }
                                }
                            }
                        }

                        if (packet_opcode == 0x5000 || packet_opcode == 0x9000) // New logic processing!
                        {
                            Handshake(packet_opcode, packet_data, packet_encrypted);

                            // Pass the handshake packets to the user so they can at least see them.
                            // They do not need to actually do anything with them. This was added to
                            // help debugging and make output logs complete.

                            Packet packet = new Packet(packet_opcode, packet_encrypted, false, buffer.Buffer, 6, packet_size);
                            packet.Lock();
                            m_incoming_packets.Add(packet);
                        }
                        else
                        {
                            if (m_client_security)
                            {
                                // Make sure the client accepted the security system first
                                if (!m_accepted_handshake)
                                {
                                    throw (new Exception("[SecurityAPI::Recv] The client has not accepted the handshake."));
                                }
                            }

                            if (packet_opcode == 0x600D) // Auto process massive messages for the user
                            {
                                byte mode = packet_data.ReadByte();
                                if (mode == 1)
                                {
                                    m_massive_count = packet_data.ReadUInt16();
                                    ushort contained_packet_opcode = packet_data.ReadUInt16();
                                    m_massive_packet = new Packet(contained_packet_opcode, packet_encrypted, true);
                                }
                                else
                                {
                                    if (m_massive_packet == null)
                                    {
                                        throw (new Exception("[SecurityAPI::Recv] A malformed 0x600D packet was received."));
                                    }
                                    m_massive_packet.WriteByteArray(packet_data.ReadBytes(packet_size - 1));
                                    m_massive_count--;

                                    if (m_massive_count == 0)
                                    {
                                        m_massive_packet.Lock();
                                        m_incoming_packets.Add(m_massive_packet);
                                        m_massive_packet = null;
                                    }
                                }
                            }
                            else
                            {
                                Packet packet = new Packet(packet_opcode, packet_encrypted, false, buffer.Buffer, 6, packet_size);
                                packet.Lock();
                                m_incoming_packets.Add(packet);
                            }
                        }
                    }
                }
            }
        }