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