CnC_Remastered_Collection/REDALERT/PKSTRAW.CPP
PG-SteveT 03416d24e1 Initial Source Code commit
Initial commit of original Tiberian Dawn and Red Alert source code converted to build as DLLs, and compatible with the release version of Command & Conquer Remastered.
2020-05-27 12:16:20 -07:00

302 lines
17 KiB
C++

//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding 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 3 of the License, or (at your option) any later version.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/* $Header: /CounterStrike/PKSTRAW.CPP 1 3/03/97 10:25a Joe_bostic $ */
/***********************************************************************************************
*** 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 : Command & Conquer *
* *
* File Name : PKSTRAW.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/08/96 *
* *
* Last Update : July 11, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* PKStraw::Encrypted_Key_Length -- Fetch the encrypted key length. *
* PKStraw::Get -- Fetch data and process it accordingly. *
* PKStraw::Get_From -- Chains one straw to another. *
* PKStraw::Key -- Assign a key to the cipher process straw. *
* PKStraw::PKStraw -- Initialize the public key straw object. *
* PKStraw::Plain_Key_Length -- Returns the number of bytes to encrypt key. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "pkstraw.h"
#include "rndstraw.h"
#include "blwstraw.h"
/***********************************************************************************************
* PKStraw::PKStraw -- Initialize the public key straw object. *
* *
* This constructs the public key straw object. The operation to perform (encrypt or *
* decrypt) as well as a random number generator must be provided. *
* *
* INPUT: control -- What operation to perform on the data. Pass in either ENCRYPT or *
* DECRYPT. *
* *
* rnd -- Reference to a random number straw that is used internally to *
* generate the sub-key. The final strength of the cipher depends on *
* quality of this random number generator. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/11/1996 JLB : Created. *
*=============================================================================================*/
PKStraw::PKStraw(CryptControl control, RandomStraw & rnd) :
IsGettingKey(true),
Rand(rnd),
BF((control == ENCRYPT) ? BlowStraw::ENCRYPT : BlowStraw::DECRYPT),
Control(control),
CipherKey(NULL),
Counter(0),
BytesLeft(0)
{
Straw::Get_From(BF);
}
/***********************************************************************************************
* PKStraw::Get_From -- Chains one straw to another. *
* *
* This routine handles the special case of this straw object in that there is an *
* embedded blowfish straw segment. It must be chained on correctly. *
* *
* INPUT: straw -- Pointer to the straw segment that this segment is to receive data from. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/11/1996 JLB : Created. *
*=============================================================================================*/
void PKStraw::Get_From(Straw * straw)
{
if (BF.ChainTo != straw) {
if (straw != NULL && straw->ChainFrom != NULL) {
straw->ChainFrom->Get_From(NULL);
straw->ChainFrom = NULL;
}
if (BF.ChainTo != NULL) {
BF.ChainTo->ChainFrom = NULL;
}
BF.ChainTo = straw;
BF.ChainFrom = this;
ChainTo = &BF;
if (BF.ChainTo != NULL) {
BF.ChainTo->ChainFrom = this;
}
}
}
/***********************************************************************************************
* PKStraw::Key -- Assign a key to the cipher process straw. *
* *
* This routine will assign the key (or NULL if the current key is to be removed) to the *
* cipher stream process. When a key has been assigned, encryption or decryption will *
* take place. In the absence (NULL key pointer) of a key, the data passes through *
* unchanged. *
* *
* INPUT: key -- Pointer to the key to assign to the stream. If the key pointer is NULL, *
* then this causes the cipher stream to stop processing the data and will *
* pass the data through unchanged. *
* *
* OUTPUT: none *
* *
* WARNINGS: Be sure that the key passed to this routine is the opposite key to that used *
* to process the stream originally (when decrypting). *
* *
* HISTORY: *
* 07/08/1996 JLB : Created. *
*=============================================================================================*/
void PKStraw::Key(PKey const * key)
{
CipherKey = key;
if (key != NULL) {
IsGettingKey = true;
}
Counter = 0;
BytesLeft = 0;
}
/***********************************************************************************************
* PKStraw::Get -- Fetch data and process it accordingly. *
* *
* This routine will fetch the number of bytes requested. If a valid key has been assigned *
* to this stream, then the data will be processed as it passes through. *
* *
* INPUT: source -- Pointer to the buffer that will hold the requested data. *
* *
* length -- The number of data bytes requested. *
* *
* OUTPUT: Returns with the actual number of data bytes stored to the destination buffer. If *
* this number is less than that requested, then it indicates that the data source *
* has been exhausted. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1996 JLB : Created. *
*=============================================================================================*/
int PKStraw::Get(void * source, int length)
{
/*
** If the parameters seem invalid, then pass the request on so that someone
** else can deal with it.
*/
if (source == NULL || length < 1 || CipherKey == NULL) {
return(Straw::Get(source, length));
}
int total = 0;
/*
** The first part of the data flow must process the special key. After the special
** key has been processed, the data flows through this straw without direct
** modification (the blowfish straw will process the data).
*/
if (IsGettingKey) {
if (Control == DECRYPT) {
/*
** Retrieve the pk encrypted blowfish key block.
*/
char cbuffer[MAX_KEY_BLOCK_SIZE];
int got = Straw::Get(cbuffer, Encrypted_Key_Length());
/*
** If the entire key block could not be retrieved, then this indicates
** a major data flow error -- just return with no action performed.
*/
if (got != Encrypted_Key_Length()) return(0);
/*
** Decrypt the blowfish key and then activate the blowfish straw
** with that key.
*/
CipherKey->Decrypt(cbuffer, got, Buffer);
BF.Key(Buffer, BLOWFISH_KEY_SIZE);
} else {
/*
** Generate the blowfish key by using random numbers.
*/
char buffer[MAX_KEY_BLOCK_SIZE];
memset(buffer, '\0', sizeof(buffer));
Rand.Get(buffer, BLOWFISH_KEY_SIZE);
/*
** Encrypt the blowfish key (along with any necessary pad bytes).
*/
Counter = BytesLeft = CipherKey->Encrypt(buffer, Plain_Key_Length(), Buffer);
BF.Key(buffer, BLOWFISH_KEY_SIZE);
}
/*
** The first phase of getting the special key has been accomplished. Now, all
** subsequent data is passed (unmodified) though this straw segment. The blowfish
** straw takes over the compression/decompression from this point forward.
*/
IsGettingKey = false;
}
/*
** If there are any pending bytes in the buffer, then pass
** these on first. The only time this should be is when the blowfish
** key has first been generated.
*/
if (BytesLeft > 0) {
int tocopy = (length < BytesLeft) ? length : BytesLeft;
memmove(source, &Buffer[Counter-BytesLeft], tocopy);
source = (char *)source + tocopy;
BytesLeft -= tocopy;
length -= tocopy;
total += tocopy;
}
/*
** Any requested bytes that haven't been satisfied are copied over now by
** drawing the data through the blowfish engine. The blowfish engine happens
** to be linked to the chain so a normal Get() operation is sufficient.
*/
total += Straw::Get(source, length);
return(total);
}
/***********************************************************************************************
* PKStraw::Encrypted_Key_Length -- Fetch the encrypted key length. *
* *
* This returns the total number of bytes (after encryption) that the blowfish key will *
* consume. It should be possible to get a block of this size, then pass it to the *
* public key decrypter and the result will be the full blowfish key. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the number of bytes that the encrypted blowfish key required. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/11/1996 JLB : Created. *
*=============================================================================================*/
int PKStraw::Encrypted_Key_Length(void) const
{
if (CipherKey == NULL) return(0);
return(CipherKey->Block_Count(BLOWFISH_KEY_SIZE) * CipherKey->Crypt_Block_Size());
}
/***********************************************************************************************
* PKStraw::Plain_Key_Length -- Returns the number of bytes to encrypt key. *
* *
* This is the number of plain (unencrypted) bytes that the blowfish key will take up. This *
* is actually the number of plain blocks minimum that can contain the full blowfish *
* key. The public key cryptography system encrypts in whole blocks only. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the total number of bytes that will contain the full blowfish key *
* and still be an even block size for the public key cryptography process. *
* *
* WARNINGS: This value is probably be larger than the actual blowfish key length. *
* *
* HISTORY: *
* 07/11/1996 JLB : Created. *
*=============================================================================================*/
int PKStraw::Plain_Key_Length(void) const
{
if (CipherKey == NULL) return(0);
return(CipherKey->Block_Count(BLOWFISH_KEY_SIZE) * CipherKey->Plain_Block_Size());
}