// // 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 //#include #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 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]; }