соответствие буквам перестановки буквы открытого текста. Для этого массив сопоставления символов изначально заполняется таким образом, чтобы каждый символ соответствовал самому себе. Это происходит в следующих строках метода:
for Ch := Low(RusDstAlphabet) to High(RusDstAlphabet) do RusDstAlphabet[Ch] := Ch;
После чего требуется подкорректировать данный массив таким образом, чтобы выполнялось требуемое соответствие. Для этого мы проходим по всем элементам редактора значений vleSubstn поправляем массив, указывая в качестве индекса элемента то, чему ставится соответствие, а в качестве значения элемента массива – то, что является соответствием.
for i := 1 to vleSubst.RowCount – 1 do
RusDstAlphabet[vleSubst.Cells[nKey, i][1]] :=
vleSubst.Cells[1 – nKey, i][1];
Редактор значений vleSubst предназначен для сопоставления букв верхнего регистра. Нам же требуется избавиться от различия между буквами верхнего и нижнего регистров. Для этого мы дополнительно производим следующие действия:
for i := 1 to vleSubst.RowCount – 1 do
RusDstAlphabet[LowCaseRus(vleSubst.Cells[nKey, i][1])] :=
LowCaseRus(vleSubst.Cells[1 – nKey, i][1]);
Мы рассмотрели работу данного метода по частям. Его полный код приведен в листинге 12.6. Как видите, все относительно просто. Здесь мы используем вспомогательную функцию LowCaseRus.
Листинг 12.6.
Функция предварительной подготовки алфавита преобразования
procedure TfmSubstitution.RecalcAlphabet(nKey: Integer);
var
Ch: Char;
i: Integer;
begin
//предварительно все символы в алфавите шифрования
//соответствуют символам из незашифрованного алфавита
for Ch := Low (RusDstAlphabet) to High(RusDstAlphabet) do
RusDstAlphabet[Ch] := Ch;
//формируем алфавит отдельно для каждого из регистров букв
//здесь для верхнего
for i := 1 to vleSubst.RowCount – 1 do
RusDstAlphabet[vleSubst.Cells[nKey, i][1]] :=
vleSubst.Cells[1 – nKey, i][1];
//здесь для нижнего
for i := 1 to vleSubst.RowCount – 1 do
RusDstAlphabet[LowCaseRus(vleSubst.Cells[nKey, i][1])] :=
LowCaseRus(vleSubst.Cells[1 – nKey, i][1]);
end;
Еще одной вспомогательной функцией является функция преобразования строки символов с помощью алфавита преобразования в соответствии с указанной операцией. Работа ее довольно проста. В цикле осуществляется прямой проход по строке, и каждый символ, принадлежащий ей, заменяется соответствующим символом алфавита преобразования. В итоге мы получаем зашифрованную либо дешифрованную строку. Посмотреть исходный код данного метода можно в листинге 12.7.
Листинг 12.7.
Преобразование строки при помощи массива сопоставления
function TfmSubstitution.EncryptDecryptString(strMsg: String):
String;
var
i: Integer;
begin
//преобразуем строку посимвольно
for i := 1 to Length(strMsg) do
strMsg[i] := RusDstAlphabet[strMsg[i]];
Result := strMsg;
end;
Теперь, используя все описанные функции, мы без труда можем зашифровать либо дешифровать сообщение. Например, чтобы зашифровать его, мы подготавливаем массив соответствия букв вызовом функции RecalcAlphabet с параметром 0. После чего для каждой строки открытого текста вызываем функцию EncryptDecryptString и в качестве результата получаем зашифрованную строку. Обработчики событий OnClick соответствующих кнопок шифруют либо дешифруют весь текст. Основная идея каждого из методов заключается в том, чтобы проверить корректность заданной перестановки, после чего производится предварительная подготовка алфавита сопоставления, и далее сообщение преобразуется (листинг 12.8).
Листинг 12.8.
Шифрование/дешифрование сообщения
procedure TfmSubstitution.btnEncryptMessageClick(Sender:
TObject);
var
i: Integer;
begin
//проверяем корректность ввода перестановки
if ValidateRearrangement then
begin
//создаем алфавит преобразования открытого текста
RecalcAlphabet(0);
//предотвращаем перерисовку компонента до тех пор,
//пока не зашифруем все строки сообщения
mmEncryptMessage.Lines.BeginUpdate;
//очищаем текстовый редактор
mmEncryptMessage.Clear;
//шифруем открытый текст построчно
for i := 0 to mmDecryptMessage.Lines.Count – 1 do
mmEncryptMessage.Lines.Add(EncryptDecryptString
(mmDecryptMessage.Lines[i]));
//разрешаем перерисовку компонента
mmEncryptMessage.Lines.EndUpdate;
end
else
MessageDlg ('Ошибка: символы подстановки заданы неверно',
mtError, [mbOk], 0);
end;
procedure TfmSubstitution.btnDecpyptMessageClick (Sender:
TObject);
var
i: Integer;
begin
//проверяем корректность ввода перестановки
if ValidateRearrangement then
begin
//создаем алфавит преобразования шифрованного текста
RecalcAlphabet (1);
mmDecryptMessage.Lines.BeginUpdate;
mmDecryptMessage.Clear;
//дешифруем шифрованный текст построчно
for i := 0 to mmEncryptMessage.Lines.Count – 1 do
mmDecryptMessage.Lines.Add(EncryptDecryptString
(mmEncryptMessage.Lines [i]));
mmDecryptMessage.Lines.EndUpdate;
end
else
MessageDlg('Ошибка: символы подстановки заданы неверно',
mtError, [mbOk], 0);
end;
В итоге мы получили вполне рабочий вариант приложения, способного без особого труда шифровать и дешифровать сообщения. На рис. 12.2 представлен результат работы данного приложения.
Рис. 12.2. Результат работы приложения «Шифр простой подстановки»
12.3. Транспозиция
Следующий шифр, который мы будем рассматривать, называется транспозицией с фиксированным периодом
Таким образом, для
Теперь, зная определение данного шифра, можно перейти к примеру одной из возможных его реализаций. Для этого, как и в предыдущем случае, создадим новое приложение, а на форму поместим те же самые компоненты, за исключением редактора значений и кнопки для генерации перестановки. Вместо них используем следующие компоненты: текстовое поле класса TEdit и еще один компонент класса TLabel с соответствующими HMeHaMHedRearrangement и IbRearrangement. Когда вы закончите, то в результате должно получиться нечто подобное изображенному на рис. 12.3.
Рис. 12.3. Интерфейс программы «Транспозиция с фиксированным периодом»
Текстовое поле edRearrangement предназначено для задания перестановки, которая будет использоваться при шифровании. Перестановка будет задаваться числами, разделенными пробелом, а их количество задаст период транспозиции. По остальному интерфейсу наше приложение аналогично предыдущему.
Стоит отметить одну неприятную особенность данного шифра. Поскольку период фиксирован, то на текст накладывается определенное ограничение. Оно заключается в том, что длина текста должна быть кратна периоду. Существует несколько вариантов решения данной проблемы. Можно дополнять открытый текст какими-либо символами. И тогда зашифровать сообщение не составит труда. Если эти символы заранее определены, то это облегчит задачу противника по вскрытию