home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / DECIPH.ZIP / DECIPH.PAS
Encoding:
Pascal/Delphi Source File  |  1985-12-28  |  14.6 KB  |  387 lines

  1. PROGRAM decipher;
  2.   {
  3.     Program:           DECIPHER.TUR
  4.       
  5.     Author:            James L. Dean
  6.                        406 40th Street
  7.                        New Orleans, LA 70124
  8.       
  9.     Date Written:      September 10, 1984
  10.        
  11.     Language:          Turbo Pascal
  12.        
  13.     Operating System:  MS-DOS 2.0
  14.  
  15.     Machine:           Zenith Data Systems Corporation Z-100
  16.  
  17.     Microprocessor:    Intel Corporation 8088
  18.  
  19.     Remarks.
  20.  
  21.         This program uses a fractionating cipher to decipher a file.
  22.  
  23.         The file is updated in place.  WARNING:  If the decipherment process
  24.     is aborted, only part of the file will be deciphered.  To recover
  25.     from this, a copy of the file must be deciphered and the plaintext
  26.     from that file must be merged with the plaintext in the original file.
  27.  
  28.         For each sector (128 bytes) of the file, sixteen substitutions of
  29.     bytes for bytes in the sector are alternated with sixteen permutations of
  30.     the half bytes in the sector.  Two permutations alternated with two
  31.     substitutions would produce a faster though less secure cipher. 
  32.     WARNING:  If a byte in a sector is read incorrectly, that sector will be
  33.     deciphered incorrectly.
  34.  
  35.         Only one permutation pattern and one substitution pattern are used.
  36.     These patterns are fixed by a thirty (or fewer) character key.
  37.     NOTE:  If a file is deciphered with the wrong key, it can be restored to
  38.     its original enciphered state by enciphering it with that key.
  39.   }
  40.   TYPE
  41.     direct_access_file = FILE;
  42.     sector_half_bytes = ARRAY [0..255] OF INTEGER;
  43.   VAR
  44.     disk_file                                : direct_access_file;
  45.     permutation                              : sector_half_bytes;
  46.     substitution                             : sector_half_bytes;
  47.   PROCEDURE print_title;
  48.     BEGIN
  49.       ClrScr;
  50.       WRITELN(OUTPUT,'                                    Decipher');
  51.       WRITELN(OUTPUT,' ');
  52.       WRITELN(OUTPUT,' ');
  53.       WRITELN(OUTPUT,' ')
  54.     END;
  55.   PROCEDURE open_plaintext{(VAR disk_file : direct_access_file)};
  56.     VAR
  57.       file_name                           : STRING[14];
  58.     BEGIN
  59.       WRITE(OUTPUT,'File? ');
  60.       READLN(INPUT,file_name);
  61.       ASSIGN(disk_file,file_name);
  62.       RESET(disk_file)
  63.     END;
  64.   PROCEDURE generate_patterns{(
  65.    VAR permutation : sector_half_bytes;
  66.    VAR substitution : sector_half_bytes)}; 
  67.     TYPE 
  68.       key_string = STRING[30];
  69.       r_n_array = ARRAY [1..30] OF INTEGER;
  70.     VAR
  71.       add_index                          : INTEGER;
  72.       key_1                              : key_string;
  73.       previous_random_number             : r_n_array;
  74.       r_n_partial_sum                    : INTEGER;
  75.       replace_index                      : INTEGER;
  76.     PROCEDURE get_key{(VAR key_1 : key_string)};
  77.       VAR
  78.         key_2                            : key_string;
  79.         key_index                        : INTEGER;
  80.       BEGIN
  81.         {
  82.               Obtain the thirty character key.  Since the key is not
  83.           displayed, the user is required to enter the key twice until
  84.           the two entries match.  For the same reason, lowercase
  85.           characters are converted to uppercase.
  86.         }
  87.         REPEAT
  88.           WRITELN(OUTPUT,' ');
  89.           WRITE(OUTPUT,'Key? ');
  90.           READLN(KBD,key_1);
  91.           WHILE (LENGTH(key_1) < 30) DO
  92.             key_1:=CONCAT(key_1,' ');
  93.           WRITELN(OUTPUT,' ');
  94.           WRITE(OUTPUT,'Again? ');
  95.           READLN(KBD,key_2);
  96.           WHILE (LENGTH(key_2) < 30) DO
  97.             key_2:=CONCAT(key_2,' ');
  98.           WRITELN(OUTPUT,' ');
  99.           FOR key_index:=1 TO 30 DO
  100.             BEGIN
  101.               key_1[key_index]:=UPCASE(key_1[key_index]);
  102.               key_2[key_index]:=UPCASE(key_2[key_index]);
  103.             END;
  104.           IF key_1 <> key_2 THEN 
  105.             WRITELN(OUTPUT,'? The two entries are not the same')
  106.         UNTIL (key_1 = key_2)
  107.       END;
  108.     PROCEDURE seed_random_number_generator{(
  109.      VAR key_1 : key_string;
  110.      VAR previous_random_number : r_n_array;
  111.      VAR r_n_partial_sum : INTEGER;
  112.      VAR add_index : INTEGER;
  113.      VAR replace_index : INTEGER)};
  114.       VAR
  115.         key_index                       : INTEGER;
  116.       BEGIN
  117.         {
  118.                Use the position in the collating sequence of each character
  119.           of the key phrase to supply seeds for the pseudo-random number
  120.           generator.
  121.         }
  122.         FOR key_index:=1 TO 30 DO
  123.           previous_random_number[key_index]:=ORD(key_1[key_index]);
  124.         replace_index:=1;
  125.         add_index:=30;
  126.         r_n_partial_sum:=0;
  127.         FOR key_index:=1 TO 29 DO
  128.           BEGIN
  129.             r_n_partial_sum
  130.              :=r_n_partial_sum+previous_random_number[key_index];
  131.             IF r_n_partial_sum >= 257 THEN 
  132.               r_n_partial_sum:=r_n_partial_sum-257
  133.           END
  134.       END;
  135.     FUNCTION random_number{(
  136.      VAR previous_random_number : r_n_array;
  137.      VAR r_n_partial_sum : INTEGER;
  138.      VAR add_index : INTEGER;
  139.      VAR replace_index : INTEGER)} : INTEGER;
  140.       VAR 
  141.         r_n                                    : INTEGER;
  142.       BEGIN
  143.         {
  144.             Each pseudo-random number is the modulo sum of the
  145.           previous thirty pseudo-random numbers.  A prime modulus
  146.           makes it likely that the pseudo-random numbers will be
  147.           uniformly distributed.  To speed computation, a partial
  148.           sum of 29 of the 30 previous pseudo-random numbers is
  149.           maintained.
  150.         }
  151.         REPEAT
  152.           r_n:=r_n_partial_sum+previous_random_number[add_index];
  153.           IF r_n >= 257 THEN r_n:=r_n-257;
  154.           r_n_partial_sum
  155.            :=r_n-previous_random_number[replace_index];
  156.           IF r_n_partial_sum < 0 THEN 
  157.             r_n_partial_sum:=r_n_partial_sum+257;
  158.           previous_random_number[replace_index]:=r_n;
  159.           add_index:=replace_index;
  160.           replace_index:=replace_index+1;
  161.           IF replace_index > 30 THEN
  162.             replace_index:=1
  163.         UNTIL
  164.           (r_n <= 255);
  165.         random_number:=r_n
  166.       END;
  167.     PROCEDURE generate_substitution_pattern{(
  168.      VAR previous_random_number : r_n_array;
  169.      VAR r_n_partial_sum : INTEGER;
  170.      VAR add_index : INTEGER;
  171.      VAR replace_index : INTEGER;
  172.      VAR substitution : sector_half_bytes)};
  173.       VAR
  174.         byte_value                             : INTEGER;
  175.         encipherment                           : sector_half_bytes;
  176.         index_1                                : INTEGER;
  177.         index_2                                : INTEGER;
  178.         tem                                    : BYTE;
  179.       BEGIN
  180.         FOR byte_value:=0 TO 255 DO
  181.           encipherment[byte_value]:=byte_value;
  182.         FOR index_1:=0 TO 255 DO
  183.           BEGIN
  184.             index_2:=random_number{(previous_random_number,
  185.              r_n_partial_sum,add_index,replace_index)};
  186.             tem:=encipherment[index_1];
  187.             encipherment[index_1]:=encipherment[index_2];
  188.             encipherment[index_2]:=tem
  189.           END;
  190.         FOR index_1:=0 TO 255 DO
  191.           substitution[encipherment[index_1]]:=index_1
  192.       END;
  193.     PROCEDURE generate_permutation_pattern{(
  194.      VAR previous_random_number : r_n_array;
  195.      VAR r_n_partial_sum : INTEGER;
  196.      VAR add_index : INTEGER;
  197.      VAR replace_index : INTEGER;
  198.      VAR permutation : sector_half_bytes)};
  199.       VAR
  200.         byte_value                             : INTEGER;
  201.         index_1                                : INTEGER;
  202.         index_2                                : INTEGER;
  203.         tem                                    : INTEGER;
  204.       BEGIN
  205.         FOR byte_value:=0 TO 255 DO
  206.           permutation[byte_value]:=byte_value;
  207.         FOR index_1:=0 TO 255 DO
  208.           BEGIN
  209.             index_2:=random_number{(previous_random_number,
  210.              r_n_partial_sum,add_index,replace_index)};
  211.             tem:=permutation[index_1];
  212.             permutation[index_1]:=permutation[index_2];
  213.             permutation[index_2]:=tem
  214.           END
  215.       END;
  216.     BEGIN
  217.       get_key{(key_1)};
  218.       seed_random_number_generator{(key_1,previous_random_number,
  219.        r_n_partial_sum,add_index,replace_index)};
  220.       generate_substitution_pattern{(previous_random_number,
  221.        r_n_partial_sum,add_index,replace_index,substitution)};
  222.       generate_permutation_pattern{(previous_random_number,
  223.        r_n_partial_sum,add_index,replace_index,permutation)}
  224.     END;
  225.   PROCEDURE decipher_each_sector{(
  226.    VAR disk_file : direct_access_file;
  227.    VAR permutation : sector_half_bytes;
  228.    VAR substitution : sector_half_bytes)};
  229.     TYPE
  230.       sector_bytes = ARRAY [1..128] OF BYTE;
  231.     VAR
  232.       high_order_half_byte               : sector_half_bytes;
  233.       iteration                          : INTEGER;
  234.       low_order_half_byte                : sector_half_bytes;
  235.       number_of_sectors                  : INTEGER;
  236.       sector                             : sector_bytes;
  237.       sector_index                       : INTEGER;
  238.       text_1_half_byte                   : sector_half_bytes;
  239.       text_2_half_byte                   : sector_half_bytes;
  240.     PROCEDURE set_up_half_byte_translation{(
  241.      VAR high_order_half_byte : sector_half_bytes;
  242.      VAR low_order_half_byte : sector_half_bytes)};
  243.       VAR
  244.         byte_value                       : INTEGER;
  245.         half_byte_index_1                : INTEGER;
  246.         half_byte_index_2                : INTEGER;
  247.       BEGIN
  248.         byte_value:=0;
  249.         FOR half_byte_index_1:=0 TO 15 DO
  250.           FOR half_byte_index_2:=0 TO 15 DO
  251.             BEGIN
  252.               low_order_half_byte[byte_value]:=half_byte_index_2;
  253.               high_order_half_byte[byte_value]:=half_byte_index_1;
  254.               byte_value:=byte_value+1
  255.             END
  256.       END;
  257.     PROCEDURE read_sector{(
  258.      VAR disk_file : direct_access_file;
  259.      VAR sector_index : INTEGER;
  260.      VAR sector : sector_bytes)};
  261.       BEGIN
  262.         SEEK(disk_file,sector_index);
  263.         BLOCKREAD(disk_file,sector,1)
  264.       END;
  265.     PROCEDURE translate_sector_to_half_bytes{(
  266.      VAR sector : sector_bytes;
  267.      VAR text_1_half_byte : sector_half_bytes;
  268.      VAR low_order_half_byte : sector_half_bytes;
  269.      VAR high_order_half_byte : sector_half_bytes)};
  270.       VAR
  271.         byte_in_sector                  : INTEGER;
  272.         byte_value                      : INTEGER;
  273.         half_byte_index                 : INTEGER;
  274.       BEGIN
  275.         half_byte_index:=0;
  276.         FOR byte_in_sector:=1 TO 128 DO
  277.           BEGIN
  278.             byte_value:=sector[byte_in_sector];
  279.             text_1_half_byte[half_byte_index]
  280.              :=high_order_half_byte[byte_value];
  281.             half_byte_index:=half_byte_index+1;
  282.             text_1_half_byte[half_byte_index]
  283.              :=low_order_half_byte[byte_value];
  284.             half_byte_index:=half_byte_index+1
  285.           END
  286.       END;
  287.     PROCEDURE permute_half_bytes{(
  288.      VAR permutation : sector_half_bytes;
  289.      VAR text_2_half_byte : sector_half_bytes;
  290.      VAR text_1_half_byte : sector_half_bytes)};
  291.       VAR
  292.         half_byte_index                      : INTEGER;
  293.       BEGIN
  294.         FOR half_byte_index:=0 TO 255 DO
  295.           text_1_half_byte[half_byte_index]
  296.            :=text_2_half_byte[permutation[half_byte_index]]
  297.       END;
  298.     PROCEDURE substitute_bytes{(
  299.      VAR substitution : sector_half_bytes;
  300.      VAR text_1_half_byte : sector_half_bytes;
  301.      VAR text_2_half_byte : sector_half_bytes;
  302.      VAR low_order_half_byte : sector_half_bytes;
  303.      VAR high_order_half_byte : sector_half_bytes)};
  304.       VAR
  305.         byte_in_sector                       : INTEGER;
  306.         byte_value                           : INTEGER;
  307.         half_byte_index_1                    : INTEGER;
  308.         half_byte_index_2                    : INTEGER;
  309.       BEGIN
  310.         half_byte_index_1:=0;
  311.         half_byte_index_2:=1;
  312.         FOR byte_in_sector:=1 TO 128 DO
  313.           BEGIN
  314.             byte_value
  315.              :=substitution[16*text_1_half_byte[half_byte_index_1]
  316.              +text_1_half_byte[half_byte_index_2]];
  317.             text_2_half_byte[half_byte_index_1]
  318.              :=high_order_half_byte[byte_value];
  319.             text_2_half_byte[half_byte_index_2]
  320.              :=low_order_half_byte[byte_value];
  321.             half_byte_index_1:=half_byte_index_1+2;
  322.             half_byte_index_2:=half_byte_index_2+2
  323.           END
  324.       END;
  325.     PROCEDURE translate_half_bytes_to_sector{(
  326.      VAR text_1_half_byte : sector_half_bytes;
  327.      VAR sector : sector_bytes)};
  328.       VAR
  329.         byte_in_sector                           : INTEGER;
  330.         half_byte_index_1                        : INTEGER;
  331.         half_byte_index_2                        : INTEGER;
  332.       BEGIN
  333.         half_byte_index_1:=0;
  334.         half_byte_index_2:=1;
  335.         FOR byte_in_sector:=1 TO 128 DO
  336.         BEGIN
  337.           sector[byte_in_sector]:=16*text_1_half_byte[half_byte_index_1]
  338.            +text_1_half_byte[half_byte_index_2];
  339.           half_byte_index_1:=half_byte_index_1+2;
  340.           half_byte_index_2:=half_byte_index_2+2
  341.         END;
  342.       END;
  343.     PROCEDURE rewrite_sector{(
  344.      VAR disk_file : direct_access_file;
  345.      VAR sector_index : INTEGER;
  346.      VAR sector : sector_bytes)};
  347.       BEGIN
  348.         SEEK(disk_file,sector_index);
  349.         BLOCKWRITE(disk_file,sector,1)
  350.       END;
  351.     BEGIN
  352.       set_up_half_byte_translation{(
  353.        high_order_half_byte,low_order_half_byte)};
  354.       number_of_sectors:=FILESIZE(disk_file);
  355.       sector_index:=0;
  356.       WHILE (sector_index < number_of_sectors) DO
  357.         BEGIN
  358.           read_sector{(disk_file,sector_index,sector)};
  359.           translate_sector_to_half_bytes{(
  360.            sector,
  361.            text_1_half_byte,low_order_half_byte,high_order_half_byte)};
  362.           {
  363.                  For a faster though less secure cipher, use
  364.             "FOR iteration:=1 TO 2 DO" in place of the next line.
  365.           }
  366.           FOR iteration:=1 TO 16 DO
  367.             BEGIN
  368.               substitute_bytes{(
  369.                substitution,text_1_half_byte,text_2_half_byte,
  370.                low_order_half_byte,high_order_half_byte)};
  371.               permute_half_bytes{(
  372.                permutation,text_2_half_byte,text_1_half_byte)}
  373.             END; 
  374.           translate_half_bytes_to_sector{(
  375.            text_1_half_byte,sector)};
  376.           rewrite_sector{(disk_file,sector_index,sector)};
  377.           sector_index:=sector_index+1
  378.         END
  379.       END;  
  380.   BEGIN
  381.     print_title;
  382.     open_plaintext{(disk_file)};
  383.     generate_patterns{(permutation,substitution)};
  384.     decipher_each_sector{(disk_file,permutation,substitution)};
  385.     CLOSE(disk_file)
  386.   END.
  387.