For others that would like to understand in more details:
The login server also uses a protocol (sent by the server to the client in the very first packet). For instance, the C4 client (the one I'm developing my emulator for) expects the protocol number `50721` (or `0xc621`) which works as follow (from what I've gathered):
Preamble: L2 packets are divided into two parts: size and payload;
As mentioned, every packet starts with two bytes containing the whole packet size (thus including those two bytes, e.g. a packet of size 15 will have the number `15` written onto its first two bytes and a following payload of 13 bytes);
For login server, first byte of the payload is the opcode (game server must deal with variable-sized opcodes);
Next bytes are the packet content;
Before sending the packet, its buffer size (minus the initial two bytes) is padded to 8 bytes (required by upcoming Blowfish encoding);
A checksum of the packet is appended at the end, then the payload is again padded to 8 bytes;
If the opcode is not `0` (also written as `0x00`), then the payload is encoded by Blowfish;
Packet is sent over the network.
You can have a look at my implementation (in C++) here (do note I'm assuming little-endian).
In this protocol, the auth packet (`0x00`) sent back by the client is RSA encrypted using the RSA modulus sent in the first server packet, inserted right after the protocol number.