SHA.CPP (16166B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /* $Header: /CounterStrike/SHA.CPP 1 3/03/97 10:25a Joe_bostic $ */ 17 /*********************************************************************************************** 18 *** 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 *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Command & Conquer * 22 * * 23 * File Name : SHA.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : 07/03/96 * 28 * * 29 * Last Update : July 3, 1996 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * SHAEngine::Result -- Fetch the current digest. * 34 * SHAEngine::Hash -- Process an arbitrarily long data block. * 35 * SHAEngine::Process_Partial -- Helper routine to process any partially accumulated data blo* 36 * SHAEngine::Process_Block -- Process a full data block into the hash accumulator. * 37 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 38 39 #include <stdlib.h> 40 //#include <iostream.h> 41 #include "sha.h" 42 43 44 45 #if !defined(__BORLANDC__) && !defined(min) 46 #define min(a, b) ((a)<(b))?(a):(b) 47 #endif 48 49 50 /*********************************************************************************************** 51 * SHAEngine::Process_Partial -- Helper routine to process any partially accumulated data bloc * 52 * * 53 * This routine will see if there is a partial block already accumulated in the holding * 54 * buffer. If so, then the data is fetched from the source such that a full buffer is * 55 * accumulated and then processed. If there is insufficient data to fill the buffer, then * 56 * it accumulates what data it can and then returns so that this routine can be called * 57 * again later. * 58 * * 59 * INPUT: data -- Reference to a pointer to the data. This pointer will be modified if * 60 * this routine consumes any of the data in the buffer. * 61 * * 62 * length-- Reference to the length of the data available. If this routine consumes * 63 * any of the data, then this length value will be modified. * 64 * * 65 * OUTPUT: none * 66 * * 67 * WARNINGS: none * 68 * * 69 * HISTORY: * 70 * 07/03/1996 JLB : Created. * 71 *=============================================================================================*/ 72 void SHAEngine::Process_Partial(void const * & data, long & length) 73 { 74 if (length == 0 || data == NULL) return; 75 76 /* 77 ** If there is no partial buffer and the source is greater than 78 ** a source block size, then partial processing is unnecessary. 79 ** Bail out in this case. 80 */ 81 if (PartialCount == 0 && length >= SRC_BLOCK_SIZE) return; 82 83 /* 84 ** Attach as many bytes as possible from the source data into 85 ** the staging buffer. 86 */ 87 int add_count = min((int)length, SRC_BLOCK_SIZE - PartialCount); 88 memcpy(&Partial[PartialCount], data, add_count); 89 data = ((char const *&)data) + add_count; 90 PartialCount += add_count; 91 length -= add_count; 92 93 /* 94 ** If a full staging buffer has been accumulated, then process 95 ** the staging buffer and then bail. 96 */ 97 if (PartialCount == SRC_BLOCK_SIZE) { 98 Process_Block(&Partial[0], Acc); 99 Length += (long)SRC_BLOCK_SIZE; 100 PartialCount = 0; 101 } 102 } 103 104 105 /*********************************************************************************************** 106 * SHAEngine::Hash -- Process an arbitrarily long data block. * 107 * * 108 * This is the main access routine to the SHA engine. It will take the arbitrarily long * 109 * data block and process it. The hash value is accumulated with any previous calls to * 110 * this routine. * 111 * * 112 * INPUT: data -- Pointer to the data block to process. * 113 * * 114 * length -- The number of bytes to process. * 115 * * 116 * OUTPUT: none * 117 * * 118 * WARNINGS: none * 119 * * 120 * HISTORY: * 121 * 07/03/1996 JLB : Created. * 122 *=============================================================================================*/ 123 void SHAEngine::Hash(void const * data, long length) 124 { 125 IsCached = false; 126 127 /* 128 ** Check for and handle any smaller-than-512bit blocks. This can 129 ** result in all of the source data submitted to this routine to be 130 ** consumed at this point. 131 */ 132 Process_Partial(data, length); 133 134 /* 135 ** If there is no more source data to process, then bail. Speed reasons. 136 */ 137 if (length == 0) return; 138 139 /* 140 ** First process all the whole blocks available in the source data. 141 */ 142 long blocks = (length / SRC_BLOCK_SIZE); 143 long const * source = (long const *)data; 144 for (int bcount = 0; bcount < blocks; bcount++) { 145 Process_Block(source, Acc); 146 Length += (long)SRC_BLOCK_SIZE; 147 source += SRC_BLOCK_SIZE/sizeof(long); 148 length -= (long)SRC_BLOCK_SIZE; 149 } 150 151 /* 152 ** Process any remainder bytes. This data is stored in the source 153 ** accumulator buffer for future processing. 154 */ 155 data = source; 156 Process_Partial(data, length); 157 } 158 159 160 #define Reverse_LONG(a) ((a>>24)&0x000000FFL) | ((a>>8)&0x0000FF00L) | ((a<<8)&0x00FF0000L) | ((a<<24)&0xFF000000L) 161 162 163 /*********************************************************************************************** 164 * SHAEngine::Result -- Fetch the current digest. * 165 * * 166 * This routine will return the digest as it currently stands. * 167 * * 168 * INPUT: pointer -- Pointer to the buffer that will hold the digest -- 20 bytes. * 169 * * 170 * OUTPUT: Returns with the number of bytes copied into the buffer. This will always be * 171 * 20. * 172 * * 173 * WARNINGS: none * 174 * * 175 * HISTORY: * 176 * 07/03/1996 JLB : Created. * 177 *=============================================================================================*/ 178 int SHAEngine::Result(void * result) const 179 { 180 /* 181 ** If the final hash result has already been calculated for the 182 ** current data state, then immediately return with the precalculated 183 ** value. 184 */ 185 if (IsCached) { 186 memcpy(result, &FinalResult, sizeof(FinalResult)); 187 } 188 189 long length = Length + PartialCount; 190 int partialcount = PartialCount; 191 char partial[SRC_BLOCK_SIZE]; 192 memcpy(partial, Partial, sizeof(Partial)); 193 194 /* 195 ** Cap the end of the source data stream with a 1 bit. 196 */ 197 partial[partialcount] = (char)0x80; 198 199 /* 200 ** Determine if there is insufficient room to append the 201 ** data length number to the hash source. If not, then 202 ** fill out the rest of the accumulator and flush it to 203 ** the hash so that there will be room for the final 204 ** count value. 205 */ 206 SHADigest acc = Acc; 207 if ((SRC_BLOCK_SIZE - partialcount) < 9) { 208 if (partialcount+1 < SRC_BLOCK_SIZE) { 209 memset(&partial[partialcount+1], '\0', SRC_BLOCK_SIZE - (partialcount+1)); 210 } 211 Process_Block(&partial[0], acc); 212 partialcount = 0; 213 } else { 214 partialcount++; 215 } 216 217 /* 218 ** Put the length of the source data as a 64 bit integer in the 219 ** last 8 bytes of the pseudo-source data. 220 */ 221 memset(&partial[partialcount], '\0', SRC_BLOCK_SIZE - partialcount); 222 *(long *)(&partial[SRC_BLOCK_SIZE-4]) = Reverse_LONG((length*8)); 223 Process_Block(&partial[0], acc); 224 225 memcpy((char *)&FinalResult, &acc, sizeof(acc)); 226 for (int index = 0; index < sizeof(FinalResult)/sizeof(long); index++) { 227 // for (int index = 0; index < SRC_BLOCK_SIZE/sizeof(long); index++) { 228 (long &)FinalResult.Long[index] = Reverse_LONG(FinalResult.Long[index]); 229 } 230 (bool&)IsCached = true; 231 memcpy(result, &FinalResult, sizeof(FinalResult)); 232 return(sizeof(FinalResult)); 233 } 234 235 /* 236 ** This pragma to turn off the warning "Conversion may lose significant digits" is to 237 ** work around a bug within the Borland compiler. It will give this warning when the 238 ** _rotl() function is called but will NOT give the warning when the _lrotl() function 239 ** is called even though they both have the same parameters and declaration attributes. 240 */ 241 //#pragma warn -sig 242 template<class T> 243 T _rotl(T X, int n) 244 { 245 return(T)( ( X << n ) | ( (unsigned)X >> ((sizeof(T)*8) - n) ) ); 246 } 247 //unsigned long _RTLENTRY _rotl(unsigned long X, int n) 248 //{ 249 // 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) ) ) ); 250 //} 251 void memrev(char * buffer, size_t length); 252 253 254 /*********************************************************************************************** 255 * SHAEngine::Process_Block -- Process a full data block into the hash accumulator. * 256 * * 257 * This helper routine is called when a full block of data is available for processing * 258 * into the hash. * 259 * * 260 * INPUT: source -- Pointer to the block of data to process. * 261 * * 262 * acc -- Reference to the hash accumulator that this hash step will be * 263 * accumulated into. * 264 * * 265 * OUTPUT: none * 266 * * 267 * WARNINGS: none * 268 * * 269 * HISTORY: * 270 * 07/03/1996 JLB : Created. * 271 *=============================================================================================*/ 272 void SHAEngine::Process_Block(void const * source, SHADigest & acc) const 273 { 274 /* 275 ** The hash is generated by performing operations on a 276 ** block of generated/seeded data. 277 */ 278 long block[PROC_BLOCK_SIZE/sizeof(long)]; 279 280 /* 281 ** Expand the source data into a large 80 * 32bit buffer. This is the working 282 ** data that will be transformed by the secure hash algorithm. 283 */ 284 long const * data = (long const *)source; 285 int index; 286 for (index = 0; index < SRC_BLOCK_SIZE/sizeof(long); index++) { 287 block[index] = Reverse_LONG(data[index]); 288 } 289 290 for (index = SRC_BLOCK_SIZE/sizeof(long); index < PROC_BLOCK_SIZE/sizeof(long); index++) { 291 // block[index] = _rotl(block[(index-3)&15] ^ block[(index-8)&15] ^ block[(index-14)&15] ^ block[(index-16)&15], 1); 292 block[index] = _rotl(block[index-3] ^ block[index-8] ^ block[index-14] ^ block[index-16], 1); 293 } 294 295 /* 296 ** This is the core algorithm of the Secure Hash Algorithm. It is a block 297 ** transformation of 512 bit source data with a 2560 bit intermediate buffer. 298 */ 299 SHADigest alt = acc; 300 for (index = 0; index < PROC_BLOCK_SIZE/sizeof(long); index++) { 301 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); 302 alt.Long[4] = alt.Long[3]; 303 alt.Long[3] = alt.Long[2]; 304 alt.Long[2] = _rotl(alt.Long[1], 30); 305 alt.Long[1] = alt.Long[0]; 306 alt.Long[0] = temp; 307 } 308 acc.Long[0] += alt.Long[0]; 309 acc.Long[1] += alt.Long[1]; 310 acc.Long[2] += alt.Long[2]; 311 acc.Long[3] += alt.Long[3]; 312 acc.Long[4] += alt.Long[4]; 313 } 314