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