aboutsummaryrefslogtreecommitdiff
path: root/src/Protocols
diff options
context:
space:
mode:
authorDarkelarious <github@333networks.com>2025-03-08 15:33:52 +0100
committerDarkelarious <github@333networks.com>2025-03-08 15:33:52 +0100
commitee9c0c04bdcd8b7223dd0f6f313592e8a91994dc (patch)
treeedd5a314d0cb68e66bd2d23f5201eb9f6ec7bb75 /src/Protocols
parentb7f431a17f0d957ff56b6a36470444a95d4752bc (diff)
downloadMasterserver-Qt5-ee9c0c04bdcd8b7223dd0f6f313592e8a91994dc.tar.gz
Masterserver-Qt5-ee9c0c04bdcd8b7223dd0f6f313592e8a91994dc.zip
hotfix 3
Support for Medal of Honor franchise with enctype2. License for 3rd party functions inside source code.
Diffstat (limited to 'src/Protocols')
-rw-r--r--src/Protocols/enctype2.cpp408
-rw-r--r--src/Protocols/enctype2.h112
2 files changed, 520 insertions, 0 deletions
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
+ ===========================================================================
+*/