]> icculus.org git repositories - taylor/freespace2.git/blob - src/parse/encrypt.cpp
Initial revision
[taylor/freespace2.git] / src / parse / encrypt.cpp
1 /*
2  * $Logfile: /Freespace2/code/parse/Encrypt.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Module for encryption code common to FreeSpace and related tools
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:10  root
11  * Initial revision
12  *
13  * 
14  * 5     4/07/99 5:41p Anoop
15  * Fixed encryption in the launcher.
16  * 
17  * 4     3/25/99 11:55a Dave
18  * Fixed up encrypt a bit.
19  * 
20  * 3     3/25/99 11:26a Dave
21  * Beefed up encryption scheme so that even someone viewing the
22  * disassembly would have a hard time cracking it.
23  * 
24  * 2     10/07/98 10:53a Dave
25  * Initial checkin.
26  * 
27  * 1     10/07/98 10:50a Dave
28  * 
29  * 5     8/09/98 4:44p Lawrance
30  * support alternate encryption scheme (doesn't pack chars into 7 bits)
31  * 
32  * 4     4/01/98 2:21p Lawrance
33  * check for wacky apostrophe char
34  * 
35  * 3     3/31/98 4:57p Lawrance
36  * Add signature at the beginning of encrypted files
37  * 
38  * 2     3/31/98 1:14a Lawrance
39  * Get .tbl and mission file encryption working.
40  * 
41  * 1     3/30/98 11:02p Lawrance
42  *
43  * $NoKeywords: $
44  */
45
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49
50 #define ENCRYPT_NEW                                                                                                     // new, better encryption scheme
51
52 #include "pstypes.h"
53 #include "encrypt.h"
54
55 const uint Encrypt_new_signature                        = 0x5c331a55;           // new encrpytion
56 const uint Encrypt_signature                            = 0xdeadbeef;           // full encryption
57 const uint Encrypt_signature_8bit               = 0xcacacaca;           // light encryption - doesn't use 7bit chars
58
59 int Encrypt_inited = 0;
60
61 // new encrpytion
62 void encrypt_new(char *text, int text_len, char *scrambled_text, int *scrambled_len);
63 void unencrypt_new(char *scrambled_text, int scrambled_len, char *text, int *text_len);
64
65 // update cur_seed with the chksum of the new_data of size new_data_size
66 ushort chksum_add_short(ushort seed, char *buffer, int size)
67 {
68         ubyte * ptr = (ubyte *)buffer;
69         unsigned int sum1,sum2;
70
71         sum1 = sum2 = (int)(seed);
72
73         while(size--)   {
74                 sum1 += *ptr++;
75                 if (sum1 >= 255 ) sum1 -= 255;
76                 sum2 += sum1;
77         }
78         sum2 %= 255;
79         
80         return (unsigned short)((sum1<<8)+ sum2);
81 }
82
83 // scramble text data
84 //
85 // input:       text            =>      ascii data to be scrambled
86 //                              text_len        =>      number of bytes of ascii data to scramble
87 //                              scrambled_text  =>      storage for scrambled text (malloc at least text_len)
88 //                              scrambled_len   =>      size of text after getting scrambled
89 //                              use_8bit => flag to indicate that chars are stored using 8 bits (default value is 0)
90 void encrypt(char *text, int text_len, char *scrambled_text, int *scrambled_len, int use_8bit)
91 {
92 #ifdef ENCRYPT_NEW
93         encrypt_new(text, text_len, scrambled_text, scrambled_len);
94 #else
95         int i;
96         int byte_offset = 0;
97         int bit_offset = 0;
98
99         *scrambled_len = 0;
100
101         // Identify encrypted files with a unique signature
102         if (use_8bit) {
103                 memcpy(scrambled_text, &Encrypt_signature_8bit, 4);
104         } else {
105                 memcpy(scrambled_text, &Encrypt_signature, 4);
106         }
107         byte_offset = 4;
108
109         // First stage: packing chars into 7 bit boundries
110         for ( i =0; i < text_len; i++ ) {
111
112                 // account for wacky apostrophe that has ascii code 0x92
113                 if ( (unsigned char)text[i] == 0x92 ) {
114                         text[i] = 0x27;
115                 }
116
117                 if (use_8bit) {
118                         scrambled_text[byte_offset++] = text[i];
119                 } else {
120                         switch(bit_offset) {
121                         case 0:
122                                 scrambled_text[byte_offset] = (char)((text[i] << 1) & 0xfe);
123                                 bit_offset = 7;
124                                 break;
125                         case 1:
126                                 scrambled_text[byte_offset] &= 0x80;                                            // clear out bottom 7 bits
127                                 scrambled_text[byte_offset] |= (text[i] & 0x7F);        
128                                 byte_offset++;
129                                 bit_offset = 0;
130                                 break;
131                         case 2:
132                                 scrambled_text[byte_offset] &= 0xc0;                                                                            // clear out bottom 6 bits
133                                 scrambled_text[byte_offset] |= ((text[i] >> 1) & 0x3F);                         // put in top 6 bits
134                                 byte_offset++;
135                                 scrambled_text[byte_offset] = (char)((text[i] << 7) & 0x80);            // put in last bit
136                                 bit_offset = 1;
137                                 break;
138                         case 3:
139                                 scrambled_text[byte_offset] &= 0xe0;                                                                            // clear out bottom 5 bits
140                                 scrambled_text[byte_offset] |= ((text[i] >> 2) & 0x1F);                         // put in top 5 bits
141                                 byte_offset++;
142                                 scrambled_text[byte_offset] = (char)((text[i] << 6) & 0xc0);            // put in last two bits
143                                 bit_offset = 2;
144                                 break;
145                         case 4:
146                                 scrambled_text[byte_offset] &= 0xf0;                                                                            // clear out bottom 4 bits
147                                 scrambled_text[byte_offset] |= ((text[i] >> 3) & 0x0F);                         // put in top 4 bits
148                                 byte_offset++;
149                                 scrambled_text[byte_offset] = (char)((text[i] << 5) & 0xe0);            // put in last three bits
150                                 bit_offset = 3;
151                                 break;
152                         case 5:
153                                 scrambled_text[byte_offset] &= 0xf8;                                                                            // clear out bottom 3 bits
154                                 scrambled_text[byte_offset] |= ((text[i] >> 4) & 0x07);                         // put in top 3 bits
155                                 byte_offset++;
156                                 scrambled_text[byte_offset] = (char)((text[i] << 4) & 0xf0);            // put in last four bits
157                                 bit_offset = 4;
158                                 break;
159                         case 6:
160                                 scrambled_text[byte_offset] &= 0xfc;                                                                            // clear out bottom 2 bits
161                                 scrambled_text[byte_offset] |= ((text[i] >> 5) & 0x03);                         // put in top 2 bits
162                                 byte_offset++;
163                                 scrambled_text[byte_offset] = (char)((text[i] << 3) & 0xf8);            // put in last five bits
164                                 bit_offset = 5;
165                                 break;
166                         case 7:
167                                 scrambled_text[byte_offset] &= 0xfe;                                                                            // clear out bottom bit
168                                 scrambled_text[byte_offset] |= ((text[i] >> 6) & 0x01);                         // put in top bit
169                                 byte_offset++;
170                                 scrambled_text[byte_offset] = (char)((text[i] << 2) & 0xfc);            // put in last six bits
171                                 bit_offset = 6;
172                                 break;
173                         default:
174                                 return;
175                         }
176                 }
177         }
178
179         if ( bit_offset > 0 ) {
180                 byte_offset++;
181         }
182
183         *scrambled_len = byte_offset;
184
185         // Second stage: XOR with offset into file (skip signature)
186         scrambled_text += 4;
187         int len = *scrambled_len - 4;
188         for ( i =0; i < len; i++ ) {
189                 scrambled_text[i] ^= i;
190         }
191 #endif
192 }
193
194 //      input:  scrambled_text  =>      scrambled text
195 //                              scrambled_len   =>      number of bytes of scrambled text
196 //                              text                            =>      storage for unscrambled ascii data
197 //                              text_len                        =>      actual number of bytes of unscrambled data
198 void unencrypt(char *scrambled_text, int scrambled_len, char *text, int *text_len)
199 {
200 #ifdef ENCRYPT_NEW
201         unencrypt_new(scrambled_text, scrambled_len, text, text_len);
202 #else
203         int i, num_runs;
204         int scramble_offset = 0;
205         int byte_offset = 0;
206         char maybe_last = 0;
207
208         uint encrypt_id;
209
210         // Only decrpyt files that start with unique signature
211         memcpy(&encrypt_id, scrambled_text, 4);
212
213         if ( (encrypt_id != Encrypt_signature) && (encrypt_id !=  Encrypt_signature_8bit) ) {
214                 memcpy(text, scrambled_text, scrambled_len);
215                 *text_len = scrambled_len;
216                 return;
217         }       
218
219         scrambled_text += 4;
220         scrambled_len -= 4;
221
222         // First decrypt stage: undo XOR operation
223         for ( i =0; i < scrambled_len; i++ ) {
224                 scrambled_text[i] ^= i;
225         }
226
227         if (encrypt_id == Encrypt_signature_8bit) {
228                 memcpy(text, scrambled_text, scrambled_len);
229                 *text_len = scrambled_len;
230                 return;
231         }
232
233         // Second decrypt stage: remove chars from 7 bit packing to 8 bit boundries
234         num_runs = (int) (scrambled_len / 7.0f );
235         if ( scrambled_len % 7 ) {
236                 num_runs++;
237         }
238
239         for ( i =0; i < num_runs; i++ ) {
240                 // a run consists of 8 chars packed into 56 bits (instead of 64)
241
242                 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 1) & 0x7f);
243                 byte_offset++;
244                 scramble_offset++;
245
246                 if ( scramble_offset >= scrambled_len ) {
247                         break;
248                 }
249
250                 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 2) & 0x3f);
251                 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 6) & 0x40 );
252                 byte_offset++;
253                 scramble_offset++;
254
255                 if ( scramble_offset >= scrambled_len ) {
256                         break;
257                 }
258
259                 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 3) & 0x1f);
260                 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 5) & 0x60 );
261                 byte_offset++;
262                 scramble_offset++;
263
264                 if ( scramble_offset >= scrambled_len ) {
265                         break;
266                 }
267
268                 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 4) & 0x0f);
269                 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 4) & 0x70 );
270                 byte_offset++;
271                 scramble_offset++;
272
273                 if ( scramble_offset >= scrambled_len ) {
274                         break;
275                 }
276
277                 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 5) & 0x07);
278                 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 3) & 0x78 );
279                 byte_offset++;
280                 scramble_offset++;
281
282                 if ( scramble_offset >= scrambled_len ) {
283                         break;
284                 }
285
286                 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 6) & 0x03);
287                 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 2) & 0x7c );
288                 byte_offset++;
289                 scramble_offset++;
290
291                 if ( scramble_offset >= scrambled_len ) {
292                         break;
293                 }
294
295                 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 7) & 0x01);
296                 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 1) & 0x7e );
297                 byte_offset++;
298
299                 maybe_last = (char)(scrambled_text[scramble_offset] & 0x7f);
300                 if ( maybe_last > 0 ) {
301                         text[byte_offset] = maybe_last;
302                         byte_offset++;
303                         scramble_offset++;
304                 }
305         }
306
307         *text_len = byte_offset;
308 #endif
309 }
310
311 #define NUM_LVL1_KEYS                                   11
312 ushort Lvl1_keys[NUM_LVL1_KEYS] = {
313         0xa820, 0x71f0,
314         0x88da, 0x1fff,
315         0x2718, 0xe6a1,
316         0x42b8, 0x0ce9,
317         0x10ec, 0xd77d,
318         0x3fa9
319 };
320
321 // scramble text data
322 //
323 // input:       text            =>      ascii data to be scrambled
324 //                              text_len        =>      number of bytes of ascii data to scramble
325 //                              scrambled_text  =>      storage for scrambled text (malloc at least text_len)
326 //                              scrambled_len   =>      size of text after getting scrambled
327 void encrypt_new(char *text, int text_len, char *scrambled_text, int *scrambled_len)
328 {
329         ushort lvl1_block[NUM_LVL1_KEYS * 2];   
330         ushort block_checksum;
331         int block_size, idx;
332
333         // add the encrpytion signature
334         memcpy(scrambled_text, &Encrypt_new_signature, 4);      
335                 
336         // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes     
337         block_checksum = 0xffff;
338         *scrambled_len = 0;     
339         while(*scrambled_len < text_len){
340                 // if we have less than one block left
341                 if((text_len - *scrambled_len) < (NUM_LVL1_KEYS * 2)){
342                         memcpy(lvl1_block, text + *scrambled_len, text_len - *scrambled_len);
343                         block_size = text_len - *scrambled_len;                 
344                 }
345                 // if we have at least one full block left
346                 else {
347                         memcpy(lvl1_block, text + *scrambled_len, NUM_LVL1_KEYS * 2);
348                         block_size = NUM_LVL1_KEYS * 2;                 
349                 }
350
351                 // run the lvl1 over the block
352                 for(idx=0; idx<block_size/2; idx++){
353                         // the base key with the running checksum from the _last_ block
354                         lvl1_block[idx] ^= (Lvl1_keys[idx] ^ block_checksum);
355                 }
356
357                 // the running checksum
358                 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block, block_size);               
359                 
360                 // copy into the outgoing buffer
361                 memcpy(scrambled_text + *scrambled_len + 4, lvl1_block, block_size);
362                 *scrambled_len += block_size;
363         }
364
365         // add the 4 bytes for the header
366         *scrambled_len += 4;
367
368 }
369
370 //      input:  scrambled_text  =>      scrambled text
371 //                              scrambled_len   =>      number of bytes of scrambled text
372 //                              text                            =>      storage for unscrambled ascii data
373 //                              text_len                        =>      actual number of bytes of unscrambled data
374 void unencrypt_new(char *scrambled_text, int scrambled_len, char *text, int *text_len)
375 {
376         ushort lvl1_block[NUM_LVL1_KEYS * 2];
377         ushort lvl1_block_copy[NUM_LVL1_KEYS * 2];
378         ushort block_checksum;
379         int block_size, idx;    
380         uint encrypt_id;
381
382         // Only decrypt files that start with unique signature
383         memcpy(&encrypt_id, scrambled_text, 4);
384         if (encrypt_id != Encrypt_new_signature) {
385                 memcpy(text, scrambled_text, scrambled_len);
386                 *text_len = scrambled_len;
387                 return;
388         }       
389         
390         // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes
391         *text_len = 0;  
392         scrambled_text += 4;
393         scrambled_len -= 4;
394         block_checksum = 0xffff;
395         while(*text_len < scrambled_len){
396                 // if we have less than one block left
397                 if((scrambled_len - *text_len) < (NUM_LVL1_KEYS * 2)){
398                         memcpy(lvl1_block, scrambled_text + *text_len, scrambled_len - *text_len);
399                         block_size = scrambled_len - *text_len;                 
400                 }
401                 // if we have at least one full block left
402                 else {
403                         memcpy(lvl1_block, scrambled_text + *text_len, NUM_LVL1_KEYS * 2);
404                         block_size = NUM_LVL1_KEYS * 2;                 
405                 }               
406                 
407                 // copy the block so that we can properly calculate the next running checksum
408                 memcpy(lvl1_block_copy, lvl1_block, block_size);
409                 // run the lvl1 over the block
410                 for(idx=0; idx<block_size/2; idx++){
411                         lvl1_block[idx] ^= (Lvl1_keys[idx] ^ block_checksum);
412                 }
413
414                 // the running checksum
415                 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block_copy, block_size);          
416
417                 // copy into the outgoing buffer
418                 memcpy(text + *text_len, lvl1_block, block_size);
419                 *text_len += block_size;
420         }
421 }
422
423 // Return 1 if the data is encrypted, otherwise return 0
424 int is_encrpyted(char *scrambled_text)
425 {
426         uint    encrypt_id;
427
428         memcpy(&encrypt_id, scrambled_text, 4);
429
430         if ( (encrypt_id == Encrypt_signature) || (encrypt_id == Encrypt_signature_8bit) || (encrypt_id == Encrypt_new_signature)) {
431                 return 1;
432         }
433
434         return 0;
435 }
436
437 // initialize encryption
438 void encrypt_init()
439 {       
440         int idx;
441         ushort haha_you_dumbass = 0xe2A8;
442
443         if(Encrypt_inited){
444                 return;
445         }
446
447         // meddle with the key table so someone reading the disassembly won't be able to get key values unless they're _REALLY_ careful
448         for(idx=0; idx<NUM_LVL1_KEYS; idx++){
449                 Lvl1_keys[idx] ^= (haha_you_dumbass >> 2);
450         }
451
452         Encrypt_inited = 1;
453 }