diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Core/version.h | 2 | ||||
| -rw-r--r-- | src/MasterServer-Qt5.pro | 2 | ||||
| -rw-r--r-- | src/Protocols/enctype2.cpp | 408 | ||||
| -rw-r--r-- | src/Protocols/enctype2.h | 112 | ||||
| -rw-r--r-- | src/TcpTasks/ListenClientHandler/listenclienthandler.h | 2 |
5 files changed, 525 insertions, 1 deletions
diff --git a/src/Core/version.h b/src/Core/version.h index 57a81b8..7cd3254 100644 --- a/src/Core/version.h +++ b/src/Core/version.h @@ -29,7 +29,7 @@ #define BUILD_VERSION QString("0.27") // short version (in query) -- Qt v0.n -#define SHORT_VER QString("Qt-" + BUILD_VERSION + "hf2") +#define SHORT_VER QString("Qt-" + BUILD_VERSION + "hf3") // build time/date #define BUILD_TIME QStringLiteral("%1 %2").arg(__DATE__).arg(__TIME__) diff --git a/src/MasterServer-Qt5.pro b/src/MasterServer-Qt5.pro index 1ba6bdc..720e4d6 100644 --- a/src/MasterServer-Qt5.pro +++ b/src/MasterServer-Qt5.pro @@ -34,6 +34,7 @@ SOURCES += \ Logger/logger.cpp \ Logger/openlogfile.cpp \ Logger/writelogfile.cpp \ + Protocols/enctype2.cpp \ Settings/loadsettings.cpp \ Settings/writesettings.cpp \ Core/core.cpp \ @@ -98,6 +99,7 @@ HEADERS += \ Core/GameInfo/loadsupportedgames.h \ Logger/logger.h \ Logger/logprimitive.h \ + Protocols/enctype2.h \ Settings/loadsettings.h \ Settings/settingstructure.h \ Core/core.h \ diff --git a/src/Protocols/enctype2.cpp b/src/Protocols/enctype2.cpp new file mode 100644 index 0000000..03fad72 --- /dev/null +++ b/src/Protocols/enctype2.cpp @@ -0,0 +1,408 @@ +#include "enctype2.h" +/* see enctype.h for proper creditations and remarks */ + +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[part & 0xff] ^ part, 24); + part = rotl32(info->key[keyIndex & 0xff] ^ keyIndex, 8); + xorKey ^= info->key[xorKey & 0xff]; + keyIndex = rotl32(info->key[part & 0xff] ^ 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[part & 0xff] ^ part, 24); + part = rotl32(info->key[xorKey & 0xff] ^ xorKey, 8); + keyIndex ^= info->key[keyIndex & 0xff]; + xorKey = rotl32(info->key[part & 0xff] ^ 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[part & 0xff] ^ part, 24); + part = rotl32(info->key[xorKey & 0xff] ^ xorKey, 8); + keyIndex ^= info->key[keyIndex & 0xff]; + xorKey = rotl32(info->key[part & 0xff] ^ part, 8); + + i *= 2; + } + + words[w] = keyIndex ^ xorKey; + offset--; + if (offset < 0) { + offset = 0; + } + + part = rotl32(~info->msg[offset], 24); + xorKey = rotl32(info->key[part & 0xff] ^ part, 24); + part = rotl32(info->key[info->msg[offset + 16] & 0xff] ^ info->msg[offset + 16], 8); + xorKey ^= info->key[xorKey & 0xff]; + keyIndex = rotl32(info->key[part & 0xff] ^ 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 = nullptr; + 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] ^= 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; + + int lenw = sizeof(info->words) / sizeof(info->words[0]); + crypt_encrypt(info, info->words, lenw); + } + + out[i] ^= *info->wordPtr; + info->wordPtr++; + } +} + +void encshare2(unsigned int *tbuff, unsigned int *tbuffp, int len) { + unsigned int t1, + t2, + t3, + t4, + t5, + *limit, + *p; + + t2 = tbuff[304]; + t1 = tbuff[305]; + t3 = tbuff[306]; + t5 = tbuff[307]; + limit = tbuffp + len; + while(tbuffp < limit) { + p = tbuff + t2 + 272; + while(t5 < 65536) { + t1 += t5; + p++; + t3 += t1; + t1 += t3; + p[-17] = t1; + p[-1] = t3; + t4 = (t3 << 24) | (t3 >> 8); + p[15] = t5; + t5 <<= 1; + t2++; + t1 ^= tbuff[t1 & 0xff]; + t4 ^= tbuff[t4 & 0xff]; + t3 = (t4 << 24) | (t4 >> 8); + t4 = (t1 >> 24) | (t1 << 8); + t4 ^= tbuff[t4 & 0xff]; + t3 ^= tbuff[t3 & 0xff]; + t1 = (t4 >> 24) | (t4 << 8); + } + t3 ^= t1; + *tbuffp++ = t3; + t2--; + t1 = tbuff[t2 + 256]; + t5 = tbuff[t2 + 272]; + t1 = ~t1; + t3 = (t1 << 24) | (t1 >> 8); + t3 ^= tbuff[t3 & 0xff]; + t5 ^= tbuff[t5 & 0xff]; + t1 = (t3 << 24) | (t3 >> 8); + t4 = (t5 >> 24) | (t5 << 8); + t1 ^= tbuff[t1 & 0xff]; + t4 ^= tbuff[t4 & 0xff]; + t3 = (t4 >> 24) | (t4 << 8); + t5 = (tbuff[t2 + 288] << 1) + 1; + } + tbuff[304] = t2; + tbuff[305] = t1; + tbuff[306] = t3; + tbuff[307] = t5; +} + + + +void encshare1(unsigned int *tbuff, unsigned char *datap, int len) { + unsigned char *p, + *s; + + p = s = (unsigned char *)(tbuff + 309); + encshare2(tbuff, (unsigned int *)p, 16); + + while(len--) { + if((p - s) == 63) { + p = s; + encshare2(tbuff, (unsigned int *)p, 16); + } + *datap ^= *p; + datap++; + p++; + } +} + + + +void encshare3(unsigned int *data, int n1, int n2) { + unsigned int t1, + t2, + t3, + t4; + int i; + + t2 = n1; + t1 = 0; + t4 = 1; + data[304] = 0; + for(i = 32768; i; i >>= 1) { + t2 += t4; + t1 += t2; + t2 += t1; + if(n2 & i) { + t2 = ~t2; + t4 = (t4 << 1) + 1; + t3 = (t2 << 24) | (t2 >> 8); + t3 ^= data[t3 & 0xff]; + t1 ^= data[t1 & 0xff]; + t2 = (t3 << 24) | (t3 >> 8); + t3 = (t1 >> 24) | (t1 << 8); + t2 ^= data[t2 & 0xff]; + t3 ^= data[t3 & 0xff]; + t1 = (t3 >> 24) | (t3 << 8); + } else { + data[data[304] + 256] = t2; + data[data[304] + 272] = t1; + data[data[304] + 288] = t4; + data[304]++; + t3 = (t1 << 24) | (t1 >> 8); + t2 ^= data[t2 & 0xff]; + t3 ^= data[t3 & 0xff]; + t1 = (t3 << 24) | (t3 >> 8); + t3 = (t2 >> 24) | (t2 << 8); + t3 ^= data[t3 & 0xff]; + t1 ^= data[t1 & 0xff]; + t2 = (t3 >> 24) | (t3 << 8); + t4 <<= 1; + } + } + data[305] = t2; + data[306] = t1; + data[307] = t4; + data[308] = n1; + // t1 ^= t2; +} + + + +void encshare4(unsigned char *src, int size, unsigned int *dest) { + unsigned int tmp; + int i; + unsigned char pos, + x, + y; + + for(i = 0; i < 256; i++) dest[i] = 0; + + for(y = 0; y < 4; y++) { + for(i = 0; i < 256; i++) { + dest[i] = (dest[i] << 8) + i; + } + + for(pos = y, x = 0; x < 2; x++) { + for(i = 0; i < 256; i++) { + tmp = dest[i]; + pos += tmp + src[i % size]; + dest[i] = dest[pos]; + dest[pos] = tmp; + } + } + } + + for(i = 0; i < 256; i++) dest[i] ^= i; + + encshare3(dest, 0, 0); +} + +unsigned char *enctype2_decoder(unsigned char *key, unsigned char *data, int *size) { + unsigned int dest[326]; + int i; + unsigned char *datap; + + *data ^= 0xec; + datap = data + 1; + + for(i = 0; key[i]; i++) datap[i] ^= key[i]; + + for(i = 0; i < 326; i++) dest[i] = 0; + if(*data) encshare4(datap, *data, dest); + + datap += *data; + *size -= (*data + 1); + if(*size < 6) { + *size = 0; + return(data); + } + + encshare1(dest, datap, *size); + + *size -= 6; + return(datap); +} + + + +int enctype2_wrapper(unsigned char *key, unsigned char *data, int size) { + unsigned char *p; + int i; + + p = enctype2_decoder(key, data, &size); + + //memmove(data, p, size); // memmove works but is untrusted + if(p > data) { + for(i = 0; i < size; i++) { + data[i] = p[i]; + } + } + return(size); +} + + + +/* +data must be big enough to contain also the following bytes: 1 + 8 + 6 +*/ +int enctype2_encoder(unsigned char *secKey, unsigned char *data, int size) +{ + GCryptInfo info = {0}; + int i; + int header_size = 8; + + for (i = size - 1; i >= 0; i--) { + data[1 + header_size + i] = data[i]; + } + *data = header_size; + + for (i = 0; i < header_size; i++) { + data[i + 1] = 0; + } + + init_crypt_key(data + 1, header_size, &info); + + for (i = 0; i < 6; i++) { + data[1 + header_size + size + i] = 0; + } + crypt_docrypt(&info, data + 1 + header_size, size + 6); + + for (i = 0; secKey[i]; i++) { + data[i + 1] ^= secKey[i]; + } + + size += 1 + header_size + 6; + *data ^= 0xec; + return size; +} + diff --git a/src/Protocols/enctype2.h b/src/Protocols/enctype2.h new file mode 100644 index 0000000..f4c71f8 --- /dev/null +++ b/src/Protocols/enctype2.h @@ -0,0 +1,112 @@ +#ifndef ENC2_H +#define ENC2_H + +#include <string.h> + +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); + +int enctype2_encoder(unsigned char *secKey, unsigned char *data, int size); + +#endif // ENC2_H + +/* +This file contains code from both Luigi Auriemma and the OpenMoHAA project. Code is used +with either direct permission of the author(s) and/or within the boundaries of the included license. + + +GS enctype2 servers list decoder/encoder 0.1.2 +by Luigi Auriemma +e-mail: aluigi@autistici.org +web: aluigi.org + + +INTRODUCTION +============ +This is the algorithm used to decrypt the data sent by the Gamespy +master server (or any other compatible server) using the enctype 2 +method. + + +USAGE +===== +Add the following prototype at the beginning of your code: + + unsigned char *enctype2_decoder(unsigned char *, unsigned char *, int *); + +then use: + + pointer = enctype2_decoder( + gamekey, // the gamekey + buffer, // all the data received from the master server + &buffer_len); // the size of the master server + +The return value is a pointer to the decrypted zone of buffer and +buffer_len is modified with the size of the decrypted data. + +A simpler way to use the function is just using: + + len = enctype2_wrapper(key, data, data_len); + + +THANX TO +======== +REC (http://www.backerstreet.com/rec/rec.htm) which has helped me in many +parts of the code. + + +LICENSE +======= + Copyright 2004-2014 Luigi Auriemma + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + http://www.gnu.org/licenses/gpl.txt + + + =========================================================================== + 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 + =========================================================================== +*/ diff --git a/src/TcpTasks/ListenClientHandler/listenclienthandler.h b/src/TcpTasks/ListenClientHandler/listenclienthandler.h index f7c300b..3c857fa 100644 --- a/src/TcpTasks/ListenClientHandler/listenclienthandler.h +++ b/src/TcpTasks/ListenClientHandler/listenclienthandler.h @@ -9,6 +9,7 @@ #include "Database/Common/commonactions.h" #include "Protocols/GameSpy0/gamespy0.h" +#include "protocols/enctype2.h" #include "Protocols/GameSpy0/securevalidate.h" class ListenClientHandler : public QObject @@ -26,6 +27,7 @@ private: QTimer _timeOut; QString _rxBuffer = ""; bool _hasValidated = false; + bool _requestEnctype2 = false; QString _clientLabel; QString _secure; |
