2 * $Logfile: /Freespace2/code/parse/Encrypt.cpp $
7 * Module for encryption code common to FreeSpace and related tools
10 * Revision 1.2 2002/05/07 03:16:48 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:10 root
17 * 5 4/07/99 5:41p Anoop
18 * Fixed encryption in the launcher.
20 * 4 3/25/99 11:55a Dave
21 * Fixed up encrypt a bit.
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.
27 * 2 10/07/98 10:53a Dave
30 * 1 10/07/98 10:50a Dave
32 * 5 8/09/98 4:44p Lawrance
33 * support alternate encryption scheme (doesn't pack chars into 7 bits)
35 * 4 4/01/98 2:21p Lawrance
36 * check for wacky apostrophe char
38 * 3 3/31/98 4:57p Lawrance
39 * Add signature at the beginning of encrypted files
41 * 2 3/31/98 1:14a Lawrance
42 * Get .tbl and mission file encryption working.
44 * 1 3/30/98 11:02p Lawrance
53 #define ENCRYPT_NEW // new, better encryption scheme
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
62 int Encrypt_inited = 0;
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);
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)
71 ubyte * ptr = (ubyte *)buffer;
72 unsigned int sum1,sum2;
74 sum1 = sum2 = (int)(seed);
78 if (sum1 >= 255 ) sum1 -= 255;
83 return (unsigned short)((sum1<<8)+ sum2);
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)
96 encrypt_new(text, text_len, scrambled_text, scrambled_len);
104 // Identify encrypted files with a unique signature
106 memcpy(scrambled_text, &Encrypt_signature_8bit, 4);
108 memcpy(scrambled_text, &Encrypt_signature, 4);
112 // First stage: packing chars into 7 bit boundries
113 for ( i =0; i < text_len; i++ ) {
115 // account for wacky apostrophe that has ascii code 0x92
116 if ( (unsigned char)text[i] == 0x92 ) {
121 scrambled_text[byte_offset++] = text[i];
125 scrambled_text[byte_offset] = (char)((text[i] << 1) & 0xfe);
129 scrambled_text[byte_offset] &= 0x80; // clear out bottom 7 bits
130 scrambled_text[byte_offset] |= (text[i] & 0x7F);
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
138 scrambled_text[byte_offset] = (char)((text[i] << 7) & 0x80); // put in last bit
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
145 scrambled_text[byte_offset] = (char)((text[i] << 6) & 0xc0); // put in last two bits
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
152 scrambled_text[byte_offset] = (char)((text[i] << 5) & 0xe0); // put in last three bits
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
159 scrambled_text[byte_offset] = (char)((text[i] << 4) & 0xf0); // put in last four bits
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
166 scrambled_text[byte_offset] = (char)((text[i] << 3) & 0xf8); // put in last five bits
170 scrambled_text[byte_offset] &= 0xfe; // clear out bottom bit
171 scrambled_text[byte_offset] |= ((text[i] >> 6) & 0x01); // put in top bit
173 scrambled_text[byte_offset] = (char)((text[i] << 2) & 0xfc); // put in last six bits
182 if ( bit_offset > 0 ) {
186 *scrambled_len = byte_offset;
188 // Second stage: XOR with offset into file (skip signature)
190 int len = *scrambled_len - 4;
191 for ( i =0; i < len; i++ ) {
192 scrambled_text[i] ^= i;
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)
204 unencrypt_new(scrambled_text, scrambled_len, text, text_len);
207 int scramble_offset = 0;
213 // Only decrpyt files that start with unique signature
214 memcpy(&encrypt_id, scrambled_text, 4);
216 if ( (encrypt_id != Encrypt_signature) && (encrypt_id != Encrypt_signature_8bit) ) {
217 memcpy(text, scrambled_text, scrambled_len);
218 *text_len = scrambled_len;
225 // First decrypt stage: undo XOR operation
226 for ( i =0; i < scrambled_len; i++ ) {
227 scrambled_text[i] ^= i;
230 if (encrypt_id == Encrypt_signature_8bit) {
231 memcpy(text, scrambled_text, scrambled_len);
232 *text_len = scrambled_len;
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 ) {
242 for ( i =0; i < num_runs; i++ ) {
243 // a run consists of 8 chars packed into 56 bits (instead of 64)
245 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 1) & 0x7f);
249 if ( scramble_offset >= scrambled_len ) {
253 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 2) & 0x3f);
254 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 6) & 0x40 );
258 if ( scramble_offset >= scrambled_len ) {
262 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 3) & 0x1f);
263 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 5) & 0x60 );
267 if ( scramble_offset >= scrambled_len ) {
271 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 4) & 0x0f);
272 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 4) & 0x70 );
276 if ( scramble_offset >= scrambled_len ) {
280 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 5) & 0x07);
281 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 3) & 0x78 );
285 if ( scramble_offset >= scrambled_len ) {
289 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 6) & 0x03);
290 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 2) & 0x7c );
294 if ( scramble_offset >= scrambled_len ) {
298 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 7) & 0x01);
299 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 1) & 0x7e );
302 maybe_last = (char)(scrambled_text[scramble_offset] & 0x7f);
303 if ( maybe_last > 0 ) {
304 text[byte_offset] = maybe_last;
310 *text_len = byte_offset;
314 #define NUM_LVL1_KEYS 11
315 ushort Lvl1_keys[NUM_LVL1_KEYS] = {
324 // scramble text data
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)
332 ushort lvl1_block[NUM_LVL1_KEYS * 2];
333 ushort block_checksum;
336 // add the encrpytion signature
337 memcpy(scrambled_text, &Encrypt_new_signature, 4);
339 // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes
340 block_checksum = 0xffff;
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;
348 // if we have at least one full block left
350 memcpy(lvl1_block, text + *scrambled_len, NUM_LVL1_KEYS * 2);
351 block_size = NUM_LVL1_KEYS * 2;
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);
360 // the running checksum
361 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block, block_size);
363 // copy into the outgoing buffer
364 memcpy(scrambled_text + *scrambled_len + 4, lvl1_block, block_size);
365 *scrambled_len += block_size;
368 // add the 4 bytes for the header
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)
379 ushort lvl1_block[NUM_LVL1_KEYS * 2];
380 ushort lvl1_block_copy[NUM_LVL1_KEYS * 2];
381 ushort block_checksum;
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;
393 // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes
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;
404 // if we have at least one full block left
406 memcpy(lvl1_block, scrambled_text + *text_len, NUM_LVL1_KEYS * 2);
407 block_size = NUM_LVL1_KEYS * 2;
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);
417 // the running checksum
418 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block_copy, block_size);
420 // copy into the outgoing buffer
421 memcpy(text + *text_len, lvl1_block, block_size);
422 *text_len += block_size;
426 // Return 1 if the data is encrypted, otherwise return 0
427 int is_encrpyted(char *scrambled_text)
431 memcpy(&encrypt_id, scrambled_text, 4);
433 if ( (encrypt_id == Encrypt_signature) || (encrypt_id == Encrypt_signature_8bit) || (encrypt_id == Encrypt_new_signature)) {
440 // initialize encryption
444 ushort haha_you_dumbass = 0xe2A8;
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);