2025-02-22 20:36:32 +01:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
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);
|
2025-02-22 20:36:32 +01:00
|
|
|
|
|
|
|
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);
|
2025-02-22 20:36:32 +01:00
|
|
|
|
|
|
|
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);
|
2025-02-22 20:36:32 +01:00
|
|
|
|
|
|
|
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);
|
2025-02-22 20:36:32 +01:00
|
|
|
|
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|