mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
Add support for server list encryption and tell the master server to return the server list encrypted
This commit is contained in:
parent
512831dea9
commit
08c718d232
4 changed files with 312 additions and 23 deletions
|
@ -11,6 +11,7 @@ file(GLOB SRCS_common
|
|||
"./hashtable.c"
|
||||
"./md5c.c"
|
||||
"./gutil.c"
|
||||
"./gcrypt.c"
|
||||
)
|
||||
|
||||
file(GLOB SRCS_gcdkey
|
||||
|
|
198
code/gamespy/gcrypt.c
Normal file
198
code/gamespy/gcrypt.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2025 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "gcrypt.h"
|
||||
#include "../qcommon/q_platform.h"
|
||||
#include "../qcommon/q_shared.h"
|
||||
|
||||
static unsigned int rotl32(unsigned int value, unsigned int count)
|
||||
{
|
||||
return (value << count) | (value >> (-count & 31));
|
||||
}
|
||||
|
||||
static unsigned int crypt_seek(GCryptInfo *info, unsigned int n1, unsigned int n2)
|
||||
{
|
||||
int part;
|
||||
int i;
|
||||
int keyIndex;
|
||||
int xorKey;
|
||||
int current;
|
||||
|
||||
current = 0x8000;
|
||||
xorKey = n1;
|
||||
keyIndex = 0;
|
||||
i = 1;
|
||||
|
||||
info->offset = 0;
|
||||
|
||||
while (current > 0) {
|
||||
xorKey += i;
|
||||
keyIndex += xorKey;
|
||||
xorKey += keyIndex;
|
||||
|
||||
if (n2 & current) {
|
||||
part = rotl32(~xorKey, 24);
|
||||
xorKey = rotl32(info->key[(unsigned char)part] ^ part, 24);
|
||||
part = rotl32(info->key[(unsigned char)keyIndex] ^ keyIndex, 8);
|
||||
xorKey ^= info->key[(unsigned char)xorKey];
|
||||
keyIndex = rotl32(info->key[(unsigned char)part] ^ part, 8);
|
||||
|
||||
i += 1 + i;
|
||||
} else {
|
||||
info->msg[info->offset] = xorKey;
|
||||
info->msg[info->offset + 16] = keyIndex;
|
||||
info->msg[info->offset + 32] = i;
|
||||
info->offset++;
|
||||
|
||||
part = rotl32(keyIndex, 24);
|
||||
keyIndex = rotl32(info->key[(unsigned char)part] ^ part, 24);
|
||||
part = rotl32(info->key[(unsigned char)xorKey] ^ xorKey, 8);
|
||||
keyIndex ^= info->key[(unsigned char)keyIndex];
|
||||
xorKey = rotl32(info->key[(unsigned char)part] ^ part, 8);
|
||||
|
||||
i *= 2;
|
||||
}
|
||||
|
||||
current >>= 1;
|
||||
}
|
||||
|
||||
info->xorKey = xorKey;
|
||||
info->keyIndex = keyIndex;
|
||||
info->i = i;
|
||||
info->start = n1;
|
||||
|
||||
return keyIndex ^ xorKey;
|
||||
}
|
||||
|
||||
static void crypt_encrypt(GCryptInfo *info, unsigned int *words, int len)
|
||||
{
|
||||
int part;
|
||||
unsigned int i;
|
||||
unsigned int w;
|
||||
int keyIndex;
|
||||
int xorKey;
|
||||
int offset;
|
||||
|
||||
offset = info->offset;
|
||||
xorKey = info->xorKey;
|
||||
keyIndex = info->keyIndex;
|
||||
i = info->i;
|
||||
|
||||
for (w = 0; w < len; w++) {
|
||||
while (i < 0x10000) {
|
||||
xorKey += i;
|
||||
keyIndex += xorKey;
|
||||
xorKey += keyIndex;
|
||||
|
||||
info->msg[offset] = xorKey;
|
||||
info->msg[offset + 16] = keyIndex;
|
||||
info->msg[offset + 32] = i;
|
||||
offset++;
|
||||
|
||||
part = rotl32(keyIndex, 24);
|
||||
keyIndex = rotl32(info->key[(unsigned char)part] ^ part, 24);
|
||||
part = rotl32(info->key[(unsigned char)xorKey] ^ xorKey, 8);
|
||||
keyIndex ^= info->key[(unsigned char)keyIndex];
|
||||
xorKey = rotl32(info->key[(unsigned char)part] ^ part, 8);
|
||||
|
||||
i *= 2;
|
||||
}
|
||||
|
||||
words[w] = LittleLong(keyIndex ^ xorKey);
|
||||
offset--;
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
part = rotl32(~info->msg[offset], 24);
|
||||
xorKey = rotl32(info->key[(unsigned char)part] ^ part, 24);
|
||||
part = rotl32(info->key[(unsigned char)info->msg[offset + 16]] ^ info->msg[offset + 16], 8);
|
||||
xorKey ^= info->key[(unsigned char)xorKey];
|
||||
keyIndex = rotl32(info->key[(unsigned char)part] ^ part, 8);
|
||||
|
||||
i = info->msg[offset + 32] + 1 + info->msg[offset + 32];
|
||||
}
|
||||
|
||||
info->offset = offset;
|
||||
info->xorKey = xorKey;
|
||||
info->keyIndex = keyIndex;
|
||||
info->i = i;
|
||||
}
|
||||
|
||||
void init_crypt_key(unsigned char *src, unsigned int len, GCryptInfo *info)
|
||||
{
|
||||
int index;
|
||||
int i, j, k;
|
||||
int tmp;
|
||||
|
||||
info->wordPtr = NULL;
|
||||
for (k = 0; k < 256; k++) {
|
||||
info->key[k] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (k = 0; k < 256; k++) {
|
||||
info->key[k] = (info->key[k] << 8) + k;
|
||||
}
|
||||
|
||||
index = i;
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
for (k = 0; k < 256; k++) {
|
||||
index = ((info->key[k] & 0xff) + src[k % len] + index) & 0xff;
|
||||
|
||||
tmp = info->key[k];
|
||||
info->key[k] = info->key[index];
|
||||
info->key[index] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 0; k < 256; k++) {
|
||||
info->key[k] = LittleLong(info->key[k]);
|
||||
}
|
||||
|
||||
for (k = 0; k < 256; k++) {
|
||||
info->key[k] ^= k;
|
||||
}
|
||||
|
||||
crypt_seek(info, 0, 0);
|
||||
}
|
||||
|
||||
void crypt_docrypt(GCryptInfo *info, unsigned char *out, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!info->wordPtr || ((char *)info->wordPtr - (char *)info->words) >= (sizeof(info->words) - 1)) {
|
||||
info->wordPtr = (unsigned char *)info->words;
|
||||
crypt_encrypt(info, info->words, ARRAY_LEN(info->words));
|
||||
}
|
||||
|
||||
char value[4];
|
||||
CopyLittleLong(value, info->wordPtr);
|
||||
memcpy(info->wordPtr, value, sizeof(value));
|
||||
|
||||
out[i] ^= *(unsigned char *)info->wordPtr;
|
||||
info->wordPtr++;
|
||||
}
|
||||
}
|
40
code/gamespy/gcrypt.h
Normal file
40
code/gamespy/gcrypt.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2025 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
int key[256];
|
||||
int msg[48];
|
||||
|
||||
int offset;
|
||||
int xorKey;
|
||||
int keyIndex;
|
||||
int i;
|
||||
int start;
|
||||
|
||||
unsigned int words[16];
|
||||
unsigned char *wordPtr;
|
||||
} GCryptInfo;
|
||||
|
||||
void init_crypt_key(unsigned char *src, unsigned int len, GCryptInfo *info);
|
||||
void crypt_docrypt(GCryptInfo *info, unsigned char *out, int len);
|
|
@ -45,6 +45,9 @@ Fax(714)549-0757
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Added in 2.0
|
||||
#include "gcrypt.h"
|
||||
|
||||
#define MSHOST MASTER_SERVER_HOST
|
||||
#define MSPORT 28900
|
||||
#define SERVER_GROWBY 64
|
||||
|
@ -87,6 +90,10 @@ struct GServerListImplementation
|
|||
unsigned long lanstarttime;
|
||||
GQueryType querytype;
|
||||
HashTable keylist;
|
||||
|
||||
// Added in 2.0
|
||||
GCryptInfo cryptinfo;
|
||||
int encryptdata;
|
||||
};
|
||||
|
||||
GServerList g_sortserverlist; //global serverlist for sorting info!!
|
||||
|
@ -125,6 +132,7 @@ GServerList ServerListNew(const char *gamename, const char *enginename, const ch
|
|||
assert(CallBackFn != NULL);
|
||||
list->instance = instance;
|
||||
list->sortkey = "";
|
||||
list->encryptdata = 1;
|
||||
SocketStartUp();
|
||||
return list;
|
||||
}
|
||||
|
@ -242,7 +250,7 @@ static GError SendListRequest(GServerList serverlist, char *filter)
|
|||
{
|
||||
char data[256], *ptr, result[64];
|
||||
int len;
|
||||
|
||||
int i;
|
||||
|
||||
len = recv(serverlist->slsocket, data, sizeof(data) - 1, 0);
|
||||
if (gsiSocketIsError(len))
|
||||
|
@ -254,11 +262,25 @@ static GError SendListRequest(GServerList serverlist, char *filter)
|
|||
return GE_DATAERROR;
|
||||
ptr = ptr + strlen(SECURE);
|
||||
gs_encrypt ( (uchar *) serverlist->seckey, 6, (uchar *)ptr, 6 );
|
||||
if (serverlist->encryptdata) {
|
||||
// Added in 2.0
|
||||
for(i = 0; i < 6; i++) {
|
||||
ptr[i] ^= serverlist->seckey[i];
|
||||
}
|
||||
}
|
||||
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
|
||||
if (serverlist->encryptdata) {
|
||||
// Added in 2.0
|
||||
// Encrypt data
|
||||
//validate to the master
|
||||
sprintf(data, "\\gamename\\%s\\gamever\\%s\\location\\0\\validate\\%s\\enctype\\2\\final\\\\queryid\\1.1\\",
|
||||
serverlist->enginename, "2", result); //validate us
|
||||
} else {
|
||||
//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
|
||||
}
|
||||
|
||||
len = send ( serverlist->slsocket, data, strlen(data), 0 );
|
||||
if (gsiSocketIsError(len) || len == 0)
|
||||
|
@ -337,6 +359,8 @@ GError ServerListUpdate2(GServerList serverlist, gbool async, char *filter, GQue
|
|||
if (error) return error;
|
||||
serverlist->nextupdate = 0;
|
||||
serverlist->abortupdate = 0;
|
||||
// Added in 2.0
|
||||
serverlist->cryptinfo.offset = -1;
|
||||
if (!async)
|
||||
DoSyncLoop(serverlist);
|
||||
|
||||
|
@ -577,27 +601,53 @@ static GError ServerListReadList(GServerList serverlist)
|
|||
return GE_NOCONNECT;
|
||||
|
||||
}
|
||||
oldlen += len;
|
||||
|
||||
if (serverlist->encryptdata && serverlist->cryptinfo.offset != -1) {
|
||||
// Added in 2.0
|
||||
crypt_docrypt(&serverlist->cryptinfo, data + oldlen, len);
|
||||
}
|
||||
|
||||
oldlen += len;
|
||||
|
||||
p = data;
|
||||
while (p - data <= oldlen - 6)
|
||||
{
|
||||
if (strncmp(p,"\\final\\",7) == 0 || serverlist->abortupdate)
|
||||
{
|
||||
closesocket(serverlist->slsocket);
|
||||
serverlist->slsocket = INVALID_SOCKET;
|
||||
oldlen = 0; //clear data so it can be used again
|
||||
ServerListModeChange(serverlist, sl_querying);
|
||||
return 0; //get out!!
|
||||
}
|
||||
if (oldlen < 6) //no way it could be a full IP, quit
|
||||
break;
|
||||
memcpy(&ip,p,4);
|
||||
p += 4;
|
||||
memcpy(&port,p,2);
|
||||
p += 2;
|
||||
ServerListAddServer(serverlist,ip, ntohs(port), serverlist->querytype );
|
||||
}
|
||||
|
||||
if (!serverlist->encryptdata) {
|
||||
serverlist->cryptinfo.offset = 0;
|
||||
} else if (serverlist->cryptinfo.offset == -1) {
|
||||
// Added in 2.0
|
||||
if (oldlen > (*p ^ 0xEC)) {
|
||||
*p ^= 0xEC;
|
||||
len = strlen(serverlist->seckey);
|
||||
for (i = 0; i < len; i++) {
|
||||
p[i + 1] ^= serverlist->seckey[i];
|
||||
}
|
||||
init_crypt_key((unsigned char *)p + 1, *p, &serverlist->cryptinfo);
|
||||
p += *p + 1;
|
||||
crypt_docrypt(&serverlist->cryptinfo, (unsigned char *)p, oldlen - (p - data));
|
||||
}
|
||||
}
|
||||
|
||||
if (serverlist->cryptinfo.offset != -1)
|
||||
{
|
||||
while (p - data <= oldlen - 6)
|
||||
{
|
||||
if (strncmp(p,"\\final\\",7) == 0 || serverlist->abortupdate)
|
||||
{
|
||||
closesocket(serverlist->slsocket);
|
||||
serverlist->slsocket = INVALID_SOCKET;
|
||||
oldlen = 0; //clear data so it can be used again
|
||||
ServerListModeChange(serverlist, sl_querying);
|
||||
return 0; //get out!!
|
||||
}
|
||||
if (oldlen < 6) //no way it could be a full IP, quit
|
||||
break;
|
||||
memcpy(&ip,p,4);
|
||||
p += 4;
|
||||
memcpy(&port,p,2);
|
||||
p += 2;
|
||||
ServerListAddServer(serverlist,ip, ntohs(port), serverlist->querytype );
|
||||
}
|
||||
}
|
||||
oldlen = oldlen - (p - data);
|
||||
memmove(data,p,oldlen); //shift it over
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue