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