• Unfortunately, we have experienced significant hard drive damage that requires urgent maintenance and rebuilding. The forum will be a state of read only until we install our new drives and rebuild all the configurations needed. Please follow our Facebook page for updates, we will be back up shortly! (The forum could go offline at any given time due to the nature of the failed drives whilst awaiting the upgrades.) When you see an Incapsula error, you know we are in the process of migration.

Issue with enc\dec game packets (aion client)

Initiate Mage
Joined
Feb 17, 2023
Messages
2
Reaction score
0
Hello, im developing 4.8 aion on C#. I have done login server and communication between login & game server, now im trying to send&receive game packets (for now im trying to enter choosed server from server list).

when i got connection from user i send SM_KEY()
Code:
write(client.enableCryptKey());

my crypt class
Code:
public static byte staticServerPacketCode = 0x44;


private bool isEnabled;
private EncryptionKeyPair packetKey = null;

private static System.Random rnd = new System.Random();

        public int enableKey()
        {
            if (packetKey != null)
                return 0;

            int key = rnd.Next();
            packetKey = new EncryptionKeyPair(key);

            //false key that will be sent to aion client in SM_KEY packet
            return (int)((key ^ 0xCD92E4DF) + 0x3FF2CCCF);
        }

        public bool decrypt(ref byte[] data, int offset, int len)
        {
            try
            {
                if (!isEnabled)
                {
                    return true;
                }
                return packetKey.decrypt(ref data, offset, len);
            }
            catch (Exception e)
            {
                Log.error("Decryption error " + e.Message);
                Log.log(e.ToString());
            }
            return false;
        }

        public void encrypt(ref byte[] data, int offset, int len)
        {
            if (!isEnabled)
            {
                Console.WriteLine(isEnabled);
                isEnabled = true;

                return;
            }
            try
            {
                packetKey.encrypt(ref data, offset, len);
            }
            catch (Exception e)
            {
                Log.error("Encryption error " + e.Message);
                Log.log(e.ToString());
            }
        }

        public static byte encodeOpcode(int op)
        {
            return (byte)((op + 0xCF) ^ 0xDF);
        }

EncryptionKeyPair
Code:
static int SERVER = 0;

        static int CLIENT = 1;

        static byte[] staticKey = Encoding.UTF8.GetBytes("nKO/WctQ0AVLbpzfBkS6NevDYT8ourG5CRlmdjyJ72aswx4EPq1UgZhFMXH?3iI9");

        private static byte staticClientPacketCode = 0x65;

        private int baseKey = 0;

        private byte[][] keys = null;

        public EncryptionKeyPair(int baseKey)
        {
            this.baseKey = baseKey;
            keys = new byte[2][];

            keys[SERVER] = new byte[] {
                (byte) (baseKey & 0xff),
                (byte) ((baseKey >> 8) & 0xff),
                (byte) ((baseKey >> 16) & 0xff),
                (byte) ((baseKey >> 24) & 0xff),
                (byte) 0xa1,
                (byte) 0x6c,
                (byte) 0x54,
                (byte) 0x87
            };

            keys[CLIENT] = new byte[keys[SERVER].Length];
            Array.Copy(keys[SERVER], 0, keys[CLIENT], 0, keys[SERVER].Length);
        }

        public int getBaseKey()
        {
            return baseKey;
        }

        private bool validateClientPacket(byte[] data)
        {
            short zero = data[0], three = data[3];
            byte two = data[2];

            return zero == ~three && two == staticClientPacketCode;
        }

        public bool decrypt(ref byte[] data, int arrayIndex, int size)
        {
            byte[] clientPacketKey = keys[CLIENT];

            int prev = data[arrayIndex];
            
            data[arrayIndex++] ^= (byte)(clientPacketKey[0] & 0xff);

            for (int i = 1; i < size; i++, arrayIndex++)
            {
                int curr = data[arrayIndex] & 0xff;
                data[arrayIndex] ^= (byte)((staticKey[i & 63] & 0xff) ^ (clientPacketKey[i & 7] & 0xff) ^ prev);
                prev = curr;
            }

            long oldKey = (((long)clientPacketKey[0] & 0xff) << 0) | (((long)clientPacketKey[1] & 0xff) << 8)
            | (((long)clientPacketKey[2] & 0xff) << 16) | (((long)clientPacketKey[3] & 0xff) << 24)
            | (((long)clientPacketKey[4] & 0xff) << 32) | (((long)clientPacketKey[5] & 0xff) << 40)
            | (((long)clientPacketKey[6] & 0xff) << 48) | (((long)clientPacketKey[7] & 0xff) << 56);

            oldKey += size;

           if (data[6] == (0xFF - data[3]))
            {
                clientPacketKey[0] = (byte)(oldKey >> 0 & 0xff);
                clientPacketKey[1] = (byte)(oldKey >> 8 & 0xff);
                clientPacketKey[2] = (byte)(oldKey >> 16 & 0xff);
                clientPacketKey[3] = (byte)(oldKey >> 24 & 0xff);
                clientPacketKey[4] = (byte)(oldKey >> 32 & 0xff);
                clientPacketKey[5] = (byte)(oldKey >> 40 & 0xff);
                clientPacketKey[6] = (byte)(oldKey >> 48 & 0xff);
                clientPacketKey[7] = (byte)(oldKey >> 56 & 0xff);
            }
            else
            {
                Log.error("Cryptographically incorrect packet received !");
                Log.debug("Data: " + Utils.hexToString(data));

                return false;
            }
            return true;
        }

        public void encrypt(ref byte[] data, int arrayIndex, int size)
        {
            byte[] serverPacketKey = keys[SERVER];

            data[arrayIndex] ^= (byte)(serverPacketKey[0] & 0xff);

            int prev = data[arrayIndex++];

            for (int i = 1; i < size; i++, arrayIndex++)
            {
                data[arrayIndex] ^= (byte)((staticKey[i & 63] & 0xff) ^ (serverPacketKey[i & 7] & 0xff) ^ prev);
                prev = data[arrayIndex];
            }

            long oldKey = (((long)serverPacketKey[0] & 0xff) << 0) | (((long)serverPacketKey[1] & 0xff) << 8)
                | (((long)serverPacketKey[2] & 0xff) << 16) | (((long)serverPacketKey[3] & 0xff) << 24)
                | (((long)serverPacketKey[4] & 0xff) << 32) | (((long)serverPacketKey[5] & 0xff) << 40)
                | (((long)serverPacketKey[6] & 0xff) << 48) | (((long)serverPacketKey[7] & 0xff) << 56);

            oldKey += size;

            serverPacketKey[0] = (byte)(oldKey >> 0 & 0xff);
            serverPacketKey[1] = (byte)(oldKey >> 8 & 0xff);
            serverPacketKey[2] = (byte)(oldKey >> 16 & 0xff);
            serverPacketKey[3] = (byte)(oldKey >> 24 & 0xff);
            serverPacketKey[4] = (byte)(oldKey >> 32 & 0xff);
            serverPacketKey[5] = (byte)(oldKey >> 40 & 0xff);
            serverPacketKey[6] = (byte)(oldKey >> 48 & 0xff);
            serverPacketKey[7] = (byte)(oldKey >> 56 & 0xff);
        }

