mirror of
https://github.com/jmarshall23/Hellfire.git
synced 2026-08-12 16:00:51 +02:00
318 lines
8.1 KiB
C++
318 lines
8.1 KiB
C++
//******************************************************************
|
|
// codec.cpp
|
|
//******************************************************************
|
|
|
|
|
|
#include "diablo.h"
|
|
#pragma hdrstop
|
|
#include "engine.h"
|
|
|
|
|
|
//******************************************************************
|
|
// externs
|
|
//******************************************************************
|
|
void DesDestroy ();
|
|
void DesEncrypt (int, const void *, void *);
|
|
void DesInitialize (int, BOOL, const void *);
|
|
void IdeaDestroy ();
|
|
void IdeaEncrypt (int, const void *, void *);
|
|
void IdeaInitialize (int, BOOL, const void *);
|
|
void ShaDestroy ();
|
|
void ShaGetLastHash (int, void *);
|
|
void ShaHash (int, const void *, void *);
|
|
void ShaInitialize (int);
|
|
|
|
|
|
//******************************************************************
|
|
// set encryption methods
|
|
//******************************************************************
|
|
#define IDEA 0
|
|
#define DES 0
|
|
|
|
|
|
//******************************************************************
|
|
// private
|
|
//******************************************************************
|
|
#define BLOCKSIZE 64
|
|
#define VERSION 0
|
|
|
|
typedef struct _appendrec {
|
|
DWORD checkvalue;
|
|
BYTE version;
|
|
BYTE lastblocksize;
|
|
WORD reserved;
|
|
} appendrec, *appendptr;
|
|
|
|
typedef struct _keyrec {
|
|
WORD ideakey[3][8];
|
|
BYTE deskey[3][8];
|
|
BYTE shainitvect[64];
|
|
} keyrec, *keyptr;
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void DestroyKeys () {
|
|
#if DES
|
|
DesDestroy();
|
|
#endif
|
|
#if IDEA
|
|
IdeaDestroy();
|
|
#endif
|
|
ShaDestroy();
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void InitializeKeys (BOOL encrypt, const char *password) {
|
|
keyrec keyset;
|
|
|
|
// generate a key
|
|
srand(SAVE_GAME_KEY);
|
|
BYTE * pb = (BYTE *) &keyset;
|
|
for (int i = sizeof(keyset); i--; )
|
|
*pb++ = (BYTE) rand();
|
|
|
|
// HASH THE PASSWORD AND MIX IT WITH THE KEY
|
|
{
|
|
BYTE originalpassword[64];
|
|
BYTE hashedpassword[20];
|
|
{
|
|
int passchar = 0;
|
|
for (int loop = 0; loop < 64; ++loop) {
|
|
if (!*(password+passchar))
|
|
passchar = 0;
|
|
originalpassword[loop] = *(password+passchar++);
|
|
}
|
|
}
|
|
|
|
ShaInitialize(0);
|
|
ShaHash(0,originalpassword,hashedpassword);
|
|
ShaDestroy();
|
|
|
|
{
|
|
LPBYTE keysptr = (LPBYTE)&keyset;
|
|
for (int loop = 0; loop < sizeof(keyset); ++loop)
|
|
*(keysptr+loop) ^= hashedpassword[loop % 20];
|
|
}
|
|
|
|
ZeroMemory(originalpassword, sizeof originalpassword);
|
|
ZeroMemory(hashedpassword, sizeof hashedpassword);
|
|
}
|
|
|
|
// INITIALIZE THE ENCRYPTION ALGORITHMS
|
|
for (int loop = 0; loop < 3; ++loop) {
|
|
#if DES
|
|
DesInitialize(loop,encrypt,keyset.deskey[loop]);
|
|
#endif
|
|
#if IDEA
|
|
IdeaInitialize(loop,encrypt,keyset.ideakey[loop]);
|
|
#endif
|
|
ShaInitialize(loop);
|
|
ShaHash(loop,keyset.shainitvect,NULL);
|
|
}
|
|
|
|
// WIPE OUT THE LOCAL COPY OF THE KEYS
|
|
ZeroMemory(&keyset,sizeof(keyrec));
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
DWORD DecodeFile(BYTE * pbSrcDst,DWORD dwDstBytes,const char * pszPassword) {
|
|
app_assert(pbSrcDst);
|
|
app_assert(pszPassword);
|
|
|
|
// initialize encryption keys
|
|
InitializeKeys(0,pszPassword);
|
|
|
|
// make sure the length is correct
|
|
if (dwDstBytes <= sizeof(appendrec)) return 0;
|
|
dwDstBytes -= sizeof(appendrec);
|
|
if (dwDstBytes & (BLOCKSIZE-1)) return 0;
|
|
DWORD dwBytesLeft = dwDstBytes;
|
|
|
|
// DECRYPT THE FILE BLOCK BY BLOCK
|
|
BYTE buffer[2][BLOCKSIZE];
|
|
while (dwBytesLeft) {
|
|
|
|
// get the next chunk
|
|
CopyMemory(&buffer[0][0],pbSrcDst,BLOCKSIZE);
|
|
|
|
// DECRYPT THE BLOCK
|
|
{
|
|
BYTE hash[20];
|
|
ShaGetLastHash(0,hash);
|
|
int loop;
|
|
|
|
#if IDEA
|
|
for (loop = 0; loop < BLOCKSIZE; loop += 8) {
|
|
IdeaEncrypt(2,&buffer[0][loop],&buffer[1][loop]);
|
|
IdeaEncrypt(1,&buffer[1][loop],&buffer[0][loop]);
|
|
IdeaEncrypt(0,&buffer[0][loop],&buffer[1][loop]);
|
|
}
|
|
for (loop = 0; loop < BLOCKSIZE; loop++)
|
|
buffer[0][loop] = buffer[1][loop]-hash[(BLOCKSIZE-(loop+1)) % 20];
|
|
#endif
|
|
|
|
#if DES
|
|
for (loop = 0; loop < BLOCKSIZE; loop += 8) {
|
|
DesEncrypt(2,&buffer[0][loop],&buffer[1][loop]);
|
|
DesEncrypt(1,&buffer[1][loop],&buffer[0][loop]);
|
|
DesEncrypt(0,&buffer[0][loop],&buffer[1][loop]);
|
|
}
|
|
for (loop = 0; loop < BLOCKSIZE; loop++)
|
|
buffer[0][loop] = hash[loop % 20] ^ buffer[1][loop];
|
|
#endif
|
|
|
|
#if ! DES && ! IDEA
|
|
for (loop = 0; loop < BLOCKSIZE; loop++)
|
|
buffer[0][loop] = hash[loop % 20] ^ buffer[0][loop];
|
|
#endif
|
|
|
|
ShaHash(0,buffer[0],NULL);
|
|
ZeroMemory(hash,sizeof(hash));
|
|
}
|
|
|
|
|
|
// WRITE THE BLOCK
|
|
CopyMemory(pbSrcDst,&buffer[0][0],BLOCKSIZE);
|
|
|
|
// next block
|
|
pbSrcDst += BLOCKSIZE;
|
|
dwBytesLeft -= BLOCKSIZE;
|
|
}
|
|
|
|
// hide buffer contents
|
|
ZeroMemory(buffer,sizeof(buffer));
|
|
|
|
// CHECK THE FILE TERMINATION RECORD
|
|
const appendrec * append = (const appendrec *) pbSrcDst;
|
|
|
|
// CHECK THE ENCRYPTION VERSION
|
|
if (append->version > VERSION)
|
|
goto error;
|
|
|
|
// CONFIRM THAT THE KEY AND PASSWORD WERE VALID
|
|
{
|
|
BYTE hash[20];
|
|
ShaGetLastHash(0,hash);
|
|
if (append->checkvalue != * (LPDWORD) &hash[0]) {
|
|
ZeroMemory(hash,20);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
// SET THE EXACT OUTPUT SIZE
|
|
dwDstBytes -= BLOCKSIZE - append->lastblocksize;
|
|
DestroyKeys();
|
|
return dwDstBytes;
|
|
|
|
error:
|
|
DestroyKeys();
|
|
return 0;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
// CalcEncodeDstBytes()
|
|
// -- calculate the number of bytes required to hold the encoded
|
|
// file information including the append record
|
|
//******************************************************************
|
|
DWORD CalcEncodeDstBytes(DWORD dwSrcBytes) {
|
|
app_assert(dwSrcBytes);
|
|
if (dwSrcBytes & (BLOCKSIZE-1))
|
|
dwSrcBytes += BLOCKSIZE - (dwSrcBytes & (BLOCKSIZE-1));
|
|
dwSrcBytes += sizeof(appendrec);
|
|
return dwSrcBytes;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void EncodeFile(BYTE * pbSrcDst,DWORD dwSrcBytes,DWORD dwDstBytes,const char * pszPassword) {
|
|
app_assert(pbSrcDst);
|
|
app_assert(pszPassword);
|
|
|
|
// make sure the user allocated enough bytes for the destination
|
|
if (dwDstBytes != CalcEncodeDstBytes(dwSrcBytes))
|
|
app_fatal("Invalid encode parameters");
|
|
|
|
// initialize encryption keys
|
|
InitializeKeys(1,pszPassword);
|
|
|
|
// ENCRYPT THE FILE BLOCK BY BLOCK
|
|
DWORD lastblocksize = 0;
|
|
BYTE buffer[2][BLOCKSIZE];
|
|
|
|
while (dwSrcBytes) {
|
|
|
|
// get the next src data chunk
|
|
DWORD blocksize = min(dwSrcBytes,BLOCKSIZE);
|
|
CopyMemory(&buffer[0][0],pbSrcDst,blocksize);
|
|
|
|
// blank out any unused portion of the buffer
|
|
if (blocksize < BLOCKSIZE)
|
|
ZeroMemory(&buffer[0][blocksize],BLOCKSIZE - blocksize);
|
|
|
|
// ENCRYPT THE BLOCK
|
|
{
|
|
BYTE hash[20];
|
|
ShaGetLastHash(0,hash);
|
|
ShaHash(0,buffer[0],NULL);
|
|
int loop;
|
|
|
|
#if ! DES && ! IDEA
|
|
for (loop = 0; loop < BLOCKSIZE; loop++)
|
|
buffer[0][loop] = hash[loop % 20] ^ buffer[0][loop];
|
|
#endif
|
|
|
|
#if DES
|
|
for (loop = 0; loop < BLOCKSIZE; loop++)
|
|
buffer[1][loop] = hash[loop % 20] ^ buffer[0][loop];
|
|
for (loop = 0; loop < BLOCKSIZE; loop += 8) {
|
|
DesEncrypt(0,&buffer[1][loop],&buffer[0][loop]);
|
|
DesEncrypt(1,&buffer[0][loop],&buffer[1][loop]);
|
|
DesEncrypt(2,&buffer[1][loop],&buffer[0][loop]);
|
|
}
|
|
#endif
|
|
|
|
#if IDEA
|
|
for (loop = 0; loop < BLOCKSIZE; loop++)
|
|
buffer[1][loop] = buffer[0][loop]+hash[(BLOCKSIZE-(loop+1)) % 20];
|
|
for (loop = 0; loop < BLOCKSIZE; loop += 8) {
|
|
IdeaEncrypt(0,&buffer[1][loop],&buffer[0][loop]);
|
|
IdeaEncrypt(1,&buffer[0][loop],&buffer[1][loop]);
|
|
IdeaEncrypt(2,&buffer[1][loop],&buffer[0][loop]);
|
|
}
|
|
#endif
|
|
|
|
// hide hash info
|
|
ZeroMemory(hash,sizeof(hash));
|
|
}
|
|
|
|
// write encrypted chunk to destination
|
|
CopyMemory(pbSrcDst,&buffer[0][0],BLOCKSIZE);
|
|
|
|
// next block
|
|
pbSrcDst += BLOCKSIZE;
|
|
dwSrcBytes -= blocksize;
|
|
lastblocksize = blocksize;
|
|
}
|
|
|
|
// hide buffer
|
|
ZeroMemory(buffer,sizeof(buffer));
|
|
|
|
// APPEND THE TERMINATION RECORD
|
|
BYTE hash[20];
|
|
appendrec * append = (appendrec *) pbSrcDst;
|
|
ShaGetLastHash(0,hash);
|
|
append->checkvalue = * (LPDWORD) &hash[0];
|
|
append->version = VERSION;
|
|
append->lastblocksize = (BYTE) lastblocksize;
|
|
append->reserved = 0;
|
|
|
|
DestroyKeys();
|
|
}
|