Энциклопедия Turbo Pascal. Главы 5-8
Страница 17. Шифры замены


Шифры замены

     Один из  простейших шифров замены представляет собой смещен-
ный на определенное число позиций алфавит.  Например, если каждая
буква была смещена на три позиции, то алфавит

     abcdefghijklmnopqrstuvwxyz

превращается в

     defghijklmnopqrstuvwxyzabc

     Отметим, что буквы abc выдвинулись и добавились в конец. Для
того,  чтобы закодировать сообщение,  используя данный метод,  вы
просто  подставляете  символы сдвинутого алфавита вместо реальных
символов. Например, сообщение

     meet me at sunset

превращается в

     phhw ph dw vxqvhw

     Программа, показанная  далее,  позволяет  зашифровать  любое
текстовое сообщение, используя любое по вашему выбору смещение:

     { шифр простой замены }
     program subst;
     type
       str80 = string[80];

     var
       inf, outf: str80;
       start: integer;
       ch: char;

     procedure code (inf, outf: str80; start: integer);
     var
       infile, outfile: file of char;
       ch: char;
       t: integer;

     begin
       assign(infile, inf);
       reset(infile);
       assign(outfile, outf);
       rewrite(outfile);
       while not eof(infile) do
       begin
         Read(infile, ch);
         ch : = upcase(ch);
         if (ch>='A') and (ch<='Z') then
         begin
           t  := ord(ch)+start;
           if t>ord('Z') then t  := t-26;
           ch  := chr(t);
         end;
         Write(outfile, ch);
       end;
       WriteLn('файл закодирован');
       close(infile); close(outfile);
     end;

     procedure decode(inf, outf: str80; start: integer);
     var
        infile, outfile: file of char;
        ch: char;
        t: integer;

     begin
       assign(infile, inf);
       reset(infile);
       assign(outfile, outf);
       rewrite(outfile);

       while not eof(infile) do
       begin
         read(infile, ch);
         ch  := upcase(ch);
         if (ch>='A') and (ch<='Z') then
         begin
           t  := ord(ch)-start;
           if t<ord('A') then t  := t+26;
           ch  := chr(t);
         end;
         Write(outfile, ch);
       end;
       WriteLn('файл декодирован');
       close(infile); close(outfile);
     end;

     begin
       Write('введите имя входного файла : ');
       ReadLn(inf);
       Write('введите имя выходного файла : ');
       ReadLn(outf);
       Write('начальная позиция (1-26): ');
       ReadLn(start);
       Write('кодировать или декодировать (C or D): ');
       ReadLn(ch);
       if upcase(ch)='C' then code(inf, outf, start)
       else if upcase(ch)='D' then decode(inf,outf,start);
     end.

     Хотя шифр замены,  основанный на постоянном смещении, одура-
чит ученика младших классов,  он не подходит для большинства при-
менений из-за того,  что его слишком легко расколоть.  Существует
только  26  возможных смещений и легко за довольно короткое время
перебрать их все. Можно улучшить шифр замены, использовав переме-
шанный алфавит вместо просто смещенного.

     Вторая слабость  шифра простой замены состоит в том,  что он
сохраняет пробелы между словами, что еще упрощает его дешифрацию.
Поэтому  следующим  улучшением  могло бы быть кодирование пробела
(кроме того,  следует кодировать и другие знаки препинания). Нап-
ример, вы могли бы отобразить алфавит

     abcdefghijklmnopqrstuvwxyz<пробел>

в произвольную строку,  которая содержит все буквы алфавита, нап-
ример

     qazwsxedcrfvtgbyhnujm ikolp

     Вы можете пожелать узнать,  значительно ли улучшается  стой-
кость шифрования при использовании перемешанного варианта алфави-
та по сравнению с вариантом простого смещения.  Ответ: да. Дело в
том, что существует 26! вариантов перестановок алфавита, а с про-
белом число вариантов достигает 27!. Факториал числа представляет
собой произведение всех чисел,  не превосходящих данного.  Напри-
мер,  6!  равно 6х5х4х3х2х1, то есть 720. Следовательно 26! очень
большое число.

     Программа, представленная  далее,  реализует улучшенный шифр
