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