my send packet
Code:
packet.set(this);
                    packet.Position = 0;

                    if (!Packets.Game.server.ContainsKey(packet.GetType()))
                    {
                        Log.error($"Undefined packet to send to AION client [{packet.GetType()}]");
                        return;
                    }

                    byte opcode = Packets.Game.server[packet.GetType()];
                    byte cryptedOpcode = CryptEngine.encodeOpcode(opcode);

                    packet.write((short)0); // future length
                    packet.write(cryptedOpcode);
                    packet.write((byte)1);
                    packet.write(CryptEngine.staticServerPacketCode);
                    packet.write((short)(~cryptedOpcode)); // for checksum?
                    packet.write((byte)(0xFF - (byte)1));
                    packet.implement();

                    int len = (int)packet.Position;
                    byte[] result = new byte[len]; //slice
                    Array.Copy(packet.ToArray(), 0, result, 0, len);

                    crypt.encrypt(ref result, 2, len - 2);

                    packet.Position = 0; //flip

                    packet.write((short)len);
                    packet.write(result, 2, len - 2);

                    channel.SendAsync(packet.ToArray(), SocketFlags.None);

and receive
Code:
ushort size =
                BitConverter.ToUInt16(
                    new byte[] { (byte)receiveStream.ReadByte(), (byte)receiveStream.ReadByte() }, 0);

                receiveStream.Position -= 2;
                while (size > 0 && size <= receiveStream.Length - receiveStream.Position)
                {
                    byte[] data = new byte[size];
                    receiveStream.Read(data, 0, size);

                    if (crypt != null && !crypt.decrypt(ref data, 2, size - 2))
                    {
                        close();
                        return;
                    }

                    //Process packet
                    using MemoryStream stream = new MemoryStream(data, 2, data.Length - 2, false);

                    byte op = (byte)stream.ReadByte();
                    if (!Packets.Game.client.ContainsValue(op))
                    {
                        Log.warn("Undefined packet from AION client " + op);
                        //close(new SM_LOGIN_FAIL(ResponseType.SYSTEM_ERROR));

                        return;
                    }

                    stream.Position += 4;

                    ClientPacket<WConnection> main = Activator.CreateInstance(Packets.Game.client.FirstOrDefault(x => x.Value == op).Key) as ClientPacket<WConnection>;

                    byte[] maintain = new byte[stream.Length - stream.Position];
                    Array.Copy(stream.ToArray(), (int)stream.Position, maintain, 0, (int)(stream.Length - stream.Position));
                    main.set(this, maintain, 0);
                    main.execute();

                    if (receiveStream.Length - receiveStream.Position > 2)
                    {
                        size = BitConverter.ToUInt16(new byte[] { (byte)receiveStream.ReadByte(), (byte)receiveStream.ReadByte() }, 0);
                        receiveStream.Position -= 2;
                    }
                    else
                        size = 0;
                }
                int remain = (int)(receiveStream.Length - receiveStream.Position);
                if (remain > 0)
                {
                    byte[] remdata = new byte[remain];
                    receiveStream.Read(remdata, 0, remain);
                    receiveStream.Position = 0;
                    receiveStream.Write(remdata, 0, remdata.Length);
                }
                else
                    receiveStream.Position = 0;

and i get error on
if (data[6] == (0xFF - data[3]))
 
Experienced Elementalist
Joined
Aug 6, 2021
Messages
220
Reaction score
55
if (data[6] == (0xFF - data[3])) is incorrect, this condition should validate the packet data sending and receiving.

For testing you don't need it.

first gameserver packet sent is SM_KEY and it's 2 bytes size, 2 bytes obfuscate opcode, 1 byte static opcode, 2 bytes bitwise complimented opcode and 4 bytes for the key which will equal 11 bytes and this is unencrypted, just obfuscate and compliment the opcode, write the key and send it directly to the connected client.

You will know if it worked when you receive 0xC2 and 0xD0, those are your CM_VERSION_CHECK and CM_TIME_CHECK packets from the client.

Your decryption function allows you to pass in the arrayIndex, for testing you can use 0 and once you are in game you can then adjust it as this will change for each game packet you receive. If you don't account for this, your decryption will mess up. Take a read of my comment left on the other post about it.
 
Last edited:
Upvote 0
Back
Top