замены,  использующий перемешанный алфавит, показанный выше. Если
вы закодируете сообщение

     meet me at sunset

используя программу  реализации  улучшенного шифра замены,  полу-
чится строка

     tssjptspqjpumgusj

которую значительно труднее дешифровать.

     { улучшенный  шифр замены,  который использует перемешанный
      алфавит
     }
     program subs1;
     type
       str80 = string[80];

     var
       inf, outf: str80;
       alphabet,sub: str80;
       ch: char;

     { данная функция возвращает индекс в алфавите замены }
     function find(alphabet: str80; ch: char): integer;
     var
       t: integer;

     begin
       find  := -1; { код ошибки }
       for t := 1 to 27 do if ch=alphabet[t] then find  := t;
     end;   {find}

     {данная функция возвращает TRUE истина,
      если с - это буква алфавита }
     function isalpha(ch: char): boolean;
     begin
          isalpha:=(upcase(ch)>='A') and (upcase(ch)<='Z');
     end;   {isalpha}

     procedure code(inf, outf: str80);
     var
       infile, outfile: file of char;
       ch: char;

     begin
       assign(infile, inf);
       reset(infile);
       assign(outfile, outf);
       rewrite(outfile);

       while not eof(infile) do
       begin
         Read(infile, ch);
         ch:=upcase(ch);
         if isalpha(ch) or (ch=' ') then
         begin
           ch:=sub[find(alphabet, ch)]; { найти замену }
         end;
         Write(outfile, ch);
       end;
       WriteLn('файл закодирован');
       close(infile); close(outfile);
     end;   {code}

     procedure decode(inf, outf: str80);
     var
       infile, outfile: file of char;
       ch: char;

     begin
       assign(infile, inf);
       reset(infile);
       assign(outfile, outf);
       rewrite(outfile);

       while not eof(infile) do
       begin
         Read(infile, ch);
         ch:=upcase(ch);
         if isalpha(ch) or (ch=' ') then
         ch:=alphabet[find(sub,ch)]; {замена снова на реальный
                                           алфавит }
         Write(outfile, ch);
       end;
       WriteLn('файл декодирован');
       close(infile); close(outfile);
     end;   {decode}


     begin
       alphabet  := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
       sub       := 'CAZWSXEDCRFVTGBYHNUJM IKOLP';
       Write('введите имя входного файла : ');
       ReadLn(inf);
       Write('введите имя выходного файла : ');
       ReadLn(outf);
       Write('кодировать или декодировать  (C or D): ');
       ReadLn(ch);
       if upcase(ch)='C' then code(inf, outf)
       else if upcase(ch)='D' then decode(inf, outf);
     end.

     Хотя дешифрация рассматривается далее в этой главе, вам сле-
дует знать, что даже такой улучшенный код замены может быть срав-
нительно легко дешифрован, используя частотные таблицы английско-
го языка, в которых дана статистическая информация по использова-
нию каждой буквы алфавита. Как вы можете легко заметить, глядя на
зашифрованное сообщение, "s" почти наверняка является буквой "е",
наиболее часто встречающейся буквой английского алфавита, а "р" -
пробелом. Оставшаяся часть сообщения может быть дешифрована быст-
ро и легко.

     Чем больше шифрованное сообщение, тем легче расшифровать его
с помощью частотных таблиц.  Для того,  чтобы осложнить успех де-
шифровальщика,  применяющего частотные таблицы, вы можете исполь-
зовать шифр множественной замены.  Одна и та же буква в  исходном
сообщении  не обязательно преобразуется в одну букву шифрованного
текста.  Один из возможных методов реализации шифра множественной
замены  состоит в добавлении второго перемешанного алфавита и пе-
реключении с одного алфавита на другой при встрече в тексте  про-
бела. Пусть вторым перемешанным алфавитом будет следующий:

     poi uytrewqasdfghjklmnbvcxz

     Тогда, используя данный подход, сообщение

     meet me at sunset

будет зашифровано в вид

     tssj su qj kmdkul

     Чтобы понаблюдать, как это выполняется, запишите упорядочен-
