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

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