KEYCODE.CPP 8.9 KB

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