openmohaa/code/gamespy/gcrypt.c

224 lines
6 KiB
C
Raw Permalink Normal View History

/*
===========================================================================
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);
2025-02-22 22:11:29 +01:00
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);
2025-02-22 22:11:29 +01:00
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);
2025-02-22 22:11:29 +01:00
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] = LittleLong(keyIndex ^ xorKey);
offset--;
if (offset < 0) {
offset = 0;
}
part = rotl32(~info->msg[offset], 24);
2025-02-22 22:11:29 +01:00
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 = 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] ^= 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));
}
2025-02-22 22:56:57 +01:00
out[i] ^= *info->wordPtr;
info->wordPtr++;
}
}
2025-02-28 18:11:09 +01:00
int enctype2_encoder(unsigned char *secKey, unsigned char *data, int size)
{
GCryptInfo info = {0};
int i;
int header_size = 8;
// move the data and put it after the header
for (i = size - 1; i >= 0; i--) {
data[1 + header_size + i] = data[i];
}
// initialize the header
for (i = 0; i < header_size; i++) {
data[i + 1] = 0;
}
// initialize the crypt key
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 = header_size ^ 0xec;
return size;
}