2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/parse/Encrypt.cpp $
15 * Module for encryption code common to FreeSpace and related tools
18 * Revision 1.4 2003/05/25 02:30:43 taylor
21 * Revision 1.3 2002/06/09 04:41:25 relnev
22 * added copyright header
24 * Revision 1.2 2002/05/07 03:16:48 theoddone33
25 * The Great Newline Fix
27 * Revision 1.1.1.1 2002/05/03 03:28:10 root
31 * 5 4/07/99 5:41p Anoop
32 * Fixed encryption in the launcher.
34 * 4 3/25/99 11:55a Dave
35 * Fixed up encrypt a bit.
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.
41 * 2 10/07/98 10:53a Dave
44 * 1 10/07/98 10:50a Dave
46 * 5 8/09/98 4:44p Lawrance
47 * support alternate encryption scheme (doesn't pack chars into 7 bits)
49 * 4 4/01/98 2:21p Lawrance
50 * check for wacky apostrophe char
52 * 3 3/31/98 4:57p Lawrance
53 * Add signature at the beginning of encrypted files
55 * 2 3/31/98 1:14a Lawrance
56 * Get .tbl and mission file encryption working.
58 * 1 3/30/98 11:02p Lawrance
68 #define ENCRYPT_NEW // new, better encryption scheme
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
78 int Encrypt_inited = 0;
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);
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)
87 ubyte * ptr = (ubyte *)buffer;
88 unsigned int sum1,sum2;
90 sum1 = sum2 = (int)(seed);
94 if (sum1 >= 255 ) sum1 -= 255;
99 return (unsigned short)((sum1<<8)+ sum2);
102 // scramble text data
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)
112 encrypt_new(text, text_len, scrambled_text, scrambled_len);
120 // Identify encrypted files with a unique signature
122 memcpy(scrambled_text, &Encrypt_signature_8bit, 4);
124 memcpy(scrambled_text, &Encrypt_signature, 4);
128 // First stage: packing chars into 7 bit boundries
129 for ( i =0; i < text_len; i++ ) {
131 // account for wacky apostrophe that has ascii code 0x92
132 if ( (unsigned char)text[i] == 0x92 ) {
137 scrambled_text[byte_offset++] = text[i];
141 scrambled_text[byte_offset] = (char)((text[i] << 1) & 0xfe);
145 scrambled_text[byte_offset] &= 0x80; // clear out bottom 7 bits
146 scrambled_text[byte_offset] |= (text[i] & 0x7F);
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
154 scrambled_text[byte_offset] = (char)((text[i] << 7) & 0x80); // put in last bit
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
161 scrambled_text[byte_offset] = (char)((text[i] << 6) & 0xc0); // put in last two bits
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
168 scrambled_text[byte_offset] = (char)((text[i] << 5) & 0xe0); // put in last three bits
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
175 scrambled_text[byte_offset] = (char)((text[i] << 4) & 0xf0); // put in last four bits
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
182 scrambled_text[byte_offset] = (char)((text[i] << 3) & 0xf8); // put in last five bits
186 scrambled_text[byte_offset] &= 0xfe; // clear out bottom bit
187 scrambled_text[byte_offset] |= ((text[i] >> 6) & 0x01); // put in top bit
189 scrambled_text[byte_offset] = (char)((text[i] << 2) & 0xfc); // put in last six bits
198 if ( bit_offset > 0 ) {
202 *scrambled_len = byte_offset;
204 // Second stage: XOR with offset into file (skip signature)
206 int len = *scrambled_len - 4;
207 for ( i =0; i < len; i++ ) {
208 scrambled_text[i] ^= i;
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)
220 unencrypt_new(scrambled_text, scrambled_len, text, text_len);
223 int scramble_offset = 0;
229 // Only decrpyt files that start with unique signature
230 memcpy(&encrypt_id, scrambled_text, 4);
232 if ( (encrypt_id != Encrypt_signature) && (encrypt_id != Encrypt_signature_8bit) ) {
233 memcpy(text, scrambled_text, scrambled_len);
234 *text_len = scrambled_len;
241 // First decrypt stage: undo XOR operation
242 for ( i =0; i < scrambled_len; i++ ) {
243 scrambled_text[i] ^= i;
246 if (encrypt_id == Encrypt_signature_8bit) {
247 memcpy(text, scrambled_text, scrambled_len);
248 *text_len = scrambled_len;
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 ) {
258 for ( i =0; i < num_runs; i++ ) {
259 // a run consists of 8 chars packed into 56 bits (instead of 64)
261 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 1) & 0x7f);
265 if ( scramble_offset >= scrambled_len ) {
269 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 2) & 0x3f);
270 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 6) & 0x40 );
274 if ( scramble_offset >= scrambled_len ) {
278 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 3) & 0x1f);
279 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 5) & 0x60 );
283 if ( scramble_offset >= scrambled_len ) {
287 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 4) & 0x0f);
288 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 4) & 0x70 );
292 if ( scramble_offset >= scrambled_len ) {
296 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 5) & 0x07);
297 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 3) & 0x78 );
301 if ( scramble_offset >= scrambled_len ) {
305 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 6) & 0x03);
306 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 2) & 0x7c );
310 if ( scramble_offset >= scrambled_len ) {
314 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 7) & 0x01);
315 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 1) & 0x7e );
318 maybe_last = (char)(scrambled_text[scramble_offset] & 0x7f);
319 if ( maybe_last > 0 ) {
320 text[byte_offset] = maybe_last;
326 *text_len = byte_offset;
330 #define NUM_LVL1_KEYS 11
331 ushort Lvl1_keys[NUM_LVL1_KEYS] = {
340 // scramble text data
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)
348 ushort lvl1_block[NUM_LVL1_KEYS * 2];
349 ushort block_checksum;
352 // add the encrpytion signature
353 memcpy(scrambled_text, &Encrypt_new_signature, 4);
355 // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes
356 block_checksum = 0xffff;
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;
364 // if we have at least one full block left
366 memcpy(lvl1_block, text + *scrambled_len, NUM_LVL1_KEYS * 2);
367 block_size = NUM_LVL1_KEYS * 2;
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);
376 // the running checksum
377 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block, block_size);
379 // copy into the outgoing buffer
380 memcpy(scrambled_text + *scrambled_len + 4, lvl1_block, block_size);
381 *scrambled_len += block_size;
384 // add the 4 bytes for the header
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)
395 ushort lvl1_block[NUM_LVL1_KEYS * 2];
396 ushort lvl1_block_copy[NUM_LVL1_KEYS * 2];
397 ushort block_checksum;
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;
409 // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes
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;
420 // if we have at least one full block left
422 memcpy(lvl1_block, scrambled_text + *text_len, NUM_LVL1_KEYS * 2);
423 block_size = NUM_LVL1_KEYS * 2;
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);
433 // the running checksum
434 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block_copy, block_size);
436 // copy into the outgoing buffer
437 memcpy(text + *text_len, lvl1_block, block_size);
438 *text_len += block_size;
442 // Return 1 if the data is encrypted, otherwise return 0
443 int is_encrpyted(char *scrambled_text)
447 memcpy(&encrypt_id, scrambled_text, 4);
449 if ( (encrypt_id == Encrypt_signature) || (encrypt_id == Encrypt_signature_8bit) || (encrypt_id == Encrypt_new_signature)) {
456 // initialize encryption
460 ushort haha_you_dumbass = 0xe2A8;
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);