315 lines
16 KiB
C++
315 lines
16 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/SHA.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 : SHA.CPP *
|
|
* *
|
|
* Programmer : Joe L. Bostic *
|
|
* *
|
|
* Start Date : 07/03/96 *
|
|
* *
|
|
* Last Update : July 3, 1996 [JLB] *
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* SHAEngine::Result -- Fetch the current digest. *
|
|
* SHAEngine::Hash -- Process an arbitrarily long data block. *
|
|
* SHAEngine::Process_Partial -- Helper routine to process any partially accumulated data blo*
|
|
* SHAEngine::Process_Block -- Process a full data block into the hash accumulator. *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include <stdlib.h>
|
|
//#include <iostream.h>
|
|
#include "sha.h"
|
|
|
|
|
|
|
|
#if !defined(__BORLANDC__) && !defined(min)
|
|
#define min(a, b) ((a)<(b))?(a):(b)
|
|
#endif
|
|
|
|
|
|
/***********************************************************************************************
|
|
* SHAEngine::Process_Partial -- Helper routine to process any partially accumulated data bloc *
|
|
* *
|
|
* This routine will see if there is a partial block already accumulated in the holding *
|
|
* buffer. If so, then the data is fetched from the source such that a full buffer is *
|
|
* accumulated and then processed. If there is insufficient data to fill the buffer, then *
|
|
* it accumulates what data it can and then returns so that this routine can be called *
|
|
* again later. *
|
|
* *
|
|
* INPUT: data -- Reference to a pointer to the data. This pointer will be modified if *
|
|
* this routine consumes any of the data in the buffer. *
|
|
* *
|
|
* length-- Reference to the length of the data available. If this routine consumes *
|
|
* any of the data, then this length value will be modified. *
|
|
* *
|
|
* OUTPUT: none *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/03/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
void SHAEngine::Process_Partial(void const * & data, long & length)
|
|
{
|
|
if (length == 0 || data == NULL) return;
|
|
|
|
/*
|
|
** If there is no partial buffer and the source is greater than
|
|
** a source block size, then partial processing is unnecessary.
|
|
** Bail out in this case.
|
|
*/
|
|
if (PartialCount == 0 && length >= SRC_BLOCK_SIZE) return;
|
|
|
|
/*
|
|
** Attach as many bytes as possible from the source data into
|
|
** the staging buffer.
|
|
*/
|
|
int add_count = min((int)length, SRC_BLOCK_SIZE - PartialCount);
|
|
memcpy(&Partial[PartialCount], data, add_count);
|
|
data = ((char const *&)data) + add_count;
|
|
PartialCount += add_count;
|
|
length -= add_count;
|
|
|
|
/*
|
|
** If a full staging buffer has been accumulated, then process
|
|
** the staging buffer and then bail.
|
|
*/
|
|
if (PartialCount == SRC_BLOCK_SIZE) {
|
|
Process_Block(&Partial[0], Acc);
|
|
Length += (long)SRC_BLOCK_SIZE;
|
|
PartialCount = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* SHAEngine::Hash -- Process an arbitrarily long data block. *
|
|
* *
|
|
* This is the main access routine to the SHA engine. It will take the arbitrarily long *
|
|
* data block and process it. The hash value is accumulated with any previous calls to *
|
|
* this routine. *
|
|
* *
|
|
* INPUT: data -- Pointer to the data block to process. *
|
|
* *
|
|
* length -- The number of bytes to process. *
|
|
* *
|
|
* OUTPUT: none *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/03/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
void SHAEngine::Hash(void const * data, long length)
|
|
{
|
|
IsCached = false;
|
|
|
|
/*
|
|
** Check for and handle any smaller-than-512bit blocks. This can
|
|
** result in all of the source data submitted to this routine to be
|
|
** consumed at this point.
|
|
*/
|
|
Process_Partial(data, length);
|
|
|
|
/*
|
|
** If there is no more source data to process, then bail. Speed reasons.
|
|
*/
|
|
if (length == 0) return;
|
|
|
|
/*
|
|
** First process all the whole blocks available in the source data.
|
|
*/
|
|
long blocks = (length / SRC_BLOCK_SIZE);
|
|
long const * source = (long const *)data;
|
|
for (int bcount = 0; bcount < blocks; bcount++) {
|
|
Process_Block(source, Acc);
|
|
Length += (long)SRC_BLOCK_SIZE;
|
|
source += SRC_BLOCK_SIZE/sizeof(long);
|
|
length -= (long)SRC_BLOCK_SIZE;
|
|
}
|
|
|
|
/*
|
|
** Process any remainder bytes. This data is stored in the source
|
|
** accumulator buffer for future processing.
|
|
*/
|
|
data = source;
|
|
Process_Partial(data, length);
|
|
}
|
|
|
|
|
|
#define Reverse_LONG(a) ((a>>24)&0x000000FFL) | ((a>>8)&0x0000FF00L) | ((a<<8)&0x00FF0000L) | ((a<<24)&0xFF000000L)
|
|
|
|
|
|
/***********************************************************************************************
|
|
* SHAEngine::Result -- Fetch the current digest. *
|
|
* *
|
|
* This routine will return the digest as it currently stands. *
|
|
* *
|
|
* INPUT: pointer -- Pointer to the buffer that will hold the digest -- 20 bytes. *
|
|
* *
|
|
* OUTPUT: Returns with the number of bytes copied into the buffer. This will always be *
|
|
* 20. *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/03/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
int SHAEngine::Result(void * result) const
|
|
{
|
|
/*
|
|
** If the final hash result has already been calculated for the
|
|
** current data state, then immediately return with the precalculated
|
|
** value.
|
|
*/
|
|
if (IsCached) {
|
|
memcpy(result, &FinalResult, sizeof(FinalResult));
|
|
}
|
|
|
|
long length = Length + PartialCount;
|
|
int partialcount = PartialCount;
|
|
char partial[SRC_BLOCK_SIZE];
|
|
memcpy(partial, Partial, sizeof(Partial));
|
|
|
|
/*
|
|
** Cap the end of the source data stream with a 1 bit.
|
|
*/
|
|
partial[partialcount] = (char)0x80;
|
|
|
|
/*
|
|
** Determine if there is insufficient room to append the
|
|
** data length number to the hash source. If not, then
|
|
** fill out the rest of the accumulator and flush it to
|
|
** the hash so that there will be room for the final
|
|
** count value.
|
|
*/
|
|
SHADigest acc = Acc;
|
|
if ((SRC_BLOCK_SIZE - partialcount) < 9) {
|
|
if (partialcount+1 < SRC_BLOCK_SIZE) {
|
|
memset(&partial[partialcount+1], '\0', SRC_BLOCK_SIZE - (partialcount+1));
|
|
}
|
|
Process_Block(&partial[0], acc);
|
|
partialcount = 0;
|
|
} else {
|
|
partialcount++;
|
|
}
|
|
|
|
/*
|
|
** Put the length of the source data as a 64 bit integer in the
|
|
** last 8 bytes of the pseudo-source data.
|
|
*/
|
|
memset(&partial[partialcount], '\0', SRC_BLOCK_SIZE - partialcount);
|
|
*(long *)(&partial[SRC_BLOCK_SIZE-4]) = Reverse_LONG((length*8));
|
|
Process_Block(&partial[0], acc);
|
|
|
|
memcpy((char *)&FinalResult, &acc, sizeof(acc));
|
|
for (int index = 0; index < sizeof(FinalResult)/sizeof(long); index++) {
|
|
// for (int index = 0; index < SRC_BLOCK_SIZE/sizeof(long); index++) {
|
|
(long &)FinalResult.Long[index] = Reverse_LONG(FinalResult.Long[index]);
|
|
}
|
|
(bool&)IsCached = true;
|
|
memcpy(result, &FinalResult, sizeof(FinalResult));
|
|
return(sizeof(FinalResult));
|
|
}
|
|
|
|
/*
|
|
** This pragma to turn off the warning "Conversion may lose significant digits" is to
|
|
** work around a bug within the Borland compiler. It will give this warning when the
|
|
** _rotl() function is called but will NOT give the warning when the _lrotl() function
|
|
** is called even though they both have the same parameters and declaration attributes.
|
|
*/
|
|
//#pragma warn -sig
|
|
template<class T>
|
|
T _rotl(T X, int n)
|
|
{
|
|
return(T)( ( X << n ) | ( (unsigned)X >> ((sizeof(T)*8) - n) ) );
|
|
}
|
|
//unsigned long _RTLENTRY _rotl(unsigned long X, int n)
|
|
//{
|
|
// return(unsigned long)( (unsigned long)( (unsigned long)( (unsigned long)X ) << (int)n ) | (unsigned long)( ((unsigned long) X ) >> ( (int)((int)(sizeof(long)*(long)8) - (long)n) ) ) );
|
|
//}
|
|
void memrev(char * buffer, size_t length);
|
|
|
|
|
|
/***********************************************************************************************
|
|
* SHAEngine::Process_Block -- Process a full data block into the hash accumulator. *
|
|
* *
|
|
* This helper routine is called when a full block of data is available for processing *
|
|
* into the hash. *
|
|
* *
|
|
* INPUT: source -- Pointer to the block of data to process. *
|
|
* *
|
|
* acc -- Reference to the hash accumulator that this hash step will be *
|
|
* accumulated into. *
|
|
* *
|
|
* OUTPUT: none *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/03/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
void SHAEngine::Process_Block(void const * source, SHADigest & acc) const
|
|
{
|
|
/*
|
|
** The hash is generated by performing operations on a
|
|
** block of generated/seeded data.
|
|
*/
|
|
long block[PROC_BLOCK_SIZE/sizeof(long)];
|
|
|
|
/*
|
|
** Expand the source data into a large 80 * 32bit buffer. This is the working
|
|
** data that will be transformed by the secure hash algorithm.
|
|
*/
|
|
long const * data = (long const *)source;
|
|
int index;
|
|
for (index = 0; index < SRC_BLOCK_SIZE/sizeof(long); index++) {
|
|
block[index] = Reverse_LONG(data[index]);
|
|
}
|
|
|
|
for (index = SRC_BLOCK_SIZE/sizeof(long); index < PROC_BLOCK_SIZE/sizeof(long); index++) {
|
|
// block[index] = _rotl(block[(index-3)&15] ^ block[(index-8)&15] ^ block[(index-14)&15] ^ block[(index-16)&15], 1);
|
|
block[index] = _rotl(block[index-3] ^ block[index-8] ^ block[index-14] ^ block[index-16], 1);
|
|
}
|
|
|
|
/*
|
|
** This is the core algorithm of the Secure Hash Algorithm. It is a block
|
|
** transformation of 512 bit source data with a 2560 bit intermediate buffer.
|
|
*/
|
|
SHADigest alt = acc;
|
|
for (index = 0; index < PROC_BLOCK_SIZE/sizeof(long); index++) {
|
|
long temp = _rotl(alt.Long[0], 5) + Do_Function(index, alt.Long[1], alt.Long[2], alt.Long[3]) + alt.Long[4] + block[index] + Get_Constant(index);
|
|
alt.Long[4] = alt.Long[3];
|
|
alt.Long[3] = alt.Long[2];
|
|
alt.Long[2] = _rotl(alt.Long[1], 30);
|
|
alt.Long[1] = alt.Long[0];
|
|
alt.Long[0] = temp;
|
|
}
|
|
acc.Long[0] += alt.Long[0];
|
|
acc.Long[1] += alt.Long[1];
|
|
acc.Long[2] += alt.Long[2];
|
|
acc.Long[3] += alt.Long[3];
|
|
acc.Long[4] += alt.Long[4];
|
|
}
|
|
|