CnC_Remastered_Collection/REDALERT/PK.CPP

361 lines
21 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/PK.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 : PK.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/04/96 *
* *
* Last Update : July 10, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* PKey::Decode_Exponent -- Decodes the exponent back into the key. *
* PKey::Decode_Modulus -- Decodes the modulus value back into the key. *
* PKey::Decrypt -- Decrypt supplied cyphertext into its original plaintext. *
* PKey::Encode_Exponent -- Encode the exponent portion of the key into a buffer. *
* PKey::Encode_Modulus -- Encode the modulus portion of the key. *
* PKey::Encrypt -- Encrypt blocks of plaintext. *
* PKey::Generate -- Generate a public and private key. *
* PKey::PKey -- Construct a key using encoded strings. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "pk.h"
#include "rndstraw.h"
/***********************************************************************************************
* PKey::PKey -- Construct a key using encoded strings. *
* *
* This constructor will construct a key based on the encoded strings supplied. *
* *
* INPUT: exponent -- The encoded string for the exponent portion of the key. *
* *
* modulus -- The encoded string for the modulus portion of the key. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1996 JLB : Created. *
*=============================================================================================*/
PKey::PKey(void const * exponent, void const * modulus)
{
Modulus.DERDecode((unsigned char *)modulus);
Exponent.DERDecode((unsigned char *)exponent);
BitPrecision = Modulus.BitCount()-1;
}
/***********************************************************************************************
* PKey::Encode_Modulus -- Encode the modulus portion of the key. *
* *
* This will store the modulus portion of the key into a buffer. The number of bytes *
* stored into the buffer depends on the value of the key. *
* *
* INPUT: buffer -- Pointer to the buffer that will hold the encoded modulus value. *
* *
* OUTPUT: Returns with the number of bytes stored to the buffer. *
* *
* WARNINGS: Be sure that the buffer can hold the encoded bytes. This is normally around the *
* same size as the Crypt_Block_Size() (plus a byte or two). *
* *
* HISTORY: *
* 07/08/1996 JLB : Created. *
*=============================================================================================*/
int PKey::Encode_Modulus(void * buffer) const
{
if (buffer == NULL) {
return(0);
}
return(Modulus.DEREncode((unsigned char *)buffer));
}
/***********************************************************************************************
* PKey::Encode_Exponent -- Encode the exponent portion of the key into a buffer. *
* *
* This routine will encode the exponent portion of the key. This is only necessary for the *
* slow key since the fast key always has an exponent of 65537. *
* *
* INPUT: buffer -- Pointer to the buffer that will be filled with the encoded exponent. *
* *
* OUTPUT: Returns with the nuber of bytes stored into the buffer. *
* *
* WARNINGS: Be sure the buffer is big enough to hold the encoded exponent. Usually this is *
* about the same size as the Crypt_Block_Size (plus a byte or two). *
* *
* HISTORY: *
* 07/08/1996 JLB : Created. *
*=============================================================================================*/
int PKey::Encode_Exponent(void * buffer) const
{
if (buffer == NULL) {
return(0);
}
return(Exponent.DEREncode((unsigned char *)buffer));
}
/***********************************************************************************************
* PKey::Decode_Modulus -- Decodes the modulus value back into the key. *
* *
* This is the counterpart to the Encode_Modulus() function. It will initialize the *
* modulus portion of the key with the encoded data supplied. *
* *
* INPUT: buffer -- Pointer to the buffer that holds the previously encoded modulus value. *
* *
* OUTPUT: void *
* *
* WARNINGS: void *
* *
* HISTORY: *
* 07/08/1996 JLB : Created. *
*=============================================================================================*/
void PKey::Decode_Modulus(void * buffer)
{
Modulus.DERDecode((unsigned char *)buffer);
BitPrecision = Modulus.BitCount()-1;
}
/***********************************************************************************************
* PKey::Decode_Exponent -- Decodes the exponent back into the key. *
* *
* This is the counterpart to the Encode_Exponent function. It will decode a previously *
* encoded exponent portion back into the key. *
* *
* INPUT: buffer -- Pointer to the buffer that holds the encoded exponent value. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1996 JLB : Created. *
*=============================================================================================*/
void PKey::Decode_Exponent(void * buffer)
{
Exponent.DERDecode((unsigned char *)buffer);
}
/***********************************************************************************************
* PKey::Generate -- Generate a public and private key. *
* *
* Public key cryptography relies on having two paired keys. The key used to encrypt *
* data must be decrypted by using the other key. Which key designated as the public or *
* private key is arbitrary. However, one is faster than the other. Use the faster key for *
* the more common operation. *
* *
* INPUT: random -- Reference to a source of random data. *
* *
* bits -- The number of bits to use for key generation. Use a number greater *
* than 16 but less than 2048. The ideal bit size is one that is evenly *
* divisible by 8 and then add one. Practical numbers range from 65 to *
* 1025 bits. *
* *
* fastkey -- Reference to the key that has fast encryption/decryption properties. *
* *
* slowkey -- Reference to the mate key of the other. *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine can take a very long time. It can take MINUTES to generate a *
* 1024 bit key (even on a Pentium Pro 200Mghz machine). *
* *
* HISTORY: *
* 07/05/1996 JLB : Created. *
* 07/10/1996 JLB : Must supply source of random data. *
*=============================================================================================*/
void PKey::Generate(Straw & random, int bits, PKey & fastkey, PKey & slowkey)
{
//PG_TO_FIX
fastkey;
slowkey;
#if (0)
/*
** Key generation consists of create a key pair and then testing the key
** pair. If the test fails, then repeat the process. The test and repeat
** method is required since the prime number generating process can't
** guarantee the generation of a prime number -- it can only generate a
** highly likely prime number.
*/
for (;;) {
/*
** Generate the two random prime numbers. This is the longest
** step.
*/
BigInt p = Generate_Prime(random, bits, &p);
BigInt q = Generate_Prime(random, bits, &q);
/*
** The exponent factors are easy to calculate from the prime numbers.
*/
BigInt e = Fast_Exponent();
BigInt n = p * q;
BigInt pqmin = (p-(unsigned short)1)*(q-(unsigned short)1);
BigInt d = e.Inverse(pqmin);
/*
** Store the data into the key objects. Notice that the modulus is the
** same for both the fast and slow keys. Also notice that the exponent for
** the fast key is ALWAYS 65537. Given this, it is possible to economize the
** fast key into being just the modulus and the slow key to being just the
** exponent (presuming the slow key also has access to the fast key so that
** it can get the modulus).
*/
fastkey.Exponent = e;
fastkey.Modulus = n;
fastkey.BitPrecision = n.BitCount()-1;
slowkey.Exponent = d;
slowkey.Modulus = n;
slowkey.BitPrecision = fastkey.BitPrecision;
/*
** Test the keys by encrypting a block of random bytes. If it decrypts
** correctly, then a valid key pair has been generated -- bail.
*/
char before[256];
char after[256];
for (int index = 0; index < fastkey.Plain_Block_Size(); index++) {
before[index] = (char)rand();
}
fastkey.Encrypt(before, fastkey.Plain_Block_Size(), after);
slowkey.Decrypt(after, slowkey.Crypt_Block_Size(), after);
/*
** Compare the pre and post processing buffer. A match indicates
** a valid key pair.
*/
if (memcmp(before, after, fastkey.Plain_Block_Size()) == 0) break;
}
#endif
}
/***********************************************************************************************
* PKey::Encrypt -- Encrypt blocks of plaintext. *
* *
* This routine will encrypt the supplied plaintext into cyphertext by processing the input *
* in block. The source is processed in whole blocks. Partial blocks are not supported by *
* public key cryptography. *
* *
* INPUT: source -- Pointer to the source plaintext that will be encrypted. *
* *
* length -- The length of the plaintext to encrypt. *
* *
* dest -- Pointer to the buffer that will hold the encrypted data. *
* *
* OUTPUT: Returns with the number of cypher text bytes placed into the destination buffer. *
* *
* WARNINGS: Be sure that the destination buffer is big enough to hold the output. *
* *
* HISTORY: *
* 07/05/1996 JLB : Created. *
*=============================================================================================*/
int PKey::Encrypt(void const * source, int slen, void * dest) const
{
int total = 0;
/*
** Encrypt the source data in full blocks. Partial blocks are not processed and are not
** copied to the destination buffer.
*/
while (slen >= Plain_Block_Size()) {
/*
** Perform the encryption of the block.
*/
BigInt temp = 0;
memmove(&temp, source, Plain_Block_Size());
temp = temp.exp_b_mod_c(Exponent, Modulus);
/*
** Move the cypher block to the destination.
*/
memmove(dest, &temp, Crypt_Block_Size());
slen -= Plain_Block_Size();
source = (char *)source + Plain_Block_Size();
dest = (char *)dest + Crypt_Block_Size();
total += Crypt_Block_Size();
}
return(total);
}
/***********************************************************************************************
* PKey::Decrypt -- Decrypt supplied cyphertext into its original plaintext. *
* *
* This routine will process the supplied cyphertext by breaking it up into blocks and *
* then decrypting each block in turn. The block size is dependant upon the key. By NOT *
* embedding this information into the cypher data, it makes the encryption more secure. *
* *
* INPUT: source -- Pointer to the cypher text to be decrypted. *
* *
* length -- The number of cypher text bytes supplied to this routine. *
* *
* dest -- Pointer to the buffer to hold the plaintext. *
* *
* OUTPUT: Returns with the number of plaintext bytes output to the destination buffer. *
* *
* WARNINGS: Only whole blocks are processed. If the source has any partial block sized *
* data, then it will be left unprocessed. *
* *
* HISTORY: *
* 07/05/1996 JLB : Created. *
*=============================================================================================*/
int PKey::Decrypt(void const * source, int slen, void * dest) const
{
int total = 0;
BigInt temp;
/*
** Decrypt the source data in full blocks. Partial blocks are not processed in any way.
*/
while (slen >= Crypt_Block_Size()) {
/*
** Perform the encryption.
*/
temp = 0;
memmove(&temp, source, Crypt_Block_Size());
temp = temp.exp_b_mod_c(Exponent, Modulus);
/*
** Move the cypher block to the destination.
*/
memmove(dest, &temp, Plain_Block_Size());
slen -= Crypt_Block_Size();
source = (char *)source + Crypt_Block_Size();
dest = (char *)dest + Plain_Block_Size();
total += Plain_Block_Size();
}
return(total);
}