Login Packets for 5089+ (New Client)

01/11/2009 08:31 BoboDundo#1
I know I might be a little crazy, but I'm going to work on a CO Client. I'm trying to do a proxy/packet logger and a very simple client that can do some basic things. Later is definitely a big project, but it is something I want to tackle. However, before I can do that, there are a few things that I need to know.

Does anyone have the login packet structures for 5089+? There are a couple of things that I am looking for and perhaps just some clarification on what I already know from the old client/server:

1) On the first packet that is sent from the Client to the Server: What is used to encrypt the password or is it still the same encryption that can be found on the private servers?

2) On the first packet that is sent from the Client to the Server: Near the end of the packet there is now some extra information. What is this? I'm pretty sure I'll need to send this to the CO Server.

3) On the first packet that is sent from the Server to the Client. Using 0 as the first offset in the index, the previous structure was the following:

0/1 = Packet Length (2 bytes)
2/3 = PackeType (0x41f) (2 bytes)
4 = Encryption Key 2 using an offset of 3
5 = Encryption Key 2 using an offset of 2
6 = Encryption Key 2 using an offset of 1
7 = Encryption Key 2 using an offset of 0
8 = Encryption Key 1 using an offset of 3
9 = Encryption Key 1 using an offset of 2
10 = Encryption Key 1 using an offset of 1
11 = Encryption Key 1 using an offset of 0
12 - 27 = IP Address
28/29 = Port Number (2 bytes)
30/31 (Unused)

Can anyone confirm is this is still the same with 5089+. If not, what is the new packet structure and how is it defined and used?

Lastly, it appears that there is one last packet that is again sent from the Client to the Login Server. What is this for? I'm unable to tell what this is.

I'm into the wee hours of the morning, so pardon any typos. thank you for your assistance.
01/11/2009 13:41 tanelipe#2
1) They still use the same encryption for password. (I'm not sure if the private servers have the encryption, decryption they've got)

2) The login packet is almost identical to what it was before with couple exceptions
- Id was changed to 0x43B
- They added padding in the packet, possibly for more information. First padding is 109 bytes and the 2nd padding is 112 bytes. The structure is :

Code:
struct login_packet {
   ushort length; 
   ushort type;
   string username; // Size = 16
   byte padding[109];
   string password; // Size = 16
   byte padding2[112];
   string server; // Size 16
}
3) I haven't noticed any diffrence in this packet, still has the two unused bytes at the end, contains port/ip.. So I'd say it hasn't changed
01/11/2009 15:44 BoboDundo#3
On #1, during my tests I was getting a different encrypted password when using a password of "test" (without the quotes) when using client 5089 vs 5017. Does the LOTF source have the decryption in it (I don't want to spend half a day searching through private servers to find the decryption). I'll do more testing to verify, but it looks like the encryption of the password is different.

I did a have a fourth question:

4) It appears that there is a second login packet that is sent from the Client to the Login Server. What is this for? I'm unable to tell what this is.

Thank you for your help.

Quote:
Originally Posted by tanelipe View Post
1) They still use the same encryption for password. (I'm not sure if the private servers have the encryption, decryption they've got)

2) The login packet is almost identical to what it was before with couple exceptions
- Id was changed to 0x43B
- They added padding in the packet, possibly for more information. First padding is 109 bytes and the 2nd padding is 112 bytes. The structure is :

Code:
struct login_packet {
   ushort length; 
   ushort type;
   string username; // Size = 16
   byte padding[109];
   string password; // Size = 16
   byte padding2[112];
   string server; // Size 16
}
3) I haven't noticed any diffrence in this packet, still has the two unused bytes at the end, contains port/ip.. So I'd say it hasn't changed
01/11/2009 19:41 tanelipe#4
Well, I have no idea what decryption they have in there, the one I have works 100% and it has worked since 5017 (Can't release it, don't have the permission from the maker ><)

