Страница 17 из 37
Шифры замены Один из простейших шифров замены представляет собой смещен- ный на определенное число позиций алфавит. Например, если каждая буква была смещена на три позиции, то алфавит
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.
Использование шифров множественной замены существенно зат- рудняет дешифрацию кода с применением частотных таблиц, изза то- го, что разные буквы в разные моменты времени отображаются в одни и те же символы. Если вы поразмыслите над этой проблемой, то най- дете, наверное, методы использования различных перемешанных алфа- витов и более сложные процедуры переключения их, которые дадут одинаковую частоту использования букв в зашифрованном тексте. В этом случае частотные таблицы окажутся бесполезными при дешифра- ции кода.
|