Subversion Repositories Games.Carmageddon

Rev

Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
 
11 pmbaty 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;
1 pmbaty 9
 
11 pmbaty 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
}
66
 
1 pmbaty 67
int main (int argc, char **argv)
68
{
69
        // Carmageddon data file decryption utility
70
 
11 pmbaty 71
        #define DECODE_CHAR_WITH_KEY(c,key) do { \
1 pmbaty 72
                if (c == '\t') \
11 pmbaty 73
                        c = 128; \
1 pmbaty 74
                c -= 32; \
11 pmbaty 75
                if (c < 128) \
1 pmbaty 76
                        c ^= (key)[seed] & 0x7f; \
77
                c += 32; \
11 pmbaty 78
                if (c == 128) \
1 pmbaty 79
                        c = '\t'; \
11 pmbaty 80
                seed = (seed + 7) % 16; \
1 pmbaty 81
        } while (0)
82
 
83
        const char *key1 = "\x6c\x1b\x99\x5f\xb9\xcd\x5f\x13\xcb\x04\x20\x0e\x5e\x1c\xa1\x0e";
84
        const char *key2 = "\x67\xa8\xd6\x26\xb6\xdd\x45\x1b\x32\x7e\x22\x13\x15\xc2\x94\x37";
85
        const char *key_to_use;
86
        char line_buffer[1024];
11 pmbaty 87
        char other_buffer[1024];
1 pmbaty 88
        char *file_pathname = NULL;
89
        int should_fix_b0rken_crypto = 1;
90
        unsigned char c;
11 pmbaty 91
        int weird_count;
92
        int seed_backup;
1 pmbaty 93
        int seed;
94
        int len;
95
        int i;
11 pmbaty 96
        int j;
1 pmbaty 97
        FILE *fp;
98
 
99
        // process command-line arguments
100
        for (i = 1; i < argc; i++)
101
        {
102
                if (strcmp (argv[i], "--dont-fix-b0rken-carmageddon-crypto") == 0)
103
                        should_fix_b0rken_crypto = 0;
104
                else if (file_pathname == NULL)
105
                        file_pathname = argv[i];
106
        }
107
 
108
        // consistency check
109
        if (file_pathname == NULL)
110
        {
111
                fprintf (stderr, "usage: %s [--dont-fix-b0rken-carmageddon-crypto] <FILE.TXT>\n", argv[0]);
112
                exit (1);
113
        }
114
 
115
        // open the Carmageddon data file to decrypt
116
        fp = fopen (file_pathname, "rb");
117
        if (fp == NULL)
118
        {
119
                fprintf (stderr, "error: couldn't open '%s'\n", argv[1]);
120
                exit (1);
121
        }
122
 
123
        // read it line per line
124
        while (fgets (line_buffer, sizeof (line_buffer), fp) != NULL)
125
        {
126
                len = (int) strlen (line_buffer); // measure line length
127
 
128
                // is this line encrypted ?
129
                if (line_buffer[0] == '@')
130
                {
131
                        // chop off all trailing CR and LFs from the input data
132
                        while ((len > 0) && ((line_buffer[len - 1] == '\r') || (line_buffer[len - 1] == '\n')))
133
                                line_buffer[--len] = 0;
134
 
11 pmbaty 135
#if 1
1 pmbaty 136
                        // start with the first key and initialize the algorithm seed to the remainder of the length of data / 16
137
                        key_to_use = key1;
138
                        seed = (len - 1) % 16;
139
 
140
                        // for each encrypted character...
141
                        for (i = 1; i < len; i++)
142
                        {
143
                                c = line_buffer[i]; // quick access to character
144
 
145
                                // when loading game data, Carmageddon does not switch the XOR cypher when the comments start
11 pmbaty 146
                                if ((key_to_use == key1) && should_fix_b0rken_crypto)
1 pmbaty 147
                                {
11 pmbaty 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
/*/
168
                                                DECODE_CHAR_WITH_KEY (c, key2); // decode character with the alternate key, but don't advance the seed
169
                                                if ((i > 4) || (c == ' ') || (c == '\t') || (c == '/'))
170
                                                {
171
//                                                      fprintf (stderr, "===> Switching keys at char %d\n", i);
172
                                                        key_to_use = key2; // if this character looks sensible enough, it's time to swap keys
173
                                                }
174
 
175
 
176
                                                c = line_buffer[i]; // reload character after decryption attempt with alternate key
177
                                                seed = seed_backup; // and restore seed
178
                                        }
1 pmbaty 179
                                }
180
 
11 pmbaty 181
                                DECODE_CHAR_WITH_KEY (c, key_to_use); // decode character and advance the seed
1 pmbaty 182
                                line_buffer[i - 1] = c; // write decoded character one position backwards to erase the '@' prefix
183
                        }
11 pmbaty 184
#else
185
i = len;
186
DecodeLine2 (&line_buffer[1]);
187
memmove (line_buffer, &line_buffer[1], len);
188
#endif
1 pmbaty 189
                        line_buffer[i - 1] = 0; // terminate the decrypted string properly
190
                }
191
 
192
                // chop off all trailing CR and LFs from the decrypted data once again
193
                while ((len > 0) && ((line_buffer[len - 1] == '\r') || (line_buffer[len - 1] == '\n')))
194
                   line_buffer[--len] = 0;
195
 
196
                fprintf (stdout, "%s\n", line_buffer); // dump decrypted line to the standard output, with a proper newline at the end
197
        }
198
 
199
        fclose (fp); // close the input file
200
        exit (0); // and exit with a success code
201
}