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); } }
private byte[] FormatPacket(ushort opcode, byte[] data, bool encrypted) { // Sanity check if (data.Length >= 0x8000) { throw (new Exception("[SecurityAPI::FormatPacket] Payload is too large!")); } ushort data_length = (ushort)data.Length; // Add the packet header to the start of the data PacketWriter writer = new PacketWriter(); writer.Write(data_length); // packet size writer.Write(opcode); // packet opcode writer.Write((ushort)0); // packet security bytes writer.Write(data); writer.Flush(); // Determine if we need to mark the packet size as encrypted if (encrypted && (m_security_flags.blowfish == 1 || (m_security_flags.security_bytes == 1 && m_security_flags.blowfish == 0))) { long seek_index = writer.BaseStream.Seek(0, SeekOrigin.Current); ushort packet_size = (ushort)(data_length | 0x8000); writer.BaseStream.Seek(0, SeekOrigin.Begin); writer.Write((ushort)packet_size); writer.Flush(); writer.BaseStream.Seek(seek_index, SeekOrigin.Begin); } // Only need to stamp bytes if this is a clientless object if (m_client_security == false && m_security_flags.security_bytes == 1) { long seek_index = writer.BaseStream.Seek(0, SeekOrigin.Current); byte sb1 = GenerateCountByte(true); writer.BaseStream.Seek(4, SeekOrigin.Begin); writer.Write(sb1); writer.Flush(); byte sb2 = GenerateCheckByte(writer.GetBytes()); writer.BaseStream.Seek(5, SeekOrigin.Begin); writer.Write(sb2); writer.Flush(); writer.BaseStream.Seek(seek_index, SeekOrigin.Begin); } // If the packet should be physically encrypted, return an encrypted version of it if (encrypted && m_security_flags.blowfish == 1) { byte[] raw_data = writer.GetBytes(); byte[] encrypted_data = m_blowfish.Encode(raw_data, 2, raw_data.Length - 2); writer.BaseStream.Seek(2, SeekOrigin.Begin); writer.Write(encrypted_data); writer.Flush(); } else { // Determine if we need to unmark the packet size from being encrypted but not physically encrypted if (encrypted && (m_security_flags.security_bytes == 1 && m_security_flags.blowfish == 0)) { long seek_index = writer.BaseStream.Seek(0, SeekOrigin.Current); writer.BaseStream.Seek(0, SeekOrigin.Begin); writer.Write((ushort)data_length); writer.Flush(); writer.BaseStream.Seek(seek_index, SeekOrigin.Begin); } } // Return the final data return writer.GetBytes(); }