| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- /*
- ** 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 <http://www.gnu.org/licenses/>.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <conio.h>
- #include <ctype.h>
- #include <string.h>
- #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);
- }
|