/* ** Command & Conquer Red Alert(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ #include #include #include #include #include #define true 1 #define false 0 typedef int bool; char KeyPhrase[128] = ""; char KeyCheck[128] = ""; long Code = 0x00000000L; extern "C" { long Calculate_CRC(void const * buffer, long length); } long Obfuscate(char const * string); int main(int , char ** ) { char buffer[128]; /* ** Fetch the key phrase from the console. */ for (;;) { /* ** Fetch the pass phrase. */ puts("\nEnter password phrase:"); int key = 0; int index = 0; KeyPhrase[0] = '\0'; bool process = true; while (process) { key = getche(); switch (key) { case 0x08: if (index) { KeyPhrase[--index] = '\0'; } break; case 0x0D: case 0x0A: process = false; break; default: if (isprint(key)) { KeyPhrase[index++] = key; KeyPhrase[index] = '\0'; } break; } } puts(""); /* ** Verify that it is long enough. */ if (strlen(KeyPhrase) == 0) break; /* ** Calculate the code for the key phrase. */ Code = Obfuscate(KeyPhrase); sprintf(buffer, "0x%08lX", Code); puts(buffer); } puts("Terminated"); return(0); } /*********************************************************************************************** * Obfuscate -- Sufficiently transform parameter to thwart casual hackers. * * * * This routine borrows from CRC and PGP technology to sufficiently alter the parameter * * in order to make it difficult to reverse engineer the key phrase. This is designed to * * be used for hidden game options that will be released at a later time over Westwood's * * Web page or through magazine hint articles. * * * * Since this is a one way transformation, it becomes much more difficult to reverse * * engineer the pass phrase even if the resultant pass code is known. This has an added * * benefit of making this algorithm immune to traditional cyrptographic attacks. * * * * The largest strength of this transformation algorithm lies in the restriction on the * * source vector being legal ASCII uppercase characters. This restriction alone makes even * * a simple CRC transformation practically impossible to reverse engineer. This algorithm * * uses far more than a simple CRC transformation to achieve added strength from advanced * * attack methods. * * * * INPUT: string -- Pointer to the key phrase that will be transformed into a code. * * * * OUTPUT: Returns with the code that the key phrase is translated into. * * * * WARNINGS: A zero length pass phrase results in a 0x00000000 result code. * * * * HISTORY: * * 08/19/1995 JLB : Created. * *=============================================================================================*/ long Obfuscate(char const * string) { char buffer[128]; if (!string) return(0); memset(buffer, '\xA5', sizeof(buffer)); /* ** Copy key phrase into a working buffer. This hides any transformation done ** to the string. */ strncpy(buffer, string, sizeof(buffer)); buffer[sizeof(buffer)-1] = '\0'; int length = strlen(buffer); /* ** Only upper case letters are significant. */ strupr(buffer); /* ** Ensure that only visible ASCII characters compose the key phrase. This ** discourages the direct forced illegal character input method of attack. */ for (int index = 0; index < length; index++) { if (!isgraph(buffer[index])) { buffer[index] = 'A' + (index%26); } } /* ** Increase the strength of even short pass phrases by extending the ** length to be at least a minimum number of characters. This helps prevent ** a weak pass phrase from compromising the obfuscation process. This ** process also forces the key phrase to be an even multiple of four. ** This is necessary to support the cypher process that occurs later. */ if (length < 16 || (length & 0x03)) { int maxlen = 16; if (((length+3) & 0x00FC) > maxlen) { maxlen = ((length+3) & 0x00FC); } for (index = length; index < maxlen; index++) { buffer[index] = 'A' + ((('?' ^ buffer[index-length]) + index) % 26); } length = index; buffer[length] = '\0'; } /* ** Transform the buffer into a number. This transformation is character ** order dependant. */ long code = Calculate_CRC(buffer, length); /* ** Record a copy of this initial transformation to be used in a later ** self referential transformation. */ long copy = code; /* ** Reverse the character string and combine with the previous transformation. ** This doubles the workload of trying to reverse engineer the CRC calculation. */ strrev(buffer); code ^= Calculate_CRC(buffer, length); /* ** Perform a self referential transformation. This makes a reverse engineering ** by using a cause and effect attack more difficult. */ code = code ^ copy; /* ** Unroll and combine the code value into the pass phrase and then perform ** another self referential transformation. Although this is a trivial cypher ** process, it gives the sophisticated hacker false hope since the strong ** cypher process occurs later. */ strrev(buffer); // Restore original string order. for (index = 0; index < length; index++) { code ^= (unsigned char)buffer[index]; unsigned char temp = (unsigned char)code; buffer[index] ^= temp; code >>= 8; code |= (((long)temp)<<24); } /* ** Introduce loss into the vector. This strengthens the key against traditional ** cryptographic attack engines. Since this also weakens the key against ** unconventional attacks, the loss is limited to less than 10%. */ for (index = 0; index < length; index++) { static unsigned char _lossbits[] = {0x00,0x08,0x00,0x20,0x00,0x04,0x10,0x00}; static unsigned char _addbits[] = {0x10,0x00,0x00,0x80,0x40,0x00,0x00,0x04}; buffer[index] |= _addbits[index % (sizeof(_addbits)/sizeof(_addbits[0]))]; buffer[index] &= ~_lossbits[index % (sizeof(_lossbits)/sizeof(_lossbits[0]))]; } /* ** Perform a general cypher transformation on the vector ** and use the vector itself as the cypher key. This is a variation on the ** cypher process used in PGP. It is a very strong cypher process with no known ** weaknesses. However, in this case, the cypher key is the vector itself and this ** opens up a weakness against attacks that have access to this transformation ** algorithm. The sheer workload of reversing this transformation should be enough ** to discourage even the most determined hackers. */ for (index = 0; index < length; index += 4) { short key1 = buffer[index]; short key2 = buffer[index+1]; short key3 = buffer[index+2]; short key4 = buffer[index+3]; short val1 = key1; short val2 = key2; short val3 = key3; short val4 = key4; val1 *= key1; val2 += key2; val3 += key3; val4 *= key4; short s3 = val3; val3 ^= val1; val3 *= key1; short s2 = val2; val2 ^= val4; val2 += val3; val2 *= key3; val3 += val2; val1 ^= val2; val4 ^= val3; val2 ^= s3; val3 ^= s2; buffer[index] = val1; buffer[index+1] = val2; buffer[index+2] = val3; buffer[index+3] = val4; } /* ** Convert this final vector into a cypher key code to be ** returned by this routine. */ code = Calculate_CRC(buffer, length); /* ** Return the final code value. */ return(code); }