Описание работы программы Vizhener.
Теоретическая часть.
Шифр Виженера (Chiffre de Vigenère) — метод полиалфавитного шифрования буквенного текста с использованием ключевого слова.
Этот метод является простой формой многоалфавитной замены. Шифр Виженера изобретался многократно. Впервые этот метод описал Джован Баттиста Беллазо (итал. Giovan Battista Bellaso) в книге La cifra del. Sig. Giovan Battista Bellasо в 1553 году, однако в XIX веке получил имя Блеза Виженера, французского дипломата. Метод прост для понимания и реализации, он является недоступным для простых методов криптоанализа.
В шифре Цезаря каждая буква алфавита сдвигается на несколько строк; например в шифре Цезаря при сдвиге +3, A стало бы D, B стало бы E и так далее. Шифр Виженера состоит из последовательности нескольких шифров Цезаря с различными значениями сдвига. Для зашифровывания может использоваться таблица алфавитов, называемая tabula recta или квадрат (таблица) Виженера. Применительно к латинскому алфавиту таблица Виженера составляется из строк по 26 символов, причём каждая следующая строка сдвигается на несколько позиций. Таким образом, в таблице получается 26 различных шифров Цезаря. На разных этапах кодировки шифр Виженера использует различные алфавиты из этой таблицы. На каждом этапе шифрования используются различные алфавиты, выбираемые в зависимости от символа ключевого слова. Например, предположим, что исходный текст имеет вид:
Человек, посылающий сообщение, записывает ключевое слово («LEMON») циклически до тех пор, пока его длина не будет соответствовать длине исходного текста:
LEMONLEMONLEПервый символ исходного текста A зашифрован последовательностью L, которая является первым символом ключа. Первый символ L шифрованного текста находится на пересечении строки L и столбца A в таблице Виженера. Точно так же для второго символа исходного текста используется второй символ ключа; то есть второй символ шифрованного текста X получается на пересечении строки E и столбца T. Остальная часть исходного текста шифруется подобным способом.
Исходный текст: ATTACKATDAWNКлюч: LEMONLEMONLEЗашифрованный текст: LXFOPVEFRNHRРасшифровывание производится следующим образом: находим в таблице Виженера строку, соответствующую первому символу ключевого слова; в данной строке находим первый символ зашифрованного текста. Столбец, в котором находится данный символ, соответствует первому символу исходного текста. Следующие символы зашифрованного текста расшифровываются подобным образом.
Если буквы A-Z соответствуют числам 0-25, то шифрование Виженера можно записать в виде формулы:
Расшифровка:
Квадрат Виженера, или таблица Виженера, также известная как tabula recta, может быть использована для шифрования и расшифрования.
Описание работы программы Vizhener.
Программа выполняет функции шифрования и дешифрования текста по методу Виженера. В программе существует возможность извлекать и записывать текстовые данные из файлов с расширением .TXT, также в программе запрашивается пароль, без ввода которого не происходит расшифровки ранее зашифрованного программой файла (пароль также выполняет функции ключа в алгоритме шифрования). Существует возможность менять содержание алфавита прямо в интерфейсе программы, таблица Виженера возникает при нажатии на сочетание клавиш Ctrl+H.
Интерфейс программы:
Готовность к вводу данных или их загрузке:
Введенные данные для шифрования и пароль(активна кнопка «Зашифровать»):
Результат нажатия кнопки «Зашифровать»:
Введенные данные для дешифрования и пароль(активна кнопка «Расшифровать»):
Таблица Виженера с возможностью редактирования алфавита:
Листинг программы:
program Vizhener;
uses
Forms,
TablVin in 'TablVin.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.Title := 'ВИЖЕНЕР';
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
unit TablVin;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, ComCtrls, ExtCtrls, StdCtrls, Buttons, Menus;
type
TForm1 = class(TForm)
PC1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
SG1: TStringGrid;
Panel1: TPanel;
SB1: TSpeedButton;
SB2: TSpeedButton;
SG2: TStringGrid;
PopupMenu1: TPopupMenu;
N1: TMenuItem;
Edit1: TEdit;
Label1: TLabel;
REd1: TMemo;
REd2: TMemo;
SB3: TSpeedButton;
SB4: TSpeedButton;
SB5: TSpeedButton;
SB6: TSpeedButton;
SBar1: TStatusBar;
OD1: TOpenDialog;
SD1: TSaveDialog;
SB7: TSpeedButton;
MainMenu1: TMainMenu;
N2: TMenuItem;
N3: TMenuItem;
Timer1: TTimer;
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
procedure FormCreate(Sender: TObject);
procedure N1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Edit1KeyPress(Sender: TObject; var Key: Char);
procedure REd1KeyPress(Sender: TObject; var Key: Char);
procedure SG2KeyPress(Sender: TObject; var Key: Char);
procedure SB1Click(Sender: TObject);
procedure SB2Click(Sender: TObject);
procedure REd2KeyPress(Sender: TObject; var Key: Char);
procedure SB7Click(Sender: TObject);
procedure SB3Click(Sender: TObject);
procedure SB5Click(Sender: TObject);
procedure N3Click(Sender: TObject);
procedure SB4Click(Sender: TObject);
procedure SB6Click(Sender: TObject);
procedure LokBut(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
Const
DopChr = ['a'..'z', '0'..'9'];
var Rez :TStrings; Old1, Old2 :String;
Cont :Set of Char; // Допустимые символы
Form1: TForm1;
Function Det0(Tb :TStringGrid):Boolean;
Function Invert(S :String; N :LongInt):String;
Function KeyR(Tb :TStringGrid; Zn :Char; N :Integer=0):Integer;
Function KeyS(Tb :TStringGrid; Zn :Char; N :Integer=0):Integer;
Function Znak(Tb :TStringGrid; C, R :LongInt):Char;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
Var ColL :LongInt; Lst :TStrings;
begin
Cont := [];
ColL := 0; // Ноль строк
Lst:=TStringList.Create;
Try
Lst.Clear;
IF FileExists( ExtractFilePath(ParamStr(0))+'Grid.cfg' ) Then
Lst.LoadFromFile( ExtractFilePath(ParamStr(0))+'Grid.cfg' );
ColL := Lst.Count;
Finally
SG2.RowCount := ColL;
Lst.Free;
End;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SG1.Visible:=False;
PC1.ActivePage:=TabSheet2;
IF FileExists(ExtractFilePath(ParamStr(0))+'Grid.cfg') Then
SG2.Cols[0].LoadFromFile(ExtractFilePath(ParamStr(0))+'Grid.cfg');
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Sg1.ColCount := ColL;
Sg1.RowCount := Sg1.ColCount;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
N1.Click;
IF(REd1.Lines.Count>0)OR(REd2.Lines.Count>0)Then SB7.Enabled:=True ELSE
SB7.Enabled:=False;
end;
Function Det0(Tb :TStringGrid):Boolean;
VAR R :LongInt; //Заполненость таблицы
begin
Det0:=True;
For R:=0 To Tb.RowCount-1 Do
IF Tb.Cells[0, R]='' Then
begin
Det0:=True;
ShowMessage('ЗАПОЛНИТЕ ВСЁ!'); Break;
end ELSE Det0:=False;
end;
procedure TForm1.N1Click(Sender: TObject);
Var R,I :LongInt; Ms, Sd :String;
begin
IF Det0(SG2) Then Exit;
//=============================================== Фильтр символов
Cont := [];
For I:=0 To Sg2.RowCount - 1 Do
begin
Cont := Cont + [ Znak(Sg2, 0, I) ];
end;
//===============================================
PC1.Enabled:=False;
Ms:='';
For I:=0 To Sg2.RowCount-1 Do
MS:=MS+SG2.Cells[0, I];
For R:=0 To SG1.RowCount-1 Do
begin
SG1.Rows[R].Clear;
Sd:=Invert(MS, R);
For I:=1 to Length(Sd) Do
SG1.Rows[R].Add( Sd[I] );
end;
PC1.Enabled:=True;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
IF Det0( Sg2 ) = False Then
SG2.Cols[0].SaveToFile(ExtractFilePath(ParamStr(0))+'Grid.cfg');
end;
Function Invert(S :String; N :LongInt):String;
Var S1,S2, Sum :String;
begin
IF(S='')OR(N>Length(S))Then Exit;
///////////////////////////
Try
IF N>0 Then
begin
S1:=''; S2:='';
S1:=Copy(S, 1, N);
S2:=Copy(S, N+1, Length(S)-N);
Sum:=S2+S1;
Invert:=Sum;
end ELSE
IF N<=0 Then
Begin
Invert:=S;
End;
Except
ShowMessage('ВНУТРЕНЯЯ ОШИБКА!'); Exit;
End;
end;
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
CASE Key OF
'А'..'Я',#8,#9: ;
'а'..'я', 'a'..'z': Key:=Chr(Ord(Key)-32);
'ё','Ё': Key:='Ё';
// ELSE Key:=#0;
End;
IF Not (Key in Cont) Then Key:=#0;
end;
procedure TForm1.REd1KeyPress(Sender: TObject; var Key: Char);
begin
CASE Key OF
'А'..'Я',#8,#9,#13,#10,' ': ;
'а'..'я', 'a'..'z': Key:=Chr(Ord(Key)-32);
'ё','Ё': Key:='Ё';
'0'..'9': ;
End;
end;
procedure TForm1.REd2KeyPress(Sender: TObject; var Key: Char);
begin
CASE Key OF
'А'..'Я',#8,#9,#13,#10,' ': ;
'а'..'я', 'a'..'z': Key:=Chr(Ord(Key)-32);
'ё','Ё': Key:='Ё';
'0'..'9': ;
// ELSE Key:=#0;
End;
end;
procedure TForm1.SG2KeyPress(Sender: TObject; var Key: Char);
begin
CASE Key OF
'А'..'Я',#8,#9,#13,#10,' ': ;
'а'..'я', 'a'..'z': Key:=Chr(Ord(Key)-32);
'ё','Ё': Key:='Ё';
'0'..'9': ;
// ELSE Key:=#0;
End;
end;
Function KeyR(Tb :TStringGrid; Zn :Char; N :Integer=0):Integer;
Var R :LongInt; // ОБЩЕЕ: сканер столбцов
begin // Определение номера строки ключа " 1-ый столбец "
Result:=0;
For R:=0 To Tb.RowCount-1 Do
begin
Application.ProcessMessages();
IF Tb.Cells[N, R]=Zn Then Begin Result:=R; Break; End;
end;
end;
Function KeyS(Tb :TStringGrid; Zn :Char; N :Integer=0):Integer;
Var C :LongInt; // ОБЩЕЕ: сканер строк
begin // Определение номера столбца
Result:=0;
For C:=0 To Tb.ColCount-1 Do
begin
Application.ProcessMessages();
IF Tb.Cells[C, N]=Zn Then Begin Result:=C; Break; End;
end;
end;
Function Znak(Tb :TStringGrid; C, R :LongInt):Char;
begin //
Result:=Tb.Cells[C, R][1];
end;
procedure TForm1.SB1Click(Sender: TObject);
Var I,J,K :LongInt; Key,Txt, Oyt :String; Ch :Char; A,B :Longint;
begin // ШИФРУЕТ
IF Edit1.Text='' Then Exit;
Timer1.Enabled:=False;
SB1.Enabled:=False;
SB2.Enabled:=False;
Edit1.Enabled:=False;
REd2.Enabled:=False;
REd1.Enabled:=False;
Key:=Edit1.Text;
J:=1;
REd2.Lines.Clear; //Чистка
FOR K:=0 To REd1.Lines.Count-1 Do
Begin Oyt:='';
Txt:=REd1.Lines.Strings[ K ]; //Грузим строку
For I:=1 To Length(Txt{REd1.Lines.Text})Do
begin
Application.ProcessMessages(); //
///////////////////////////////
IF {REd1.Lines.Text[I]}Txt[I] in Cont{['А'..'Я','Ё']} Then
Begin
Ch:=Key[J];
A:=KeyR(SG1, Ch, 0) ; // Ищем номер символа ключа в столбце
Ch:=Txt[I]; //REd1.text[I];
B:=KeyS(SG1, Ch, 0) ; // Ищем номер символа текста в строке
//REd2.Text:=REd2.Text+Znak(SG1, B, A);
Oyt:=Oyt+Znak(SG1, B, A);
IF J<=Length(Key)-1 Then J:=J+1 ELSE J:=1; //Перебор Ключа
End ELSE
Begin //
Ch:=Txt[ I ];
//REd2.Text:=REd2.Text+Ch;
Oyt:=Oyt+Ch;
End;
///////////////////////////////
end;
REd2.Lines.Add(Oyt);
End;
SB1.Enabled:=True;
SB2.Enabled:=True;
Edit1.Enabled:=True;
Timer1.Enabled:=True;
REd2.Enabled:=True;
REd1.Enabled:=True;
end;
procedure TForm1.SB2Click(Sender: TObject);
Var I,J,K :LongInt; Key,Txt, Oyt :String; Ch :Char; A,B :Longint;
begin // РАСШИФРОВЫВАЕМ
IF Edit1.Text='' Then Exit;
Timer1.Enabled:=False;
SB1.Enabled:=False;
Edit1.Enabled:=False;
REd2.Enabled:=False;
REd1.Enabled:=False;
REd1.Clear; //Чистим
Key:=Edit1.Text;
J:=1;
For K:=0 To REd2.Lines.Count-1 Do
Begin Oyt:='';
Txt:=REd2.Lines.Strings[K];
Application.ProcessMessages(); //
For I:=1 To Length( Txt ) DO
Begin
Application.ProcessMessages();
//////////////////////////////
IF Txt[I] IN Cont{['А'..'Я','Ё']} Then
Begin
Ch:=Key[J];
A:=KeyR(SG1, Ch, 0) ; // Ищем номер символа ключа в столбце
Ch:=Txt[I]; //REd2.text[I];
B:=KeyS(SG1, Ch, A) ; // Ищем номер символа текста в строке " Main "
//REd1.Text:=REd1.Text+Znak(SG1, B, 0);
Oyt:=Oyt+Znak(SG1, B, 0);
IF J<=Length(Key)-1 Then J:=J+1 ELSE J:=1; //Перебор Ключа
End ELSE
Begin
Ch:=Txt[ I ];
//REd1.Text:=REd1.Text+Ch;
Oyt:=Oyt+Ch;
End;
//////////////////////////////
End;
REd1.Lines.Add(Oyt);
End;
SB1.Enabled:=True;
SB2.Enabled:=True;
Edit1.Enabled:=True;
Timer1.Enabled:=True;
REd2.Enabled:=True;
REd1.Enabled:=True;
end;
procedure TForm1.SB7Click(Sender: TObject);
begin // Удалить всё
IF REd1.Lines.Count>0 Then REd1.Clear;
IF REd2.Lines.Count>0 Then REd2.Clear;
SB7.Enabled:=False; SB1.Enabled:=False;
SB2.Enabled:=False; SB4.Enabled:=False;
SB6.Enabled:=False;
SBar1.Panels[0].Text:='';
SBar1.Panels[1].Text:='';
end;
procedure TForm1.SB3Click(Sender: TObject);
begin
OD1.Title:='Открыть исходный текст ...';
IF OD1.Execute Then
Begin
SBar1.Panels[0].Text:=ExtractFileName( OD1.FileName );
Old1:=OD1.FileName;
Application.ProcessMessages(); //
Try
SD1.FileName:=Old1;
REd1.Lines.LoadFromFile( Old1 );
Except
BEEP; ShowMessage('Нет доступа к: '+Old1);
SBar1.Panels[0].Text:=''; SD1.FileName:='';
End;
OD1.FileName:='';
End;
end;
procedure TForm1.SB5Click(Sender: TObject);
begin
OD1.Title:='Открыть шифрованный текст ...';
IF OD1.Execute Then
Begin
SBar1.Panels[1].Text:=ExtractFileName( OD1.FileName );
Old2:=OD1.FileName;
Application.ProcessMessages(); //
Try
REd2.Lines.LoadFromFile( Old2 );
Except
BEEP; ShowMessage('Нет доступа к: '+Old2);
SBar1.Panels[1].Text:='';
End;
OD1.FileName:='';
End;
end;
procedure TForm1.N3Click(Sender: TObject);
begin
SG1.Visible:=Not SG1.Visible;
end;
procedure TForm1.SB4Click(Sender: TObject);
Label 0;
begin
SD1.Title:='Сохранить Исходный текст как ...';
IF SBar1.Panels[0].Text='' Then
Begin
0 : IF SD1.Execute Then
begin
Old1:=SD1.FileName;
Application.ProcessMessages();
REd1.Lines.SaveToFile( Old1 );
SBar1.Panels[0].Text:=ExtractFileName( Old1 );
end;
End ELSE
IF MessageBox(Handle, PChar( 'Если хотите использовать имеющийся путь'+
#13+'"'+Old1+'"'+
#13' Нажмите " Да ".' ), 'Сохранение',
MB_YESNO+MB_ICONINFORMATION)=MrYes Then
REd1.Lines.SaveToFile(Old1) ELSE GoTo 0;
//SBar1.Panels[0].Text
SD1.FileName:='';
end;
procedure TForm1.SB6Click(Sender: TObject);
Label 1;
begin
SD1.Title:='Сохранить Зашифрованный текст как ...';
IF SBar1.Panels[1].Text='' Then
Begin
1: IF SD1.Execute Then
begin
Old2:=SD1.FileName;
Application.ProcessMessages();
REd2.Lines.SaveToFile( Old2 );
SBar1.Panels[1].Text:=ExtractFileName( Old2 );
end;
End ELSE
IF MessageBox(Handle, PChar( 'Если хотите использовать имеющийся путь'+
#13+'"'+Old2+'"'+
#13' Нажмите " Да ".' ), 'Сохранение',
MB_YESNO+MB_ICONINFORMATION)=MrYes Then
REd2.Lines.SaveToFile( Old2 ) ELSE GoTo 1;
//SBar1.Panels[0].Text
SD1.FileName:='';
end;
procedure TForm1.LokBut(Sender: TObject);
begin // Проверка текстовых полей
IF REd1.Lines.Count>0 Then
begin
SB1.Enabled:=True;
SB4.Enabled:=True;
end ELSE
IF REd1.Lines.Count<=0 Then
begin
SB1.Enabled:=False;
SB4.Enabled:=False;
end;
IF REd2.Lines.Count>0 Then
begin
SB2.Enabled:=True;
SB6.Enabled:=True;
end ELSE
IF REd2.Lines.Count<=0 Then
begin
SB2.Enabled:=False;
SB6.Enabled:=False;
end;
IF(REd1.Lines.Count>0)OR(REd2.Lines.Count>0)Then SB7.Enabled:=True ELSE
SB7.Enabled:=False;
TabSheet1.Caption:=Format('Таблица - [R=%d, C=%d]',
[SG1.RowCount, SG1.ColCount])
end;
// МЕТОДЫ ДЛЯ " STRINGGRID "
procedure DelCol(SG: TStringGrid);
Var I, J :LongInt;
begin // Удалить колонку
with SG do
begin
J := ColCount - 1;
Cols[ J ].Clear;
for I:=J to ColCount - 2 do
Cols[ I ].Assign( Cols[ I+1 ] );
ColCount := ColCount - 1;
end;
end;
procedure DelRow(SG: TStringGrid);
Var I, J :LongInt;
begin // Удалить строку
with SG do
begin
J := RowCount - 1; // Последняя строка
Rows[ J ].Clear;
for I:=J to RowCount - 2 do
Rows[I].Assign( Rows[ I+1 ] );
RowCount := RowCount - 1;
end;
end;
procedure InsRow(SG: TStringGrid);
begin // Вставка строки
With SG do
RowCount := RowCount + 1;
end;
procedure InsCol(StrGrid: TStringGrid);
begin // Вставка колонок
StrGrid.ColCount := StrGrid.ColCount + 1;
end;
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin // Добавить Строку для символов
IF SG2.RowCount<256 Then
begin
InsRow( Sg2 );
InsRow( Sg1 );
InsCol( SG1 );
end ELSE Beep;
end;
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin // Удалить Строку для символов
IF Sg2.RowCount>33 Then
Begin
DelRow( Sg2 );
DelRow( Sg1 );
DelCol( SG1 );
End ELSE Beep;
end;
end.