What is the 4th login packet id though? 0x44C ? If so, I have no idea sorry.
01/11/2009 23:45 tao4229#5
Most private servers don't have password decryption.
They take the first encrypted password from the client, store it encrypted, and then just check.
01/12/2009 04:39 BoboDundo#6
Ya, I've looked through a couple and even some online web registrations. As you mentioned, the servers just compare the encrypted password against the encrypted password in the database.

On the web registration programs, all they do is set the password to null. The private servers then update the password if it is null.

I did find some source on one of my computers from long ago that had the decryption of the password for the older clients. I'm going to do some testing and see if I can get it to work with what is currently be sent in the 5089+.


Quote:
Originally Posted by tao4229 View Post
Most private servers don't have password decryption.
They take the first encrypted password from the client, store it encrypted, and then just check.
01/12/2009 05:36 BoboDundo#7
I am now able to "decrypt" the password in the 5089+ client. However, what I'm looking for is to encrypt the password. I'll just have to go through the code and reverse what is being done so I can encrypt the password.

Thank you for everyone's help. That takes care of the first login packet :)
02/13/2009 19:14 XtremeX-CO#8
I still use the old ones lol.... may be a bit dirty , but they work
note:... java
Code:
    private static byte m_dwS[]=new byte[256];

    public static void encrypt(byte[] bOutput) {
        int chiperOffset = 28;
        long key3 = (m_dwS[19] & 0xff) << 24 | (m_dwS[18] & 0xff) << 16 | (m_dwS[17] & 0xff) << 8 | m_dwS[16] & 0xff;
        long key1 = (m_dwS[23] & 0xff) << 24 | (m_dwS[22] & 0xff) << 16 | (m_dwS[21] & 0xff) << 8 | m_dwS[20] & 0xff;
        long org2, org4, dwTemp1, dwTemp2, A, B, chiperContent;
        for (int j = 0; j < 2; j++) {
            org2 = (bOutput[j * 8 + 0] & 0xff) | (bOutput[j * 8 + 1] & 0xff) << 8 | (bOutput[j * 8 + 2] & 0xff) << 16 | (bOutput[j * 8 + 3] & 0xff) << 24;
            org4 = (bOutput[j * 8 + 4] & 0xff) | (bOutput[j * 8 + 5] & 0xff) << 8 | (bOutput[j * 8 + 6] & 0xff) << 16 | (bOutput[j * 8 + 7] & 0xff) << 24;
            dwTemp2 = org2 + key3 & 0xffffffffL;
            dwTemp1 = org4 + key1 & 0xffffffffL;
            for (int i = 0; i < 12; i++) {
                A = leftRotate(dwTemp2 ^ dwTemp1, dwTemp1);
                chiperContent = (m_dwS[(chiperOffset + i * 8) - 1] & 0xff) << 24 | (m_dwS[(chiperOffset + i * 8) - 2] & 0xff) << 16 | (m_dwS[(chiperOffset + i * 8) - 3] & 0xff) << 8 | m_dwS[(chiperOffset + i * 8) - 4] & 0xff;
                dwTemp2 = A + chiperContent & 0xffffffffL;
                B = leftRotate(dwTemp1 ^ dwTemp2, dwTemp2);
                chiperContent = (m_dwS[chiperOffset + i * 8 + 3] & 0xff) << 24 | (m_dwS[chiperOffset + i * 8 + 2] & 0xff) << 16 | (m_dwS[chiperOffset + i * 8 + 1] & 0xff) << 8 | m_dwS[chiperOffset + i * 8 + 0] & 0xff;
                dwTemp1 = B + chiperContent & 0xffffffffL;
            }
            bOutput[j * 8 + 0] = (byte) (int) (dwTemp2 & 255L);
            bOutput[j * 8 + 1] = (byte) (int) ((dwTemp2 & 65280L) >> 8);
            bOutput[j * 8 + 2] = (byte) (int) ((dwTemp2 & 0xff0000L) >> 16);
            bOutput[j * 8 + 3] = (byte) (int) ((dwTemp2 & 0xffffffffff000000L) >> 24);
            bOutput[j * 8 + 4] = (byte) (int) (dwTemp1 & 255L);
            bOutput[j * 8 + 5] = (byte) (int) ((dwTemp1 & 65280L) >> 8);
            bOutput[j * 8 + 6] = (byte) (int) ((dwTemp1 & 0xff0000L) >> 16);
            bOutput[j * 8 + 7] = (byte) (int) ((dwTemp1 & 0xffffffffff000000L) >> 24);
        }
    }

    public static void decrypt(byte bOutput[]) {
        int chiperOffset = 28;
        long key3 = (m_dwS[19] & 0xff) << 24 | (m_dwS[18] & 0xff) << 16 | (m_dwS[17] & 0xff) << 8 | m_dwS[16] & 0xff;
        long key1 = (m_dwS[23] & 0xff) << 24 | (m_dwS[22] & 0xff) << 16 | (m_dwS[21] & 0xff) << 8 | m_dwS[20] & 0xff;
        for (int j = 1; j >= 0; j--) {
            long dwTemp1 = (bOutput[j * 8 + 7] & 0xff) << 24 | (bOutput[j * 8 + 6] & 0xff) << 16 | (bOutput[j * 8 + 5] & 0xff) << 8 | bOutput[j * 8 + 4] & 0xff;
            long dwTemp2 = (bOutput[j * 8 + 3] & 0xff) << 24 | (bOutput[j * 8 + 2] & 0xff) << 16 | (bOutput[j * 8 + 1] & 0xff) << 8 | bOutput[j * 8 + 0] & 0xff;
            for (int i = 11; i >= 0; i--) {
                long chiperContent = (m_dwS[chiperOffset + i * 8 + 3] & 0xff) << 24 | (m_dwS[chiperOffset + i * 8 + 2] & 0xff) << 16 | (m_dwS[chiperOffset + i * 8 + 1] & 0xff) << 8 | m_dwS[chiperOffset + i * 8 + 0] & 0xff;
                long B = dwTemp1 - chiperContent & 0xffffffffL;
                dwTemp1 = rightRotate(B, dwTemp2) ^ dwTemp2;
                chiperContent = (m_dwS[(chiperOffset + i * 8) - 1] & 0xff) << 24 | (m_dwS[(chiperOffset + i * 8) - 2] & 0xff) << 16 | (m_dwS[(chiperOffset + i * 8) - 3] & 0xff) << 8 | m_dwS[(chiperOffset + i * 8) - 4] & 0xff;
                long A = dwTemp2 - chiperContent & 0xffffffffL;
                dwTemp2     = rightRotate(A, dwTemp1) ^ dwTemp1;
            }
            long org2 = dwTemp2 - key3 & 0xffffffffL;
            long org4 = dwTemp1 - key1 & 0xffffffffL;
            bOutput[j * 8 + 0] = (byte) (int) (org2 & 255L);
            bOutput[j * 8 + 1] = (byte) (int) ((org2 & 65280L) >> 8);
            bOutput[j * 8 + 2] = (byte) (int) ((org2 & 0xff0000L) >> 16);
            bOutput[j * 8 + 3] = (byte) (int) ((org2 & 0xffffffffff000000L) >> 24);
            bOutput[j * 8 + 4] = (byte) (int) (org4 & 255L);
            bOutput[j * 8 + 5] = (byte) (int) ((org4 & 65280L) >> 8);
            bOutput[j * 8 + 6] = (byte) (int) ((org4 & 0xff0000L) >> 16);
            bOutput[j * 8 + 7] = (byte) (int) ((org4 & 0xffffffffff000000L) >> 24);
        }
    }

    public static void keyGen() {
        long P32 = 0xb7e15163L;
        long Q32 = 0x61c88647L;
        byte bKey[] = {
            60, -36, -2, -24, -60, 84, -42, 126, 22, -90,
            -8, 26, -24, -48, 56, -66
        };
        System.arraycopy(bKey, 0, m_dwS, 0, 16);
        m_dwS[16] = (byte) (int) (P32 & 255L);
        m_dwS[17] = (byte) (int) ((P32 & 65280L) >> 8);
        m_dwS[18] = (byte) (int) ((P32 & 0xff0000L) >> 16);
        m_dwS[19] = (byte) (int) ((P32 & 0xffffffffff000000L) >> 24);
        long A;
        long B;
        for (int i = 1; i <= 25; i++) {
            B = (m_dwS[19 + (i - 1) * 4] & 0xff) << 24 | (m_dwS[18 + (i - 1) * 4] & 0xff) << 16 | (m_dwS[17 + (i - 1) * 4] & 0xff) << 8 | m_dwS[16 + (i - 1) * 4] & 0xff;
            A = B - Q32 & 0xffffffffL;
            m_dwS[16 + i * 4] = (byte) (int) (A & 255L);
            m_dwS[17 + i * 4] = (byte) (int) ((A & 65280L) >> 8);
            m_dwS[18 + i * 4] = (byte) (int) ((A & 0xff0000L) >> 16);
            m_dwS[19 + i * 4] = (byte) (int) ((A & 0xffffffffff000000L) >> 24);
        }
        int offsetA = 0;
        int offsetB = 0;
        A = 0L;
        B = 0L;
        long nLoopAmount = 78L;
        for (int s = 1; (long) s <= nLoopAmount; s++) {
            long dwTemp = (m_dwS[offsetA * 4 + 19] & 0xff) << 24 | (m_dwS[offsetA * 4 + 18] & 0xff) << 16 | (m_dwS[offsetA * 4 + 17] & 0xff) << 8 | m_dwS[offsetA * 4 + 16] & 0xff;
            A = leftRotate(dwTemp + A + B & 0xffffffffL, 3L);
            m_dwS[offsetA * 4 + 16] = (byte) (int) (A & 255L);
            m_dwS[offsetA * 4 + 17] = (byte) (int) ((A & 65280L) >> 8);
            m_dwS[offsetA * 4 + 18] = (byte) (int) ((A & 0xff0000L) >> 16);
            m_dwS[offsetA * 4 + 19] = (byte) (int) ((A & 0xffffffffff000000L) >> 24);
            offsetA = (offsetA + 1) % 26;
            dwTemp = 0L;
            dwTemp = (m_dwS[offsetB * 4 + 3] & 0xff) << 24 | (m_dwS[offsetB * 4 + 2] & 0xff) << 16 | (m_dwS[offsetB * 4 + 1] & 0xff) << 8 | m_dwS[offsetB * 4 + 0] & 0xff;
            B = leftRotate(dwTemp + A + B & 0xffffffffL, A + B);
            m_dwS[offsetB * 4 + 0] = (byte) (int) (B & 255L);
            m_dwS[offsetB * 4 + 1] = (byte) (int) ((B & 65280L) >> 8);
            m_dwS[offsetB * 4 + 2] = (byte) (int) ((B & 0xff0000L) >> 16);
            m_dwS[offsetB * 4 + 3] = (byte) (int) ((B & 0xffffffffff000000L) >> 24);
            offsetB = (offsetB + 1) % 4;
        }

    }

    public static long leftRotate(long dwVar, long dwOffset) {
        dwOffset &= 31L;
        long dwTemp1 = dwVar >> 32 - (int) dwOffset;
        long dwTemp2 = dwVar << (int) dwOffset;
        dwTemp2 = (dwTemp2 | dwTemp1) & -1L;
        return dwTemp2;
    }

    public static long rightRotate(long dwVar, long dwOffset) {
        dwOffset &= 31L;
        long dwTemp1 = dwVar << 32 - (int) dwOffset;
        long dwTemp2 = dwVar >> (int) dwOffset;
        dwTemp2 = (dwTemp2 | dwTemp1) & -1L;
        return dwTemp2;
    }

Also the structures, as i remember them are

Code:
Login Packet
int size;
int packet_id;
char username[16];
char empty1[114]; //114 bytes of nothing...
char password[16];
char empty[114]; //same again...
char server[16];


Second Packet
int size;
int packet_id;
int account_id;
int key; //send to game server to allow login
char ip[16];
int port;


Third packet
ill get the struct when i get home... i don't have my source with me