sha.cpp 16 KB

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