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.3 2002/06/09 04:41:25 relnev
19 * added copyright header
21 * Revision 1.2 2002/05/07 03:16:48 theoddone33
22 * The Great Newline Fix
24 * Revision 1.1.1.1 2002/05/03 03:28:10 root
28 * 5 4/07/99 5:41p Anoop
29 * Fixed encryption in the launcher.
31 * 4 3/25/99 11:55a Dave
32 * Fixed up encrypt a bit.
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.
38 * 2 10/07/98 10:53a Dave
41 * 1 10/07/98 10:50a Dave
43 * 5 8/09/98 4:44p Lawrance
44 * support alternate encryption scheme (doesn't pack chars into 7 bits)
46 * 4 4/01/98 2:21p Lawrance
47 * check for wacky apostrophe char
49 * 3 3/31/98 4:57p Lawrance
50 * Add signature at the beginning of encrypted files
52 * 2 3/31/98 1:14a Lawrance
53 * Get .tbl and mission file encryption working.
55 * 1 3/30/98 11:02p Lawrance
64 #define ENCRYPT_NEW // new, better encryption scheme
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
73 int Encrypt_inited = 0;
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);
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)
82 ubyte * ptr = (ubyte *)buffer;
83 unsigned int sum1,sum2;
85 sum1 = sum2 = (int)(seed);
89 if (sum1 >= 255 ) sum1 -= 255;
94 return (unsigned short)((sum1<<8)+ sum2);
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)
107 encrypt_new(text, text_len, scrambled_text, scrambled_len);
115 // Identify encrypted files with a unique signature
117 memcpy(scrambled_text, &Encrypt_signature_8bit, 4);
119 memcpy(scrambled_text, &Encrypt_signature, 4);
123 // First stage: packing chars into 7 bit boundries
124 for ( i =0; i < text_len; i++ ) {
126 // account for wacky apostrophe that has ascii code 0x92
127 if ( (unsigned char)text[i] == 0x92 ) {
132 scrambled_text[byte_offset++] = text[i];
136 scrambled_text[byte_offset] = (char)((text[i] << 1) & 0xfe);
140 scrambled_text[byte_offset] &= 0x80; // clear out bottom 7 bits
141 scrambled_text[byte_offset] |= (text[i] & 0x7F);
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
149 scrambled_text[byte_offset] = (char)((text[i] << 7) & 0x80); // put in last bit
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
156 scrambled_text[byte_offset] = (char)((text[i] << 6) & 0xc0); // put in last two bits
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
163 scrambled_text[byte_offset] = (char)((text[i] << 5) & 0xe0); // put in last three bits
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
170 scrambled_text[byte_offset] = (char)((text[i] << 4) & 0xf0); // put in last four bits
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
177 scrambled_text[byte_offset] = (char)((text[i] << 3) & 0xf8); // put in last five bits
181 scrambled_text[byte_offset] &= 0xfe; // clear out bottom bit
182 scrambled_text[byte_offset] |= ((text[i] >> 6) & 0x01); // put in top bit
184 scrambled_text[byte_offset] = (char)((text[i] << 2) & 0xfc); // put in last six bits
193 if ( bit_offset > 0 ) {
197 *scrambled_len = byte_offset;
199 // Second stage: XOR with offset into file (skip signature)
201 int len = *scrambled_len - 4;
202 for ( i =0; i < len; i++ ) {
203 scrambled_text[i] ^= i;
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)
215 unencrypt_new(scrambled_text, scrambled_len, text, text_len);
218 int scramble_offset = 0;
224 // Only decrpyt files that start with unique signature
225 memcpy(&encrypt_id, scrambled_text, 4);
227 if ( (encrypt_id != Encrypt_signature) && (encrypt_id != Encrypt_signature_8bit) ) {
228 memcpy(text, scrambled_text, scrambled_len);
229 *text_len = scrambled_len;
236 // First decrypt stage: undo XOR operation
237 for ( i =0; i < scrambled_len; i++ ) {
238 scrambled_text[i] ^= i;
241 if (encrypt_id == Encrypt_signature_8bit) {
242 memcpy(text, scrambled_text, scrambled_len);
243 *text_len = scrambled_len;
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 ) {
253 for ( i =0; i < num_runs; i++ ) {
254 // a run consists of 8 chars packed into 56 bits (instead of 64)
256 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 1) & 0x7f);
260 if ( scramble_offset >= scrambled_len ) {
264 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 2) & 0x3f);
265 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 6) & 0x40 );
269 if ( scramble_offset >= scrambled_len ) {
273 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 3) & 0x1f);
274 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 5) & 0x60 );
278 if ( scramble_offset >= scrambled_len ) {
282 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 4) & 0x0f);
283 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 4) & 0x70 );
287 if ( scramble_offset >= scrambled_len ) {
291 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 5) & 0x07);
292 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 3) & 0x78 );
296 if ( scramble_offset >= scrambled_len ) {
300 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 6) & 0x03);
301 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 2) & 0x7c );
305 if ( scramble_offset >= scrambled_len ) {
309 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 7) & 0x01);
310 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 1) & 0x7e );
313 maybe_last = (char)(scrambled_text[scramble_offset] & 0x7f);
314 if ( maybe_last > 0 ) {
315 text[byte_offset] = maybe_last;
321 *text_len = byte_offset;
325 #define NUM_LVL1_KEYS 11
326 ushort Lvl1_keys[NUM_LVL1_KEYS] = {
335 // scramble text data
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)
343 ushort lvl1_block[NUM_LVL1_KEYS * 2];
344 ushort block_checksum;
347 // add the encrpytion signature
348 memcpy(scrambled_text, &Encrypt_new_signature, 4);
350 // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes
351 block_checksum = 0xffff;
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;
359 // if we have at least one full block left
361 memcpy(lvl1_block, text + *scrambled_len, NUM_LVL1_KEYS * 2);
362 block_size = NUM_LVL1_KEYS * 2;
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);
371 // the running checksum
372 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block, block_size);
374 // copy into the outgoing buffer
375 memcpy(scrambled_text + *scrambled_len + 4, lvl1_block, block_size);
376 *scrambled_len += block_size;
379 // add the 4 bytes for the header
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)
390 ushort lvl1_block[NUM_LVL1_KEYS * 2];
391 ushort lvl1_block_copy[NUM_LVL1_KEYS * 2];
392 ushort block_checksum;
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;
404 // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes
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;
415 // if we have at least one full block left
417 memcpy(lvl1_block, scrambled_text + *text_len, NUM_LVL1_KEYS * 2);
418 block_size = NUM_LVL1_KEYS * 2;
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);
428 // the running checksum
429 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block_copy, block_size);
431 // copy into the outgoing buffer
432 memcpy(text + *text_len, lvl1_block, block_size);
433 *text_len += block_size;
437 // Return 1 if the data is encrypted, otherwise return 0
438 int is_encrpyted(char *scrambled_text)
442 memcpy(&encrypt_id, scrambled_text, 4);
444 if ( (encrypt_id == Encrypt_signature) || (encrypt_id == Encrypt_signature_8bit) || (encrypt_id == Encrypt_new_signature)) {
451 // initialize encryption
455 ushort haha_you_dumbass = 0xe2A8;
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);