home *** CD-ROM | disk | FTP | other *** search
- PROGRAM decipher;
- {
- Program: DECIPHER.TUR
-
- Author: James L. Dean
- 406 40th Street
- New Orleans, LA 70124
-
- Date Written: September 10, 1984
-
- Language: Turbo Pascal
-
- Operating System: MS-DOS 2.0
-
- Machine: Zenith Data Systems Corporation Z-100
-
- Microprocessor: Intel Corporation 8088
-
- Remarks.
-
- This program uses a fractionating cipher to decipher a file.
-
- The file is updated in place. WARNING: If the decipherment process
- is aborted, only part of the file will be deciphered. To recover
- from this, a copy of the file must be deciphered and the plaintext
- from that file must be merged with the plaintext in the original file.
-
- For each sector (128 bytes) of the file, sixteen substitutions of
- bytes for bytes in the sector are alternated with sixteen permutations of
- the half bytes in the sector. Two permutations alternated with two
- substitutions would produce a faster though less secure cipher.
- WARNING: If a byte in a sector is read incorrectly, that sector will be
- deciphered incorrectly.
-
- Only one permutation pattern and one substitution pattern are used.
- These patterns are fixed by a thirty (or fewer) character key.
- NOTE: If a file is deciphered with the wrong key, it can be restored to
- its original enciphered state by enciphering it with that key.
- }
- TYPE
- direct_access_file = FILE;
- sector_half_bytes = ARRAY [0..255] OF INTEGER;
- VAR
- disk_file : direct_access_file;
- permutation : sector_half_bytes;
- substitution : sector_half_bytes;
- PROCEDURE print_title;
- BEGIN
- ClrScr;
- WRITELN(OUTPUT,' Decipher');
- WRITELN(OUTPUT,' ');
- WRITELN(OUTPUT,' ');
- WRITELN(OUTPUT,' ')
- END;
- PROCEDURE open_plaintext{(VAR disk_file : direct_access_file)};
- VAR
- file_name : STRING[14];
- BEGIN
- WRITE(OUTPUT,'File? ');
- READLN(INPUT,file_name);
- ASSIGN(disk_file,file_name);
- RESET(disk_file)
- END;
- PROCEDURE generate_patterns{(
- VAR permutation : sector_half_bytes;
- VAR substitution : sector_half_bytes)};
- TYPE
- key_string = STRING[30];
- r_n_array = ARRAY [1..30] OF INTEGER;
- VAR
- add_index : INTEGER;
- key_1 : key_string;
- previous_random_number : r_n_array;
- r_n_partial_sum : INTEGER;
- replace_index : INTEGER;
- PROCEDURE get_key{(VAR key_1 : key_string)};
- VAR
- key_2 : key_string;
- key_index : INTEGER;
- BEGIN
- {
- Obtain the thirty character key. Since the key is not
- displayed, the user is required to enter the key twice until
- the two entries match. For the same reason, lowercase
- characters are converted to uppercase.
- }
- REPEAT
- WRITELN(OUTPUT,' ');
- WRITE(OUTPUT,'Key? ');
- READLN(KBD,key_1);
- WHILE (LENGTH(key_1) < 30) DO
- key_1:=CONCAT(key_1,' ');
- WRITELN(OUTPUT,' ');
- WRITE(OUTPUT,'Again? ');
- READLN(KBD,key_2);
- WHILE (LENGTH(key_2) < 30) DO
- key_2:=CONCAT(key_2,' ');
- WRITELN(OUTPUT,' ');
- FOR key_index:=1 TO 30 DO
- BEGIN
- key_1[key_index]:=UPCASE(key_1[key_index]);
- key_2[key_index]:=UPCASE(key_2[key_index]);
- END;
- IF key_1 <> key_2 THEN
- WRITELN(OUTPUT,'? The two entries are not the same')
- UNTIL (key_1 = key_2)
- END;
- PROCEDURE seed_random_number_generator{(
- VAR key_1 : key_string;
- VAR previous_random_number : r_n_array;
- VAR r_n_partial_sum : INTEGER;
- VAR add_index : INTEGER;
- VAR replace_index : INTEGER)};
- VAR
- key_index : INTEGER;
- BEGIN
- {
- Use the position in the collating sequence of each character
- of the key phrase to supply seeds for the pseudo-random number
- generator.
- }
- FOR key_index:=1 TO 30 DO
- previous_random_number[key_index]:=ORD(key_1[key_index]);
- replace_index:=1;
- add_index:=30;
- r_n_partial_sum:=0;
- FOR key_index:=1 TO 29 DO
- BEGIN
- r_n_partial_sum
- :=r_n_partial_sum+previous_random_number[key_index];
- IF r_n_partial_sum >= 257 THEN
- r_n_partial_sum:=r_n_partial_sum-257
- END
- END;
- FUNCTION random_number{(
- VAR previous_random_number : r_n_array;
- VAR r_n_partial_sum : INTEGER;
- VAR add_index : INTEGER;
- VAR replace_index : INTEGER)} : INTEGER;
- VAR
- r_n : INTEGER;
- BEGIN
- {
- Each pseudo-random number is the modulo sum of the
- previous thirty pseudo-random numbers. A prime modulus
- makes it likely that the pseudo-random numbers will be
- uniformly distributed. To speed computation, a partial
- sum of 29 of the 30 previous pseudo-random numbers is
- maintained.
- }
- REPEAT
- r_n:=r_n_partial_sum+previous_random_number[add_index];
- IF r_n >= 257 THEN r_n:=r_n-257;
- r_n_partial_sum
- :=r_n-previous_random_number[replace_index];
- IF r_n_partial_sum < 0 THEN
- r_n_partial_sum:=r_n_partial_sum+257;
- previous_random_number[replace_index]:=r_n;
- add_index:=replace_index;
- replace_index:=replace_index+1;
- IF replace_index > 30 THEN
- replace_index:=1
- UNTIL
- (r_n <= 255);
- random_number:=r_n
- END;
- PROCEDURE generate_substitution_pattern{(
- VAR previous_random_number : r_n_array;
- VAR r_n_partial_sum : INTEGER;
- VAR add_index : INTEGER;
- VAR replace_index : INTEGER;
- VAR substitution : sector_half_bytes)};
- VAR
- byte_value : INTEGER;
- encipherment : sector_half_bytes;
- index_1 : INTEGER;
- index_2 : INTEGER;
- tem : BYTE;
- BEGIN
- FOR byte_value:=0 TO 255 DO
- encipherment[byte_value]:=byte_value;
- FOR index_1:=0 TO 255 DO
- BEGIN
- index_2:=random_number{(previous_random_number,
- r_n_partial_sum,add_index,replace_index)};
- tem:=encipherment[index_1];
- encipherment[index_1]:=encipherment[index_2];
- encipherment[index_2]:=tem
- END;
- FOR index_1:=0 TO 255 DO
- substitution[encipherment[index_1]]:=index_1
- END;
- PROCEDURE generate_permutation_pattern{(
- VAR previous_random_number : r_n_array;
- VAR r_n_partial_sum : INTEGER;
- VAR add_index : INTEGER;
- VAR replace_index : INTEGER;
- VAR permutation : sector_half_bytes)};
- VAR
- byte_value : INTEGER;
- index_1 : INTEGER;
- index_2 : INTEGER;
- tem : INTEGER;
- BEGIN
- FOR byte_value:=0 TO 255 DO
- permutation[byte_value]:=byte_value;
- FOR index_1:=0 TO 255 DO
- BEGIN
- index_2:=random_number{(previous_random_number,
- r_n_partial_sum,add_index,replace_index)};
- tem:=permutation[index_1];
- permutation[index_1]:=permutation[index_2];
- permutation[index_2]:=tem
- END
- END;
- BEGIN
- get_key{(key_1)};
- seed_random_number_generator{(key_1,previous_random_number,
- r_n_partial_sum,add_index,replace_index)};
- generate_substitution_pattern{(previous_random_number,
- r_n_partial_sum,add_index,replace_index,substitution)};
- generate_permutation_pattern{(previous_random_number,
- r_n_partial_sum,add_index,replace_index,permutation)}
- END;
- PROCEDURE decipher_each_sector{(
- VAR disk_file : direct_access_file;
- VAR permutation : sector_half_bytes;
- VAR substitution : sector_half_bytes)};
- TYPE
- sector_bytes = ARRAY [1..128] OF BYTE;
- VAR
- high_order_half_byte : sector_half_bytes;
- iteration : INTEGER;
- low_order_half_byte : sector_half_bytes;
- number_of_sectors : INTEGER;
- sector : sector_bytes;
- sector_index : INTEGER;
- text_1_half_byte : sector_half_bytes;
- text_2_half_byte : sector_half_bytes;
- PROCEDURE set_up_half_byte_translation{(
- VAR high_order_half_byte : sector_half_bytes;
- VAR low_order_half_byte : sector_half_bytes)};
- VAR
- byte_value : INTEGER;
- half_byte_index_1 : INTEGER;
- half_byte_index_2 : INTEGER;
- BEGIN
- byte_value:=0;
- FOR half_byte_index_1:=0 TO 15 DO
- FOR half_byte_index_2:=0 TO 15 DO
- BEGIN
- low_order_half_byte[byte_value]:=half_byte_index_2;
- high_order_half_byte[byte_value]:=half_byte_index_1;
- byte_value:=byte_value+1
- END
- END;
- PROCEDURE read_sector{(
- VAR disk_file : direct_access_file;
- VAR sector_index : INTEGER;
- VAR sector : sector_bytes)};
- BEGIN
- SEEK(disk_file,sector_index);
- BLOCKREAD(disk_file,sector,1)
- END;
- PROCEDURE translate_sector_to_half_bytes{(
- VAR sector : sector_bytes;
- VAR text_1_half_byte : sector_half_bytes;
- VAR low_order_half_byte : sector_half_bytes;
- VAR high_order_half_byte : sector_half_bytes)};
- VAR
- byte_in_sector : INTEGER;
- byte_value : INTEGER;
- half_byte_index : INTEGER;
- BEGIN
- half_byte_index:=0;
- FOR byte_in_sector:=1 TO 128 DO
- BEGIN
- byte_value:=sector[byte_in_sector];
- text_1_half_byte[half_byte_index]
- :=high_order_half_byte[byte_value];
- half_byte_index:=half_byte_index+1;
- text_1_half_byte[half_byte_index]
- :=low_order_half_byte[byte_value];
- half_byte_index:=half_byte_index+1
- END
- END;
- PROCEDURE permute_half_bytes{(
- VAR permutation : sector_half_bytes;
- VAR text_2_half_byte : sector_half_bytes;
- VAR text_1_half_byte : sector_half_bytes)};
- VAR
- half_byte_index : INTEGER;
- BEGIN
- FOR half_byte_index:=0 TO 255 DO
- text_1_half_byte[half_byte_index]
- :=text_2_half_byte[permutation[half_byte_index]]
- END;
- PROCEDURE substitute_bytes{(
- VAR substitution : sector_half_bytes;
- VAR text_1_half_byte : sector_half_bytes;
- VAR text_2_half_byte : sector_half_bytes;
- VAR low_order_half_byte : sector_half_bytes;
- VAR high_order_half_byte : sector_half_bytes)};
- VAR
- byte_in_sector : INTEGER;
- byte_value : INTEGER;
- half_byte_index_1 : INTEGER;
- half_byte_index_2 : INTEGER;
- BEGIN
- half_byte_index_1:=0;
- half_byte_index_2:=1;
- FOR byte_in_sector:=1 TO 128 DO
- BEGIN
- byte_value
- :=substitution[16*text_1_half_byte[half_byte_index_1]
- +text_1_half_byte[half_byte_index_2]];
- text_2_half_byte[half_byte_index_1]
- :=high_order_half_byte[byte_value];
- text_2_half_byte[half_byte_index_2]
- :=low_order_half_byte[byte_value];
- half_byte_index_1:=half_byte_index_1+2;
- half_byte_index_2:=half_byte_index_2+2
- END
- END;
- PROCEDURE translate_half_bytes_to_sector{(
- VAR text_1_half_byte : sector_half_bytes;
- VAR sector : sector_bytes)};
- VAR
- byte_in_sector : INTEGER;
- half_byte_index_1 : INTEGER;
- half_byte_index_2 : INTEGER;
- BEGIN
- half_byte_index_1:=0;
- half_byte_index_2:=1;
- FOR byte_in_sector:=1 TO 128 DO
- BEGIN
- sector[byte_in_sector]:=16*text_1_half_byte[half_byte_index_1]
- +text_1_half_byte[half_byte_index_2];
- half_byte_index_1:=half_byte_index_1+2;
- half_byte_index_2:=half_byte_index_2+2
- END;
- END;
- PROCEDURE rewrite_sector{(
- VAR disk_file : direct_access_file;
- VAR sector_index : INTEGER;
- VAR sector : sector_bytes)};
- BEGIN
- SEEK(disk_file,sector_index);
- BLOCKWRITE(disk_file,sector,1)
- END;
- BEGIN
- set_up_half_byte_translation{(
- high_order_half_byte,low_order_half_byte)};
- number_of_sectors:=FILESIZE(disk_file);
- sector_index:=0;
- WHILE (sector_index < number_of_sectors) DO
- BEGIN
- read_sector{(disk_file,sector_index,sector)};
- translate_sector_to_half_bytes{(
- sector,
- text_1_half_byte,low_order_half_byte,high_order_half_byte)};
- {
- For a faster though less secure cipher, use
- "FOR iteration:=1 TO 2 DO" in place of the next line.
- }
- FOR iteration:=1 TO 16 DO
- BEGIN
- substitute_bytes{(
- substitution,text_1_half_byte,text_2_half_byte,
- low_order_half_byte,high_order_half_byte)};
- permute_half_bytes{(
- permutation,text_2_half_byte,text_1_half_byte)}
- END;
- translate_half_bytes_to_sector{(
- text_1_half_byte,sector)};
- rewrite_sector{(disk_file,sector_index,sector)};
- sector_index:=sector_index+1
- END
- END;
- BEGIN
- print_title;
- open_plaintext{(disk_file)};
- generate_patterns{(permutation,substitution)};
- decipher_each_sector{(disk_file,permutation,substitution)};
- CLOSE(disk_file)
- END.