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