Rev 1 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1 | Rev 11 | ||
---|---|---|---|
Line 4... | Line 4... | ||
4 | 4 | ||
- | 5 | void DecodeLine2(char* pS) { |
|
- | 6 | const char *gLong_key = "\x6c\x1b\x99\x5f\xb9\xcd\x5f\x13\xcb\x04\x20\x0e\x5e\x1c\xa1\x0e"; |
|
- | 7 | const char *gOther_long_key = "\x67\xa8\xd6\x26\xb6\xdd\x45\x1b\x32\x7e\x22\x13\x15\xc2\x94\x37"; |
|
- | 8 | const int gEncryption_method = 2; |
|
- | 9 | ||
- | 10 | int len; |
|
- | 11 | int seed; |
|
- | 12 | int i; |
|
- | 13 | unsigned char c; |
|
- | 14 | char* key; |
|
- | 15 | ||
- | 16 | len = strlen(pS); |
|
- | 17 | key = (char*)gLong_key; |
|
- | 18 | while (len > 0 && (pS[len - 1] == '\r' || pS[len - 1] == '\n')) { |
|
- | 19 | len--; |
|
- | 20 | pS[len] = '\0'; |
|
- | 21 | } |
|
- | 22 | seed = len % 16; |
|
- | 23 | for (i = 0; i < len; i++) { |
|
- | 24 | c = pS[i]; |
|
- | 25 | if (i >= 2) { |
|
- | 26 | if (pS[i - 1] == '/' && pS[i - 2] == '/') { |
|
- | 27 | key = (char*)gOther_long_key; |
|
- | 28 | } |
|
- | 29 | } |
|
- | 30 | if (gEncryption_method == 1) { |
|
- | 31 | if (c == '\t') { |
|
- | 32 | c = 0x9f; |
|
- | 33 | } |
|
- | 34 | ||
- | 35 | c -= 0x20; |
|
- | 36 | c ^= key[seed]; |
|
- | 37 | c &= 0x7f; |
|
- | 38 | c += 0x20; |
|
- | 39 | ||
- | 40 | seed += 7; |
|
- | 41 | seed %= 16; |
|
- | 42 | ||
- | 43 | if (c == 0x9f) { |
|
- | 44 | c = '\t'; |
|
- | 45 | } |
|
- | 46 | } else { |
|
- | 47 | if (c == '\t') { |
|
- | 48 | c = 0x80; |
|
- | 49 | } |
|
- | 50 | c -= 0x20; |
|
- | 51 | if ((c & 0x80) == 0) { |
|
- | 52 | c ^= key[seed] & 0x7f; |
|
- | 53 | } |
|
- | 54 | c += 0x20; |
|
- | 55 | ||
- | 56 | seed += 7; |
|
- | 57 | seed %= 16; |
|
- | 58 | ||
- | 59 | if (c == 0x80) { |
|
- | 60 | c = '\t'; |
|
- | 61 | } |
|
- | 62 | } |
|
- | 63 | pS[i] = c; |
|
- | 64 | } |
|
- | 65 | } |
|
5 | 66 | ||
6 | int main (int argc, char **argv) |
67 | int main (int argc, char **argv) |
7 | { |
68 | { |
8 | // Carmageddon data file decryption utility |
69 | // Carmageddon data file decryption utility |
9 | 70 | ||
10 | #define DECODE_CHAR_WITH_KEY( |
71 | #define DECODE_CHAR_WITH_KEY(c,key) do { \ |
11 | if (c == '\t') \ |
72 | if (c == '\t') \ |
12 | c = |
73 | c = 128; \ |
13 | c -= 32; \ |
74 | c -= 32; \ |
14 | if |
75 | if (c < 128) \ |
15 | c ^= (key)[seed] & 0x7f; \ |
76 | c ^= (key)[seed] & 0x7f; \ |
16 | c += 32; \ |
77 | c += 32; \ |
17 | if (c == |
78 | if (c == 128) \ |
18 | c = '\t'; \ |
79 | c = '\t'; \ |
19 | if (should_bump_seed) \ |
- | |
20 |
|
80 | seed = (seed + 7) % 16; \ |
21 | } while (0) |
81 | } while (0) |
22 | 82 | ||
23 | const char *key1 = "\x6c\x1b\x99\x5f\xb9\xcd\x5f\x13\xcb\x04\x20\x0e\x5e\x1c\xa1\x0e"; |
83 | const char *key1 = "\x6c\x1b\x99\x5f\xb9\xcd\x5f\x13\xcb\x04\x20\x0e\x5e\x1c\xa1\x0e"; |
24 | const char *key2 = "\x67\xa8\xd6\x26\xb6\xdd\x45\x1b\x32\x7e\x22\x13\x15\xc2\x94\x37"; |
84 | const char *key2 = "\x67\xa8\xd6\x26\xb6\xdd\x45\x1b\x32\x7e\x22\x13\x15\xc2\x94\x37"; |
25 | const char *key_to_use; |
85 | const char *key_to_use; |
26 | char line_buffer[1024]; |
86 | char line_buffer[1024]; |
- | 87 | char other_buffer[1024]; |
|
27 | char *file_pathname = NULL; |
88 | char *file_pathname = NULL; |
28 | int should_fix_b0rken_crypto = 1; |
89 | int should_fix_b0rken_crypto = 1; |
29 | unsigned char c; |
90 | unsigned char c; |
- | 91 | int weird_count; |
|
- | 92 | int seed_backup; |
|
30 | int seed; |
93 | int seed; |
31 | int len; |
94 | int len; |
32 | int i; |
95 | int i; |
- | 96 | int j; |
|
33 | FILE *fp; |
97 | FILE *fp; |
34 | 98 | ||
35 | // process command-line arguments |
99 | // process command-line arguments |
36 | for (i = 1; i < argc; i++) |
100 | for (i = 1; i < argc; i++) |
37 | { |
101 | { |
Line 43... | Line 107... | ||
43 | 107 | ||
44 | // consistency check |
108 | // consistency check |
45 | if (file_pathname == NULL) |
109 | if (file_pathname == NULL) |
46 | { |
110 | { |
47 | fprintf (stderr, "usage: %s [--dont-fix-b0rken-carmageddon-crypto] <FILE.TXT>\n", argv[0]); |
111 | fprintf (stderr, "usage: %s [--dont-fix-b0rken-carmageddon-crypto] <FILE.TXT>\n", argv[0]); |
48 | exit (1); |
112 | exit (1); |
49 | } |
113 | } |
50 | 114 | ||
51 | // open the Carmageddon data file to decrypt |
115 | // open the Carmageddon data file to decrypt |
52 | fp = fopen (file_pathname, "rb"); |
116 | fp = fopen (file_pathname, "rb"); |
53 | if (fp == NULL) |
117 | if (fp == NULL) |
54 | { |
118 | { |
55 | fprintf (stderr, "error: couldn't open '%s'\n", argv[1]); |
119 | fprintf (stderr, "error: couldn't open '%s'\n", argv[1]); |
56 | exit (1); |
120 | exit (1); |
57 | } |
121 | } |
58 | 122 | ||
59 | // read it line per line |
123 | // read it line per line |
60 | while (fgets (line_buffer, sizeof (line_buffer), fp) != NULL) |
124 | while (fgets (line_buffer, sizeof (line_buffer), fp) != NULL) |
61 | { |
125 | { |
62 | len = (int) strlen (line_buffer); // measure line length |
126 | len = (int) strlen (line_buffer); // measure line length |
63 | 127 | ||
Line 66... | Line 130... | ||
66 | { |
130 | { |
67 | // chop off all trailing CR and LFs from the input data |
131 | // chop off all trailing CR and LFs from the input data |
68 | while ((len > 0) && ((line_buffer[len - 1] == '\r') || (line_buffer[len - 1] == '\n'))) |
132 | while ((len > 0) && ((line_buffer[len - 1] == '\r') || (line_buffer[len - 1] == '\n'))) |
69 | line_buffer[--len] = 0; |
133 | line_buffer[--len] = 0; |
70 | 134 | ||
- | 135 | #if 1 |
|
71 | // start with the first key and initialize the algorithm seed to the remainder of the length of data / 16 |
136 | // start with the first key and initialize the algorithm seed to the remainder of the length of data / 16 |
72 | key_to_use = key1; |
137 | key_to_use = key1; |
73 | seed = (len - 1) % 16; |
138 | seed = (len - 1) % 16; |
74 | 139 | ||
75 | // for each encrypted character... |
140 | // for each encrypted character... |
76 | for (i = 1; i < len; i++) |
141 | for (i = 1; i < len; i++) |
77 | { |
142 | { |
78 | c = line_buffer[i]; // quick access to character |
143 | c = line_buffer[i]; // quick access to character |
79 | 144 | ||
80 | // when loading game data, Carmageddon does not switch the XOR cypher when the comments start |
145 | // when loading game data, Carmageddon does not switch the XOR cypher when the comments start |
81 | if ( |
146 | if ((key_to_use == key1) && should_fix_b0rken_crypto) |
82 | { |
147 | { |
- | 148 | if ((i >= 3) && (line_buffer[i - 2] == '/') && (line_buffer[i - 3] == '/')) // pattern: "//?" |
|
- | 149 | { |
|
- | 150 | seed_backup = seed; |
|
- | 151 | /* |
|
- | 152 | weird_count = 0; |
|
- | 153 | for (j = i; j < len; j++) |
|
- | 154 | { |
|
- | 155 | c = line_buffer[j]; |
|
- | 156 | DECODE_CHAR_WITH_KEY (c, key2); // decode character with the alternate key, but don't advance the seed |
|
- | 157 | if (c > 0x7f) |
|
- | 158 | weird_count++; |
|
- | 159 | else if (c == ' ') |
|
- | 160 | break; |
|
- | 161 | } |
|
- | 162 | if ((j < len) || (weird_count > (len - i) / 10)) |
|
- | 163 | { |
|
- | 164 | // fprintf (stderr, "===> Switching keys at char %d\n", i); |
|
- | 165 | key_to_use = key2; |
|
- | 166 | } |
|
- | 167 | /*/ |
|
83 |
|
168 | DECODE_CHAR_WITH_KEY (c, key2); // decode character with the alternate key, but don't advance the seed |
84 | if ((i > 4) || (c == ' ') || (c == '\t') || (c == '/')) |
169 | if ((i > 4) || (c == ' ') || (c == '\t') || (c == '/')) |
- | 170 | { |
|
- | 171 | // fprintf (stderr, "===> Switching keys at char %d\n", i); |
|
85 | key_to_use = key2; // if this character looks sensible enough, it's time to swap keys |
172 | key_to_use = key2; // if this character looks sensible enough, it's time to swap keys |
- | 173 | } |
|
- | 174 | ||
- | 175 | ||
86 | c = line_buffer[i]; // reload character after decryption attempt with alternate key |
176 | c = line_buffer[i]; // reload character after decryption attempt with alternate key |
- | 177 | seed = seed_backup; // and restore seed |
|
- | 178 | } |
|
87 | } |
179 | } |
88 | 180 | ||
89 | DECODE_CHAR_WITH_KEY (c, key_to_use |
181 | DECODE_CHAR_WITH_KEY (c, key_to_use); // decode character and advance the seed |
90 | line_buffer[i - 1] = c; // write decoded character one position backwards to erase the '@' prefix |
182 | line_buffer[i - 1] = c; // write decoded character one position backwards to erase the '@' prefix |
91 | } |
183 | } |
92 | 184 | #else |
|
- | 185 | i = len; |
|
- | 186 | DecodeLine2 (&line_buffer[1]); |
|
- | 187 | memmove (line_buffer, &line_buffer[1], len); |
|
- | 188 | #endif |
|
93 | line_buffer[i - 1] = 0; // terminate the decrypted string properly |
189 | line_buffer[i - 1] = 0; // terminate the decrypted string properly |
94 | } |
190 | } |
95 | 191 | ||
96 | // chop off all trailing CR and LFs from the decrypted data once again |
192 | // chop off all trailing CR and LFs from the decrypted data once again |
97 | while ((len > 0) && ((line_buffer[len - 1] == '\r') || (line_buffer[len - 1] == '\n'))) |
193 | while ((len > 0) && ((line_buffer[len - 1] == '\r') || (line_buffer[len - 1] == '\n'))) |