Issue with enc\dec game packets (aion client)

Results 1 to 2 of 2
  1. #1
    Newbie danilaion is offline
    MemberRank
    Feb 2023 Join Date
    2Posts

    sad Issue with enc\dec game packets (aion client)

    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]))


  2. #2
    Elite Member StingerOne is offline
    Member +Rank
    Aug 2021 Join Date
    AltgardLocation
    179Posts
    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 by StingerOne; 4 Weeks Ago at 04:00 PM.



Advertisement