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.5 2004/06/11 02:04:35 tigital
19 * byte-swapping changes for bigendian systems
21 * Revision 1.4 2003/05/25 02:30:43 taylor
24 * Revision 1.3 2002/06/09 04:41:25 relnev
25 * added copyright header
27 * Revision 1.2 2002/05/07 03:16:48 theoddone33
28 * The Great Newline Fix
30 * Revision 1.1.1.1 2002/05/03 03:28:10 root
34 * 5 4/07/99 5:41p Anoop
35 * Fixed encryption in the launcher.
37 * 4 3/25/99 11:55a Dave
38 * Fixed up encrypt a bit.
40 * 3 3/25/99 11:26a Dave
41 * Beefed up encryption scheme so that even someone viewing the
42 * disassembly would have a hard time cracking it.
44 * 2 10/07/98 10:53a Dave
47 * 1 10/07/98 10:50a Dave
49 * 5 8/09/98 4:44p Lawrance
50 * support alternate encryption scheme (doesn't pack chars into 7 bits)
52 * 4 4/01/98 2:21p Lawrance
53 * check for wacky apostrophe char
55 * 3 3/31/98 4:57p Lawrance
56 * Add signature at the beginning of encrypted files
58 * 2 3/31/98 1:14a Lawrance
59 * Get .tbl and mission file encryption working.
61 * 1 3/30/98 11:02p Lawrance
71 #define ENCRYPT_NEW // new, better encryption scheme
77 #if SDL_BYTEORDER != SDL_BIG_ENDIAN
78 const uint Encrypt_new_signature = 0x5c331a55; // new encrpytion
79 const uint Encrypt_signature = 0xdeadbeef; // full encryption
80 const uint Encrypt_signature_8bit = 0xcacacaca; // light encryption - doesn't use 7bit chars
82 const uint Encrypt_new_signature = 0x551a335c; // new encrpytion
83 const uint Encrypt_signature = 0xefbeadde; // full encryption
84 const uint Encrypt_signature_8bit = 0xcacacaca; // light encryption - doesn't use 7bit chars
87 int Encrypt_inited = 0;
90 void encrypt_new(char *text, int text_len, char *scrambled_text, int *scrambled_len);
91 void unencrypt_new(char *scrambled_text, int scrambled_len, char *text, int *text_len);
93 // update cur_seed with the chksum of the new_data of size new_data_size
94 ushort chksum_add_short(ushort seed, char *buffer, int size)
96 ubyte * ptr = (ubyte *)buffer;
97 unsigned int sum1,sum2;
99 sum1 = sum2 = (int)(seed);
103 if (sum1 >= 255 ) sum1 -= 255;
108 return (unsigned short)((sum1<<8)+ sum2);
111 // scramble text data
113 // input: text => ascii data to be scrambled
114 // text_len => number of bytes of ascii data to scramble
115 // scrambled_text => storage for scrambled text (malloc at least text_len)
116 // scrambled_len => size of text after getting scrambled
117 // use_8bit => flag to indicate that chars are stored using 8 bits (default value is 0)
118 void encrypt(char *text, int text_len, char *scrambled_text, int *scrambled_len, int use_8bit)
121 encrypt_new(text, text_len, scrambled_text, scrambled_len);
129 // Identify encrypted files with a unique signature
131 memcpy(scrambled_text, &Encrypt_signature_8bit, 4);
133 memcpy(scrambled_text, &Encrypt_signature, 4);
137 // First stage: packing chars into 7 bit boundries
138 for ( i =0; i < text_len; i++ ) {
140 // account for wacky apostrophe that has ascii code 0x92
141 if ( (unsigned char)text[i] == 0x92 ) {
146 scrambled_text[byte_offset++] = text[i];
150 scrambled_text[byte_offset] = (char)((text[i] << 1) & 0xfe);
154 scrambled_text[byte_offset] &= 0x80; // clear out bottom 7 bits
155 scrambled_text[byte_offset] |= (text[i] & 0x7F);
160 scrambled_text[byte_offset] &= 0xc0; // clear out bottom 6 bits
161 scrambled_text[byte_offset] |= ((text[i] >> 1) & 0x3F); // put in top 6 bits
163 scrambled_text[byte_offset] = (char)((text[i] << 7) & 0x80); // put in last bit
167 scrambled_text[byte_offset] &= 0xe0; // clear out bottom 5 bits
168 scrambled_text[byte_offset] |= ((text[i] >> 2) & 0x1F); // put in top 5 bits
170 scrambled_text[byte_offset] = (char)((text[i] << 6) & 0xc0); // put in last two bits
174 scrambled_text[byte_offset] &= 0xf0; // clear out bottom 4 bits
175 scrambled_text[byte_offset] |= ((text[i] >> 3) & 0x0F); // put in top 4 bits
177 scrambled_text[byte_offset] = (char)((text[i] << 5) & 0xe0); // put in last three bits
181 scrambled_text[byte_offset] &= 0xf8; // clear out bottom 3 bits
182 scrambled_text[byte_offset] |= ((text[i] >> 4) & 0x07); // put in top 3 bits
184 scrambled_text[byte_offset] = (char)((text[i] << 4) & 0xf0); // put in last four bits
188 scrambled_text[byte_offset] &= 0xfc; // clear out bottom 2 bits
189 scrambled_text[byte_offset] |= ((text[i] >> 5) & 0x03); // put in top 2 bits
191 scrambled_text[byte_offset] = (char)((text[i] << 3) & 0xf8); // put in last five bits
195 scrambled_text[byte_offset] &= 0xfe; // clear out bottom bit
196 scrambled_text[byte_offset] |= ((text[i] >> 6) & 0x01); // put in top bit
198 scrambled_text[byte_offset] = (char)((text[i] << 2) & 0xfc); // put in last six bits
207 if ( bit_offset > 0 ) {
211 *scrambled_len = byte_offset;
213 // Second stage: XOR with offset into file (skip signature)
215 int len = *scrambled_len - 4;
216 for ( i =0; i < len; i++ ) {
217 scrambled_text[i] ^= i;
222 // input: scrambled_text => scrambled text
223 // scrambled_len => number of bytes of scrambled text
224 // text => storage for unscrambled ascii data
225 // text_len => actual number of bytes of unscrambled data
226 void unencrypt(char *scrambled_text, int scrambled_len, char *text, int *text_len)
229 unencrypt_new(scrambled_text, scrambled_len, text, text_len);
232 int scramble_offset = 0;
238 // Only decrpyt files that start with unique signature
239 memcpy(&encrypt_id, scrambled_text, 4);
241 if ( (encrypt_id != Encrypt_signature) && (encrypt_id != Encrypt_signature_8bit) ) {
242 memcpy(text, scrambled_text, scrambled_len);
243 *text_len = scrambled_len;
250 // First decrypt stage: undo XOR operation
251 for ( i =0; i < scrambled_len; i++ ) {
252 scrambled_text[i] ^= i;
255 if (encrypt_id == Encrypt_signature_8bit) {
256 memcpy(text, scrambled_text, scrambled_len);
257 *text_len = scrambled_len;
261 // Second decrypt stage: remove chars from 7 bit packing to 8 bit boundries
262 num_runs = (int) (scrambled_len / 7.0f );
263 if ( scrambled_len % 7 ) {
267 for ( i =0; i < num_runs; i++ ) {
268 // a run consists of 8 chars packed into 56 bits (instead of 64)
270 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 1) & 0x7f);
274 if ( scramble_offset >= scrambled_len ) {
278 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 2) & 0x3f);
279 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 6) & 0x40 );
283 if ( scramble_offset >= scrambled_len ) {
287 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 3) & 0x1f);
288 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 5) & 0x60 );
292 if ( scramble_offset >= scrambled_len ) {
296 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 4) & 0x0f);
297 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 4) & 0x70 );
301 if ( scramble_offset >= scrambled_len ) {
305 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 5) & 0x07);
306 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 3) & 0x78 );
310 if ( scramble_offset >= scrambled_len ) {
314 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 6) & 0x03);
315 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 2) & 0x7c );
319 if ( scramble_offset >= scrambled_len ) {
323 text[byte_offset] = (char)((scrambled_text[scramble_offset] >> 7) & 0x01);
324 text[byte_offset] |= ( (scrambled_text[scramble_offset-1] << 1) & 0x7e );
327 maybe_last = (char)(scrambled_text[scramble_offset] & 0x7f);
328 if ( maybe_last > 0 ) {
329 text[byte_offset] = maybe_last;
335 *text_len = byte_offset;
339 #define NUM_LVL1_KEYS 11
340 ushort Lvl1_keys[NUM_LVL1_KEYS] = {
349 // scramble text data
351 // input: text => ascii data to be scrambled
352 // text_len => number of bytes of ascii data to scramble
353 // scrambled_text => storage for scrambled text (malloc at least text_len)
354 // scrambled_len => size of text after getting scrambled
355 void encrypt_new(char *text, int text_len, char *scrambled_text, int *scrambled_len)
357 ushort lvl1_block[NUM_LVL1_KEYS * 2];
358 ushort block_checksum;
361 // add the encrpytion signature
362 memcpy(scrambled_text, &Encrypt_new_signature, 4);
364 // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes
365 block_checksum = 0xffff;
367 while(*scrambled_len < text_len){
368 // if we have less than one block left
369 if((text_len - *scrambled_len) < (NUM_LVL1_KEYS * 2)){
370 memcpy(lvl1_block, text + *scrambled_len, text_len - *scrambled_len);
371 block_size = text_len - *scrambled_len;
373 // if we have at least one full block left
375 memcpy(lvl1_block, text + *scrambled_len, NUM_LVL1_KEYS * 2);
376 block_size = NUM_LVL1_KEYS * 2;
379 // run the lvl1 over the block
380 for(idx=0; idx<block_size/2; idx++){
381 // the base key with the running checksum from the _last_ block
382 lvl1_block[idx] ^= (Lvl1_keys[idx] ^ block_checksum);
385 // the running checksum
386 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block, block_size);
388 // copy into the outgoing buffer
389 memcpy(scrambled_text + *scrambled_len + 4, lvl1_block, block_size);
390 *scrambled_len += block_size;
393 // add the 4 bytes for the header
398 // input: scrambled_text => scrambled text
399 // scrambled_len => number of bytes of scrambled text
400 // text => storage for unscrambled ascii data
401 // text_len => actual number of bytes of unscrambled data
402 void unencrypt_new(char *scrambled_text, int scrambled_len, char *text, int *text_len)
404 ushort lvl1_block[NUM_LVL1_KEYS * 2];
405 ushort lvl1_block_copy[NUM_LVL1_KEYS * 2];
406 ushort block_checksum;
410 // Only decrypt files that start with unique signature
411 memcpy(&encrypt_id, scrambled_text, 4);
412 if (encrypt_id != Encrypt_new_signature) {
413 memcpy(text, scrambled_text, scrambled_len);
414 *text_len = scrambled_len;
418 // go through and read in chunks of NUM_LVL1_KEYS * 2 bytes
422 block_checksum = 0xffff;
423 while(*text_len < scrambled_len){
424 // if we have less than one block left
425 if((scrambled_len - *text_len) < (NUM_LVL1_KEYS * 2)){
426 memcpy(lvl1_block, scrambled_text + *text_len, scrambled_len - *text_len);
427 block_size = scrambled_len - *text_len;
429 // if we have at least one full block left
431 memcpy(lvl1_block, scrambled_text + *text_len, NUM_LVL1_KEYS * 2);
432 block_size = NUM_LVL1_KEYS * 2;
435 // copy the block so that we can properly calculate the next running checksum
436 memcpy(lvl1_block_copy, lvl1_block, block_size);
437 // run the lvl1 over the block
438 for(idx=0; idx<block_size/2; idx++){
439 lvl1_block[idx] ^= (Lvl1_keys[idx] ^ block_checksum);
442 // the running checksum
443 block_checksum = chksum_add_short(block_checksum, (char*)lvl1_block_copy, block_size);
445 // copy into the outgoing buffer
446 memcpy(text + *text_len, lvl1_block, block_size);
447 *text_len += block_size;
451 // Return 1 if the data is encrypted, otherwise return 0
452 int is_encrpyted(char *scrambled_text)
456 memcpy(&encrypt_id, scrambled_text, 4);
458 if ( (encrypt_id == Encrypt_signature) || (encrypt_id == Encrypt_signature_8bit) || (encrypt_id == Encrypt_new_signature)) {
465 // initialize encryption
469 ushort haha_you_dumbass = 0xe2A8;
475 // meddle with the key table so someone reading the disassembly won't be able to get key values unless they're _REALLY_ careful
476 for(idx=0; idx<NUM_LVL1_KEYS; idx++){
477 Lvl1_keys[idx] ^= (haha_you_dumbass >> 2);