ный алфавит и два перемешанных алфавита один под другим,  как по-
казано ниже

     алфавит: abcdefghijklmnopqrstuvwxyz<пробел>
     замена:  qazwsxedcrfvtgbyhnujm ikolp
     замена2: poi uytrewqasdfghjklmnbvcxz

     В начале  работы программы используется первый алфавит.  Это
означает,  что "meet" кодируется в "tssj". Когда встречается пер-
вый пробел происходит переключение на второй алфавит,  приводящее
к кодированию слова "me"  в  "su".  Следующий  пробел  заставляет
программу использовать снова первый алфавит. Этот процесс продол-
жается до тех пор, пока не будет закодировано все сообщение.

     Данная программа создает шифр множественной замены:
     { шифр множественной замены }
     program subs3;

     type
       str80=string[80];

     var
       inf, outf: str80;
       alphabet, sub, sub2: str80;
       ch: char;

     {данная функция  возвращает
      индекс в  алфавите подстановки }
     function find(alphabet: str80; ch: char): integer;
     var
       t: integer;

     begin
       find:= -1;  { код ошибки }
       for t:= 1 to 27 do if ch=alphabet[t] then find:= t;
     end;  {find}

     {This function returns TRUE if ch is a letter
      of the alphabet.}
     function isalpha(ch: char): boolean;
     begin
       isalpha:= (upcase(ch)>='A') and (upcase(ch)<='Z');
     end;  {is alpha}

     procedure code(inf, outf: str80);
     var
       infile, outfile: file of char;
       ch: char;
       change: boolean;

     begin
       assign(infile, inf);
       reset(infile);
       assign(outfile, outf);
       rewrite(outfile);

     change  := TRUE;
     while not eof(infile) do
     begin
       Read(infile,ch);
       ch := upcase(ch);

       { переключение алфавитов при каждом пробеле }

       if ch=' ' then change  := not change;
       if isalpha(ch) then
       begin
         if change then
          ch:=sub[find(alphabet,ch)]
         else
          ch:=sub2[find(alphabet,ch)];
       end;
       Write(outfile, ch);
     end;
       WriteLn('файл закодирован ');
       close(infile); close(outfile);
     end;  {code}

     procedure decode(inf, outf: str80);
     var
       infile, outfile: file of char;
       ch: char;
       change: boolean;

     begin
       assign(infile, inf);
       reset(infile);
       assign(outfile, outf);
       rewrite(outfile);

       change  := TRUE;
       while not eof(infile) do
       begin
         Read(infile, ch);
         ch  := upcase(ch);
         if ch=' ' then change  := not change;
         if isalpha(ch) then
         begin
           if change then
             ch:=alphabet[find(sub, ch)] {find substitution}
           else
             ch:=alphabet[find(sub2, ch)]; {second sub}
         end;
         Write(outfile, ch);
       end;
       WriteLn('файл декодирован ');
       close(infile); close(outfile);
     end;

     begin
       alphabet:='ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
       sub     :='QAZWSXEDCRFVTGBYHNUJM IKOLP'; {алфавит #1}
       sub2    :='POI UYTREWQASDFGHJKLMNBVCXZ'; {алфавит #2}

       Write('введите имя входного файла : ');
       ReadLn(inf);
       Write('введите имя выходного файла : ');
       ReadLn(outf);
       Write('кодировать или декодировать (C or D): ');
       ReadLn(ch);
       if upcase(ch)='C' then code(inf, outf)
       else if upcase(ch)='D' then decode(inf, outf);
     end.


     Использование шифров множественной замены  существенно  зат-
рудняет дешифрацию кода с применением частотных таблиц,  изза то-
го, что разные буквы в разные моменты времени отображаются в одни
и те же символы. Если вы поразмыслите над этой проблемой, то най-
дете, наверное, методы использования различных перемешанных алфа-
витов  и  более сложные процедуры переключения их,  которые дадут
одинаковую частоту использования букв в зашифрованном  тексте.  В
этом  случае частотные таблицы окажутся бесполезными при дешифра-
ции кода.

 
« Предыдущая статья   Следующая статья »