obscure.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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/Obscure.cpp $*
  25. * *
  26. * $Author:: Greg_h $*
  27. * *
  28. * $Modtime:: 7/22/97 11:37a $*
  29. * *
  30. * $Revision:: 1 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * Obfuscate -- Sufficiently transform parameter to thwart casual hackers. *
  35. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  36. #include "always.h"
  37. #include "crc.h"
  38. #include "obscure.h"
  39. #include <ctype.h>
  40. #include <string.h>
  41. /***********************************************************************************************
  42. * Obfuscate -- Sufficiently transform parameter to thwart casual hackers. *
  43. * *
  44. * This routine borrows from CRC and PGP technology to sufficiently alter the parameter *
  45. * in order to make it difficult to reverse engineer the key phrase. This is designed to *
  46. * be used for hidden game options that will be released at a later time over Westwood's *
  47. * Web page or through magazine hint articles. *
  48. * *
  49. * This algorithm is cryptographically categorized as a "one way hash". *
  50. * *
  51. * Since this is a one way transformation, it becomes much more difficult to reverse *
  52. * engineer the pass phrase even if the resultant pass code is known. This has an added *
  53. * benefit of making this algorithm immune to traditional cryptographic attacks. *
  54. * *
  55. * The largest strength of this transformation algorithm lies in the restriction on the *
  56. * source vector being legal ASCII uppercase characters. This restriction alone makes even *
  57. * a simple CRC transformation practically impossible to reverse engineer. This algorithm *
  58. * uses far more than a simple CRC transformation to achieve added strength from advanced *
  59. * attack methods. *
  60. * *
  61. * INPUT: string -- Pointer to the key phrase that will be transformed into a code. *
  62. * *
  63. * OUTPUT: Returns with the code that the key phrase is translated into. *
  64. * *
  65. * WARNINGS: A zero length pass phrase results in a 0x00000000 result code. *
  66. * *
  67. * HISTORY: *
  68. * 08/19/1995 JLB : Created. *
  69. *=============================================================================================*/
  70. long Obfuscate(char const * string)
  71. {
  72. char buffer[128];
  73. if (!string) return(0);
  74. memset(buffer, '\xA5', sizeof(buffer));
  75. /*
  76. ** Copy key phrase into a working buffer. This hides any transformation done
  77. ** to the string.
  78. */
  79. strncpy(buffer, string, sizeof(buffer));
  80. buffer[sizeof(buffer)-1] = '\0';
  81. int length = strlen(buffer);
  82. /*
  83. ** Only upper case letters are significant.
  84. */
  85. strupr(buffer);
  86. /*
  87. ** Ensure that only visible ASCII characters compose the key phrase. This
  88. ** discourages the direct forced illegal character input method of attack.
  89. */
  90. for (int index = 0; index < length; index++) {
  91. if (!isgraph(buffer[index])) {
  92. buffer[index] = (char)('A' + (index%26));
  93. }
  94. }
  95. /*
  96. ** Increase the strength of even short pass phrases by extending the
  97. ** length to be at least a minimum number of characters. This helps prevent
  98. ** a weak pass phrase from compromising the obfuscation process. This
  99. ** process also forces the key phrase to be an even multiple of four.
  100. ** This is necessary to support the cypher process that occurs later.
  101. */
  102. if (length < 16 || (length & 0x03)) {
  103. int maxlen = 16;
  104. if (((length+3) & 0x00FC) > maxlen) {
  105. maxlen = ((length+3) & 0x00FC);
  106. }
  107. int index;
  108. for (index = length; index < maxlen; index++) {
  109. buffer[index] = (char)('A' + ((('?' ^ buffer[index-length]) + index) % 26));
  110. }
  111. length = index;
  112. buffer[length] = '\0';
  113. }
  114. /*
  115. ** Transform the buffer into a number. This transformation is character
  116. ** order dependant.
  117. */
  118. long code = CRCEngine()(buffer, length);
  119. /*
  120. ** Record a copy of this initial transformation to be used in a later
  121. ** self referential transformation.
  122. */
  123. long copy = code;
  124. /*
  125. ** Reverse the character string and combine with the previous transformation.
  126. ** This doubles the workload of trying to reverse engineer the CRC calculation.
  127. */
  128. strrev(buffer);
  129. code ^= CRCEngine()(buffer, length);
  130. /*
  131. ** Perform a self referential transformation. This makes a reverse engineering
  132. ** by using a cause and effect attack more difficult.
  133. */
  134. code = code ^ copy;
  135. /*
  136. ** Unroll and combine the code value into the pass phrase and then perform
  137. ** another self referential transformation. Although this is a trivial cypher
  138. ** process, it gives the sophisticated hacker false hope since the strong
  139. ** cypher process occurs later.
  140. */
  141. strrev(buffer); // Restore original string order.
  142. for (int index2 = 0; index2 < length; index2++) {
  143. code ^= (unsigned char)buffer[index2];
  144. unsigned char temp = (unsigned char)code;
  145. buffer[index2] ^= temp;
  146. code >>= 8;
  147. code |= (((long)temp)<<24);
  148. }
  149. /*
  150. ** Introduce loss into the vector. This strengthens the key against traditional
  151. ** cryptographic attack engines. Since this also weakens the key against
  152. ** unconventional attacks, the loss is limited to less than 10%.
  153. */
  154. for (int index3 = 0; index3 < length; index3++) {
  155. static unsigned char _lossbits[] = {0x00,0x08,0x00,0x20,0x00,0x04,0x10,0x00};
  156. static unsigned char _addbits[] = {0x10,0x00,0x00,0x80,0x40,0x00,0x00,0x04};
  157. buffer[index3] |= _addbits[index3 % (sizeof(_addbits)/sizeof(_addbits[0]))];
  158. buffer[index3] &= (char)(~_lossbits[index3 % (sizeof(_lossbits)/sizeof(_lossbits[0]))]);
  159. }
  160. /*
  161. ** Perform a general cypher transformation on the vector
  162. ** and use the vector itself as the cypher key. This is a variation on the
  163. ** cypher process used in PGP. It is a very strong cypher process with no known
  164. ** weaknesses. However, in this case, the cypher key is the vector itself and this
  165. ** opens up a weakness against attacks that have access to this transformation
  166. ** algorithm. The sheer workload of reversing this transformation should be enough
  167. ** to discourage even the most determined hackers.
  168. */
  169. for (int index4 = 0; index4 < length; index4 += 4) {
  170. short key1 = buffer[index4];
  171. short key2 = buffer[index4+1];
  172. short key3 = buffer[index4+2];
  173. short key4 = buffer[index4+3];
  174. short val1 = key1;
  175. short val2 = key2;
  176. short val3 = key3;
  177. short val4 = key4;
  178. val1 *= key1;
  179. val2 += key2;
  180. val3 += key3;
  181. val4 *= key4;
  182. short s3 = val3;
  183. val3 ^= val1;
  184. val3 *= key1;
  185. short s2 = val2;
  186. val2 ^= val4;
  187. val2 += val3;
  188. val2 *= key3;
  189. val3 += val2;
  190. val1 ^= val2;
  191. val4 ^= val3;
  192. val2 ^= s3;
  193. val3 ^= s2;
  194. buffer[index4] = val1;
  195. buffer[index4+1] = val2;
  196. buffer[index4+2] = val3;
  197. buffer[index4+3] = val4;
  198. }
  199. /*
  200. ** Convert this final vector into a cypher key code to be
  201. ** returned by this routine.
  202. */
  203. code = CRCEngine()(buffer, length);
  204. /*
  205. ** Return the final code value.
  206. */
  207. return(code);
  208. }