mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 23:51:41 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
482
Code/Tools/RenegadeGR/WENCRYPT.CPP
Normal file
482
Code/Tools/RenegadeGR/WENCRYPT.CPP
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
** Command & Conquer Renegade(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *
|
||||
******************************************************************************
|
||||
Project Name: Generic Game Results Server
|
||||
File Name : wencrypt.cpp
|
||||
Author : Joe Howes
|
||||
Start Date : Jul 9, 1999
|
||||
Last Update : Jul 20, 1999
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
A simple encryption system for game results packets. Specifically designed
|
||||
to work only with unsigned char buffers of least 15 bytes long.
|
||||
|
||||
\****************************************************************************/
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <winsock2.h>
|
||||
#include "wencrypt.h"
|
||||
#include "wnet/packet.h"
|
||||
|
||||
/*extern "C" {
|
||||
extern unsigned char* PrepareEncryptedPacket(unsigned char* packet, int* size);
|
||||
}*/
|
||||
/*------------------------------------------------------------------------------.
|
||||
| FUNCTION: PrepareEncryptedPacket() |
|
||||
| If an error occurs, a NULL will be returned and the size value will be a |
|
||||
| negative integer corresponding to an error in wencrypt.h. |
|
||||
| JUL 20/99: In the Windows WOLAPI, the function RequestGameresSend requires |
|
||||
| a buffer that can be passed to the constructor of PacketClass. Thus we need |
|
||||
| to wrap our encrypted buffer in a packet with one big data field and pass |
|
||||
| it's Comms Packet output back. |
|
||||
`------------------------------------------------------------------------------*/
|
||||
unsigned char* PrepareEncryptedPacket(unsigned char* packet, int* size)
|
||||
{
|
||||
unsigned char* rlebuf = NULL;
|
||||
unsigned char* encbuf = NULL;
|
||||
PacketClass wrap;
|
||||
static char field[5] = { "CNTL" };
|
||||
|
||||
|
||||
rlebuf = (unsigned char *) malloc((*size)*2);
|
||||
|
||||
|
||||
// Run length encode
|
||||
RLEncode(packet, rlebuf, size); // Does not allocate any memory
|
||||
|
||||
|
||||
// XOR encrypt
|
||||
encbuf = SimpleEncrypt(rlebuf, size);
|
||||
if( rlebuf != NULL ) free(rlebuf);
|
||||
if( encbuf == NULL ) return NULL; // SimpleEncrypt fills the error in
|
||||
|
||||
|
||||
// Now we have to wrap the encrypted data inside a valid PacketClass blob
|
||||
wrap.Add_Field((char*)"CNTL", (void*)encbuf, *size);
|
||||
free(encbuf);
|
||||
|
||||
|
||||
return (unsigned char*)(wrap.Create_Comms_Packet(*size));
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------.
|
||||
| FUNCTION: DecryptPacket() |
|
||||
| If an error occurs, a NULL will be returned and the size value will be a |
|
||||
| negative integer corresponding to an error in wencrypt.h |
|
||||
`------------------------------------------------------------------------------*/
|
||||
#ifndef __CLIENT__
|
||||
unsigned char* DecryptPacket(unsigned char* encbuf, int* size)
|
||||
{
|
||||
unsigned char* rlebuf;
|
||||
unsigned char* packet;
|
||||
|
||||
|
||||
rlebuf = SimpleDecrypt(encbuf, size);
|
||||
if( rlebuf == NULL )
|
||||
return NULL; // SimpleDecrypt fills the error in
|
||||
|
||||
|
||||
packet = RLDecode(rlebuf, size); // Allocates memory!!
|
||||
if( packet == NULL )
|
||||
return NULL; // RLDecode fills the error in
|
||||
|
||||
|
||||
return packet;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------.
|
||||
| FUNCTION: RLEncode() |
|
||||
| - src is a buffer conatining the uncompressed data. |
|
||||
| - dst is a buffer which should be twice the size of the src buffer. |
|
||||
| - size indicates the size of the source buffer at the start of the function, |
|
||||
| and is filled with the length of the dest buffer on return. |
|
||||
| |
|
||||
| NOTE: As is the nature of RLE, it is possible the "compressed" buffer |
|
||||
| will be bigger than the uncompressed one by one byte. Actually in the |
|
||||
| absolute worst case it can be bigger than that if the escape code occurs |
|
||||
| often enough in the buffer and needs to be stuffed several times. I *think* |
|
||||
| it's impossible for the compressed buffer to ever get twice as big as the |
|
||||
| original, being that we choose the lowest frequency value as the escape, but |
|
||||
| there will never be a memory overrun this way, and gameres packets are tiny. |
|
||||
`------------------------------------------------------------------------------*/
|
||||
void RLEncode(unsigned char* src, unsigned char* dst, int* size)
|
||||
{
|
||||
int i, j, k;
|
||||
int frequencies[256];
|
||||
int lowest;
|
||||
unsigned char escape;
|
||||
unsigned char currtally = 1;
|
||||
unsigned char curr;
|
||||
|
||||
|
||||
// Determine what we should use for the escape code. Ideally it's a value
|
||||
// that doesn't occur in the buffer, but we'll settle for the value that
|
||||
// appears the least number of times.
|
||||
memset(frequencies, 0, 256 * sizeof(int));
|
||||
for(i = 0; i < *size; frequencies[src[i++]]++);
|
||||
lowest = frequencies[0];
|
||||
escape = 0;
|
||||
for(i = 0; i < 256; i++)
|
||||
{
|
||||
if( frequencies[i] == 0 )
|
||||
{
|
||||
escape = (unsigned char)i;
|
||||
break;
|
||||
}
|
||||
if( frequencies[i] < lowest )
|
||||
{
|
||||
lowest = frequencies[i];
|
||||
escape = (unsigned char)i;
|
||||
}
|
||||
}
|
||||
dst[0] = escape;
|
||||
|
||||
|
||||
// Build the dest buffer
|
||||
curr = src[0];
|
||||
for(i = 1, j = 1; i <= *size; i++)
|
||||
{
|
||||
if( src[i] == curr && i < *size )
|
||||
currtally++;
|
||||
else
|
||||
{
|
||||
if( currtally > 3 )
|
||||
{
|
||||
dst[j++] = escape;
|
||||
dst[j++] = currtally;
|
||||
dst[j++] = curr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stuff the escape character
|
||||
for(k = 0; k < currtally; k++)
|
||||
{
|
||||
if( curr == escape )
|
||||
dst[j++] = curr;
|
||||
dst[j++] = curr;
|
||||
}
|
||||
}
|
||||
curr = src[i];
|
||||
currtally = 1;
|
||||
}
|
||||
}
|
||||
*size = j;
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------.
|
||||
| FUNCTION: RLDecode() |
|
||||
| Nothing special...just remember byte 0 is the escape and not part of the |
|
||||
| original buffer. If there is an error, the returned pointer will be NULL |
|
||||
| and the size will contain a negative number indicating the error code. |
|
||||
`------------------------------------------------------------------------------*/
|
||||
#ifndef __CLIENT__
|
||||
unsigned char* RLDecode(unsigned char* src, int* size)
|
||||
{
|
||||
int i, j, k;
|
||||
int dstsize = 0;
|
||||
unsigned char escape = src[0];
|
||||
unsigned char* dst;
|
||||
|
||||
|
||||
// How big will the resultant buffer be?
|
||||
for(i = 1; i < *size; i++)
|
||||
{
|
||||
if( src[i] == escape && i < (*size-1) )
|
||||
{
|
||||
if( src[i+1] == escape )
|
||||
{
|
||||
dstsize++; // Stuffed escape
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dstsize += (int)src[i+1]; // Add the occurences
|
||||
i += 2; // Skip the token
|
||||
}
|
||||
}
|
||||
else if( src[i] == escape && i == (*size-1) )
|
||||
{
|
||||
*size = ERR_SPURIOUS_ESCAPE;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
dstsize++;
|
||||
}
|
||||
|
||||
|
||||
// Build the new buffer
|
||||
dst = malloc( dstsize );
|
||||
j = 0;
|
||||
for(i = 1; i < *size; i++)
|
||||
{
|
||||
if( src[i] == escape && i < (*size-1) )
|
||||
{
|
||||
if( src[i+1] == escape )
|
||||
{
|
||||
dst[j++] = src[i]; // Stuffed escape
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(k = 0; k < (int)src[i+1]; k++)
|
||||
dst[j+k] = src[i+2];
|
||||
j += k;
|
||||
i += 2; // Skip the token
|
||||
}
|
||||
}
|
||||
else if( src[i] == escape && i == (*size-1) )
|
||||
{
|
||||
*size = ERR_SPURIOUS_ESCAPE;
|
||||
delete[] dst;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
dst[j++] = src[i];
|
||||
}
|
||||
|
||||
*size = dstsize;
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------------------.
|
||||
| FUNCTION: ran3() |
|
||||
| From 'Numerical Recipies In C', Chapter 7, 'Portable Random Number Generators'. |
|
||||
`--------------------------------------------------------------------------------------*/
|
||||
float ran3(long* idnum)
|
||||
{
|
||||
static int inext, inextp;
|
||||
static long ma[66];
|
||||
static int iff = 0;
|
||||
long mj, mk;
|
||||
int i, ii, k;
|
||||
|
||||
|
||||
if( *idnum < 0 || iff == 0 )
|
||||
{
|
||||
iff = 1;
|
||||
mj = MSEED - (*idnum < 0 ? -*idnum : *idnum);
|
||||
mj %= MBIG;
|
||||
ma[55] = mj;
|
||||
mk = 1;
|
||||
for(i = 1; i <= 54; i++)
|
||||
{
|
||||
ii = (21*i) % 55;
|
||||
ma[ii] = mk;
|
||||
mk = mj - mk;
|
||||
if( mk < MZ ) mk += MBIG;
|
||||
mj = ma[ii];
|
||||
}
|
||||
for(k = 1; k <=4; k++)
|
||||
{
|
||||
for(i = 1; i <= 55; i++)
|
||||
{
|
||||
ma[i] -= ma[1+(i+30) % 55];
|
||||
if( ma[i] < MZ ) ma[i] += MBIG;
|
||||
}
|
||||
}
|
||||
inext = 0;
|
||||
inextp = 31;
|
||||
*idnum = 1;
|
||||
}
|
||||
if( ++inext == 56 ) inext = 1;
|
||||
if( ++inextp == 56 ) inextp = 1;
|
||||
mj = ma[inext] - ma[inextp];
|
||||
if( mj < MZ ) mj += MBIG;
|
||||
ma[inext] = mj;
|
||||
return (float) (mj*FAC );
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------.
|
||||
| FUNCTION: GenerateKey() |
|
||||
| Make a key the same length as the buffer. Gameres packets are typically |
|
||||
| < 600 bytes so period isn't a concern. |
|
||||
`------------------------------------------------------------------------------*/
|
||||
void GenerateKey(unsigned char* key, int len, long seed)
|
||||
{
|
||||
int i;
|
||||
float running;
|
||||
long num;
|
||||
|
||||
|
||||
if( seed > 0 ) seed *= -1; // Initial val must be negative
|
||||
running = ran3(&seed);
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
num = (long)(running * (float)255.0);
|
||||
if( num < 0 ) num *= -1;
|
||||
key[i] = (unsigned char)num;
|
||||
running = ran3(&seed);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------.
|
||||
| FUNCTON: SimpleEncrypt() |
|
||||
| Ok, not entirely simple but it's not bad. We generate the |
|
||||
| key, then prepare a new buffer which will contain the |
|
||||
| encrypted data. Byte 6 of the buffer is a random offset into |
|
||||
| bytes 10 - 256 which will contain the four byte seed value |
|
||||
| used to construct the key. |
|
||||
| If there is an error, the returned pointer will be NULL and |
|
||||
| the len value will be filled with a negative number |
|
||||
| indicating the error code. |
|
||||
`--------------------------------------------------------------*/
|
||||
unsigned char* SimpleEncrypt(const unsigned char* src, int* len)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char* key;
|
||||
unsigned char* dst;
|
||||
unsigned char offset = 0;
|
||||
long offsetseed = 0;
|
||||
unsigned long netseed;
|
||||
long seed;
|
||||
float limit;
|
||||
|
||||
|
||||
key = (unsigned char *) malloc( *len );
|
||||
|
||||
dst = (unsigned char *) malloc( (*len)+5 );
|
||||
|
||||
if( *len < 15 )
|
||||
{
|
||||
*len = -2;
|
||||
free( key );
|
||||
free( dst );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Generate the random stuff
|
||||
seed = (long)time(NULL);
|
||||
if( seed > 0 ) seed *= -1; // Don't check for seed == 0 because a ligit
|
||||
// packet builder should never set a seed of
|
||||
// 0 and it's another mistake a cracker could
|
||||
// possibly make.
|
||||
netseed = htonl((unsigned long)seed);
|
||||
GenerateKey(key, *len, seed);
|
||||
|
||||
// We want the offset to be somewhere between byte 10 and byte (255-14), or
|
||||
// (*len - 4), whichever is smaller
|
||||
offsetseed = (long)time(NULL);
|
||||
if( offsetseed > 0 ) offsetseed *= -1;
|
||||
limit = ((*len) < 241) ? (float)((*len)-14) : (float)241.0;
|
||||
offset = (unsigned char)(ran3(&offsetseed) * limit);
|
||||
offset += (unsigned char)10;
|
||||
|
||||
|
||||
// Construct the buffer
|
||||
for(i = 0, j = 0; i < *len; i++)
|
||||
{
|
||||
if( j == 5 )
|
||||
dst[j++] = offset;
|
||||
|
||||
if( j == (int)offset )
|
||||
{
|
||||
memcpy(&dst[j], &netseed, 4);
|
||||
j += 4;
|
||||
}
|
||||
|
||||
dst[j++] = src[i] ^ key[i];
|
||||
}
|
||||
|
||||
|
||||
*len += 5;
|
||||
free( key );
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------.
|
||||
| FUNCTON: SimpleDecrypt() |
|
||||
| We look for the offset, grab the seed, generate a key, then |
|
||||
| decrypt. |
|
||||
`--------------------------------------------------------------*/
|
||||
#ifndef __CLIENT__
|
||||
unsigned char* SimpleDecrypt(unsigned char* src, int* len)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char* key;
|
||||
unsigned char* dst;
|
||||
unsigned char offset = 0;
|
||||
unsigned long netseed;
|
||||
long seed;
|
||||
|
||||
|
||||
|
||||
key = malloc( *len );
|
||||
|
||||
dst = malloc((*len) - 5 );
|
||||
|
||||
|
||||
if( *len < 20 )
|
||||
{
|
||||
*len = -2;
|
||||
delete[] key;
|
||||
delete[] dst;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Generate the key
|
||||
offset = src[5];
|
||||
memcpy(&netseed, &src[offset], 4);
|
||||
seed = (long)ntohl(netseed);
|
||||
if( seed > 0 )
|
||||
{
|
||||
*len = -3;
|
||||
delete[] key;
|
||||
delete[] dst;
|
||||
return NULL;
|
||||
}
|
||||
GenerateKey(key, (*len)-5, seed);
|
||||
|
||||
|
||||
// Construct the buffer
|
||||
for(i = 0, j = 0; i < *len; i++)
|
||||
{
|
||||
if( i == 5 )
|
||||
continue;
|
||||
else if( i >= (int)offset && i <= (int)(offset+(unsigned char)3) )
|
||||
continue;
|
||||
else
|
||||
{
|
||||
dst[j] = src[i] ^ key[j];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*len -= 5;
|
||||
delete[] key;
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user