I have been writing a gamespy enctype 0 emulator for the older games to teach myself some basic sockets programming and it works very well. Using Daikatana with the Gamespy SDK I am able to see all the handshakes and good stuff going on.
During this time, I have noticed that QTracker always sends the same \\basic\\secure\\TXKOAT key every time. I want to use your enctypex_decoder.c to cross-check the key during a list request or even a heartbeat. Experimenting I found out that gamespy will periodically send a heartbeat packet out that is just \\status\\ but you can do \\status\\secure\\<your key> and then the game will use the gs_encrypt and gs_encode functions to send the special key back.
Currently, I just ignore the key and allow the server (or query list request) to go through, and QTracker is doing the same. I would like to get it working properly for fun.
My question is, how do I use your enctypex_decoder.c to accomplish this?
Here is a snippet from how the SDK is handling parsing a \\secure\\
Code: Select all
char data[256], *ptr, result[64];
ptr = strstr ( data, SECURE ) + strlen(SECURE);
gs_encrypt ( (uchar *)serverlist->seckey, 6, (uchar *)ptr, 6 );
gs_encode ( (uchar *)ptr, 6, (uchar *)result );
//validate to the master
sprintf(data, "\\gamename\\%s\\gamever\\%s\\location\\0\\validate\\%s\\final\\\\queryid\\1.1\\",
serverlist->enginename, ENGINE_VERSION, result); //validate us
In the above code, gamespy strips out the \\secure and any other data before it. The following 6 characters are the key sent out by the server (in this hardcoded case TXKOAT)
Here is the Gamespy SDK functions for enctype 0 (I added the printfs to see how it works)
Code: Select all
/*****************************************************************************/
/* Various encryption / encoding routines */
void swap_byte ( uchar *a, uchar *b )
{
uchar swapByte;
swapByte = *a;
*a = *b;
*b = swapByte;
}
uchar encode_ct ( uchar c )
{
if (c < 26) return ('A'+c);
if (c < 52) return ('a'+c-26);
if (c < 62) return ('0'+c-52);
if (c == 62) return ('+');
if (c == 63) return ('/');
return 0;
}
void gs_encode ( uchar *ins, int size, uchar *result )
{
int i,pos;
uchar trip[3];
uchar kwart[4];
Com_Printf("Ins[%i]: %s\n", size, ins);
i=0;
while (i < size)
{
for (pos=0 ; pos <= 2 ; pos++, i++)
if (i < size) trip[pos] = *ins++;
else trip[pos] = '\0';
kwart[0] = (trip[0]) >> 2;
kwart[1] = (((trip[0]) & 3) << 4) + ((trip[1]) >> 4);
kwart[2] = (((trip[1]) & 15) << 2) + ((trip[2]) >> 6);
kwart[3] = (trip[2]) & 63;
for (pos=0; pos <= 3; pos++) *result++ = encode_ct(kwart[pos]);
}
*result='\0';
}
void gs_encrypt ( uchar *key, int key_len, uchar *buffer_ptr, int buffer_len )
{
short counter;
uchar x, y, xorIndex;
uchar state[256];
Com_Printf("Key[%i]: %s\n", key_len, key);
Com_Printf("Ptr[%i]: %s\n", buffer_len, buffer_ptr);
for ( counter = 0; counter < 256; counter++) state[counter] = (uchar) counter;
x = 0; y = 0;
for ( counter = 0; counter < 256; counter++)
{
y = (key[x] + state[counter] + y) & 255;
x = (x + 1) % key_len;
swap_byte ( &state[counter], &state[y] );
}
x = 0; y = 0;
for ( counter = 0; counter < buffer_len; counter ++)
{
x = (x + buffer_ptr[counter] + 1)& 255;
y = (state[x] + y) & 255;
swap_byte ( &state[x], &state[y] );
xorIndex = (state[x] + state[y])& 255;
buffer_ptr[counter] ^= state[xorIndex];
}
}
And here is what I am trying to do in the master server for list request
Code: Select all
char *buffer = "\\basic\\\\secure\\TXKOAT"; // FS: This is the generic encode key QTracker is sending out.
char *validateKey;
char decodedKey[64];
// FS: This doesn't work yet.
validateKey = value_for_key(incomingTcpValidate, "validate");
// printf("Validate Key: %s\n", validateKey);
enctype = enctypex_wrapper((unsigned char *)"TXKOAT", (unsigned char*)validateKey, decodedKey, 6);
printf("Decoded[%i]: %u\n", enctype, decodedKey);
value_for_key is another internal gamespy SDK function to just simply grab the validate key. In the case of daikatana,
Gamespy validate server key: \basic\\secure\TXKOAT
Key[6]: fl8aY7 <-- secret ket
Ptr[6]: TXKOAT <-- what I am sending
Ins[6]: ©ü<‡/Ã <-- what the function is turning it into before it goes to gs_encode
Result: 1243196 <-- the final value as %u.
qfw8hy/D <-- the result as a string sent out to the world
Gamespy validate to the master: \gamename\daikatana\gamever\0.5\location\0\validate\qfw8hy/D\final\\queryid\1.1\
Also, I am not skilled with any kind of encryption/decryption techniques. So, I'm hoping this is something as simple as not using the proper functions or using them correctly.
Thanks for everyones help in advance.