Шифрование текста
   
Шифрование методом Льюиса Квадрат Полибия
Шифрование методом Атбаш Шифр Вижинера
Шифрование методом Цезаря Шифр Гронсфельда
   
Шифр Хилла (с длиной блока = 2) Шифрование с помощью решетки
   


Шифрование методом Льюиса

(я проверял на латинском алфавите, поэтому Alpha_Hor следует заполнить символами русского алфавита, и в Len написать их количество)

+ еще кое-что важное. Эта программа оставит символы, не присутствующие в строке Alpha_Hor без изменения. То же самое касается и заглавных букв (хотя заглавные буквы можно внести в эту самую строку).
const
  len = 26;

  {Это символы для выбора столбца таблицы}
  alpha_hor: string = 'abcdefghijklmnopqrstuvwxyz';

  {Здесь будут символы для выбора строки таблицы}
  alpha_ver: string = '';

var
  {Это собственно таблица кодирования}
  table: array[1 .. len, 1 .. len] of char;

{функция получает строку S и возвращает строку,
  полученную из исходной сдвигом на N позиций}
function shift(s: string; n: integer): string;
  begin
    s := copy(s, length(s) - pred(n), n) + s;
    delete(s, length(s) - pred(n), n); shift := s
  end;

var
  i, j, row, col: integer;
  s: string; ch: char;

  key: string;
  is_russian: boolean;
  f_in: file of char; f_out, f_key: text;
begin
  { Заполнение таблицы кодировки }
  for i := 1 to len do begin
    {получаем строку символов для текущей строки таблицы}
    s := shift(alpha_hor, pred(i));
    for j := 1 to len do
      table[i, j] := s[j];
    {
      не забываем первый символ заносить в "хранилище"
      для выбора строк по кодируемой букве
    }
    alpha_ver := alpha_ver + s[1]
  end;

  { связываем логические файлы программы с физическими файлами на диске }

  { файл с фразой для кодирования - открываем для чтения }
  assign(f_in, 'f_00in.txt');
  {$i-} reset(f_in); {$i+}

  { файл для сохранения результата - открываем для записи }
  assign(f_out, 'f_00out.txt');
  {$i-} rewrite(f_out); {$i+}

  {
    файл, содержащий ключевое слово - открываем для чтения,
    считываем слово в строковую переменную и закрываем файл
  }
  assign(f_key, 'f_00key.txt');
  {$i-} reset(f_key); {$i+}
  readln(f_key, key);
  close(f_key);

  { счетчик закодированных символов }
  i := 0;
  {до конца кодируемого файла делаем следующее:}
  while not eof(f_in) do begin
    { читаем очередной символ }
    read(f_in, ch);
    { находим по нему строку таблицы }
    row := pos(ch, alpha_ver);
    {
      эта переменная содержит значение успеха предыдущей операции
      (если True, то символ присутствует в таблице, иначе False)
    }
    is_russian := (row > 0);
    if is_russian then begin
      { Если символ присутствует в таблице, его надо кодировать }

      { увеличиваем счетчик закодированных символов }
      inc(i);

      {
        находим столбец по значению ключевого символа
        (операция mod используется, чтобы исключить выход
        за пределы ключа, т.к. длина ключа обычно меньше
        длины шифруемой последовательности)
      }
      col := pos(key[i mod (length(key))], alpha_hor);
      { и заменяем простой символ на зашифрованный (из таблицы) }
      ch := table[row, col];
    end;
    {
      если символ надо было шифровать, он уже зашифрован,
      если он не может быть зашифрован, он остался без изменений.
      Пишем его в выходной файл
    }
    write(f_out, ch)
  end;

  { И закрываем оба файла: исходный и зашифрованный }
  close(f_out);
  close(f_in)
end.


Шифрование методом Атбаш

Некоторые фрагменты библейских текстов зашифрованы с помощью шифра, который назывался Атбаш. Правило зашифрования

состояло в замене i-й буквы алфавита буквой с номером n - i + 1, где n - число букв в алфавите.

Происхождение слова Атбаш объясняется принципом замены букв. Это слово составлено из букв Алеф, Тав, Бет, Шин, то есть первой и последней, второй и предпоследней букв древнесемитского алфавита.

Функция, шифрующая строку методом Атбаш, имеет вид:
function Atbash(toCode: string): string;
var i: integer;
begin
  for i := 1 to length(toCode) do
    toCode[ i ] := Chr(256 - Ord(toCode[ i ]));
  Atbash := toCode;
end;

{ Использование: }
var
  s: string;

begin
  s := Atbash('Just a test'); { зашифровать }
  writeln(s);
  writeln('s = ', Atbash(s)); { расшифровать }
end.
Для дешифрования сообщения нужно просто повторно применить к нему этот же алгоритм.


Шифрование методом Цезаря

Шифр Цезаря реализует кодирование фразы путем «сдвига» всех букв фразы на определенное число n (в оригинальном шифре Цезаря число n равнялось 3). Если буква кодируемой фразы имеет в алфавите позицию j, то она в "шифровке" будет заменяться буквой, находящейся в алфавите на позиции j + n.

Для кодирования и декодирования текста данным методом используются функции:
const
  n = 3;

function CaesarEncipher(toCode: string): string;
var i, T: integer;
begin
  for i := 1 to length(toCode) do begin
    T := (Ord(toCode[ i ]) + n);
    if T >= 256 then dec(T, 256);
    toCode[ i ] := Chr(T);
  end;
  CaesarEncipher := toCode;
end;

function CaesarDecipher(toDecode: string): string;
var i, T: integer;
begin
  for i := 1 to length(toDecode) do begin
    T := (Ord(toDecode[ i ]) - n);
    if T < 0 then Inc(T, 256);
    toDecode[ i ] := Chr(T);
  end;
  CaesarDecipher := toDecode;
end;

{ применение: }
var
  s: string;

begin
  s := CaesarEncipher('just a Caesar');
  writeln(s);
  writeln('s = ', CaesarDecipher(s));
end.


Квадрат Полибия

В Древней Греции (II в. до н.э.) был известен шифр, называемый "квадрат Полибия". Шифровальная таблица представляла собой квадрат с пятью столбцами и пятью строками, которые нумеровались цифрами от 1 до 5. В каждую клетку такого квадрата записывалась одна буква. В результате каждой букве соответствовала пара чисел, и шифрование сводилось к замене буквы парой чисел.

Для латинского алфавита квадрат Полибия имеет вид:
Квадрат Полибия

Соответственно, шифрование/дешифрование текста производятся следующим образом:
const
  TPolibius: array['A' .. 'E', 'A' .. 'E'] of char = (
    ('A', 'B', 'C', 'D', 'E'),
    ('F', 'G', 'H', 'I', 'K'),
    ('L', 'M', 'N', 'O', 'P'),
    ('Q', 'R', 'S', 'T', 'U'),
    ('V', 'W', 'X', 'Y', 'Z')
  );
function PolibiusEncipher(toCode: string): string;
var
  i: integer;
  ix, jx: char;
  s: string;
begin
  s := '';
  for i := 1 to length(toCode) do begin

    for ix := 'A' to 'E' do
      for jx := 'A' to 'E' do
        if TPolibius[ix, jx] = toCode[ i ] then begin
          s := s + ix + jx; break;
        end;

  end;
  PolibiusEncipher := s
end;

function PolibiusDecipher(toDecode: string): string;
var
  i: integer;
  s: string;
begin
  s := '';
  i := 1;
  while i <= length(toDecode) do begin
    s := s + TPolibius[toDecode[ i ], toDecode[succ(i)]];
    inc(i, 2);
  end;
  PolibiusDecipher := s
end;

var
  s: string;

begin
  s := PolibiusEncipher('POLIBIUS');
  writeln(s);
  writeln('s = ', PolibiusDecipher(s));
end.


Шифр Вижинера

Важное усовершенствование многоалфавитных систем, состоящее в идее использования в качестве ключа текста самого сообщения или же шифрованного текста, принадлежит Джероламо Кардано и Блезу де Виженеру. Такой шифр был назван самоключом.

Ниже приведены функции для работы с текстом по методу Вижинера (текст может состоять ТОЛЬКО из символов, присутствующих в алфавите):
const
  TViginer: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

function ViginerEncipher(toCode, K: string): string;
var
  i: integer;
  currK: byte;
  s: string;
begin
  s := '';
  for i := 1 to length(toCode) do begin
    currK := pred(pos(K[ (pred(i) mod length(K)) + 1 ], TViginer));
    s := s +
      TViginer[ ((pred(pos(toCode[ i ], TViginer)) + currK) mod length(TViginer)) + 1 ];
  end;
  ViginerEncipher := s;
end;

function ViginerDecipher(toDecode, K: string): string;
var
  i, T: integer;
  currK: byte;
  s: string;
begin
  s := '';
  for i := 1 to length(toDecode) do begin
    currK := pred(pos(K[ (pred(i) mod length(K)) + 1 ], TViginer));
    T := pred(pos(toDecode[ i ], TViginer)) - currK;
    if T < 0 then inc(T, length(TViginer));
    s := s + TViginer[T + 1];
  end;
  ViginerDecipher := s;
end;

var
  s: string;

begin
  s := ViginerEncipher('INFORMATION', 'BORED');
  writeln(s);
  writeln('s = ', ViginerDecipher(s, 'BORED'));
end.


Шифр Гронсфельда

Алгоритм шифра Гронсфельда (созданный в 1734 году бельгийцем Хосе де Бронкхором, графом де Гронсфельд, военным и дипломатом), является модификацией шифра Цезаря, заключающейся в том, что величина сдвига не является постоянной, а задается ключом (гаммой).

Такой способ шифрования также называется короткопериодической гаммой.
function GronsfeldEncipher(toCode, K: string): string;
var i, T, _T: integer;
begin
  for i := 1 to length(toCode) do begin
    _T := ord(toCode[ i ]);

    T := (Ord(toCode[ i ])

      +
      (Ord(K[(pred(i) mod length(K)) + 1]) - Ord('0'))

         );

    if T >= 256 then dec(T, 256);
    toCode[ i ] := Chr(T);
  end;
  GronsfeldEncipher := toCode;
end;

function GronsfeldDecipher(toDecode, K: string): string;
var i, T: integer;
begin
  for i := 1 to length(toDecode) do begin
    T := (Ord(toDecode[i])

      -
      (Ord(K[(pred(i) mod length(K)) + 1]) - Ord('0'))

         );
    if T < 0 then Inc(T, 256);
    toDecode[ i ] := Chr(T);
  end;
  GronsfeldDecipher := toDecode;
end;

var
  s: string;

begin
  s := GronsfeldEncipher('INFORMATION', '2178');
  writeln(s);
  writeln('s = ', GronsfeldDecipher(s, '2178'));
end.


Шифрование с помощью решетки

Неоднократно на форуме поднимался вопрос о шифровании текста с помощью решетки...

Ниже приводится программа, шифрующая заданный текст по этому алгоритму (процедура EncodeText, создается матрица, хранящая закодированный текст), и дешифрующая его же (функция DecodeText):
const
  n = 8;
type
  sType = string[n];
  matrix = array[1 .. n] of sType;
const
  mask: matrix = (
    'x...x...',
    '.x...x..',
    '..x...x.',
    '...x...x',
    '..x...x.',
    '...x....',
    'x...x..x',
    '..x..x..'
  );

  st: string =
    'сколькоцелыхчетырёхзначныхчиселможнополучитьизцифрнольодиндватри';

var
  encoded: matrix;
  masked: matrix;

{ Процедура поворота матрицы }
procedure T(var res: matrix);
var
  i, j: integer;
  mx: matrix;
begin
  mx := res;
  for i := 1 to n do
    for j := 1 to n do
      res[j, n - i + 1] := mx[i, j];
end;

{ Зашифровка текста }
procedure EncodeText(const s: string;
          const mask: matrix; var mx: matrix);
var
  i, j, count: integer;
  masked: matrix;
begin
  { Заполнение матрицы mx строками по N пробелов }
  for i := 1 to n do
    for j := 1 to n do mx[i] := mx[i] + #32;

  masked := mask;
  count := 1;
  while count <= length(s) do begin

    for i := 1 to n do
      for j := 1 to n do
        if masked[i, j] = 'x' then begin
          mx[i][j] := s[count];
          inc(count)
        end;
    T(masked);

  end;
end;

{ Расшифровка текста }
function DecodeText(const mask, encoded: matrix): string;
var
  s: string;
  i, j, count: integer;
  masked: matrix;
begin

  masked := mask;
  count := 0; s := '';
  while length(s) < n*n do begin
    for i := 1 to n do
      for j := 1 to n do
        if masked[i, j] = 'x' then s := s + encoded[i, j];
    T(masked);
  end;
  DecodeText := s;

end;
var
  i: integer;
begin

  EncodeText(st, mask, encoded);

  writeln('encoded text: ');
  for i := 1 to n do begin
    writeln(encoded[i]);
  end;

  writeln(DecodeText(mask, encoded));

end.
Результат прогона программы:
encoded text:
срофкжрё
ноноолхп
зльноакь
олчонудц
чыеиинлх
чтдывьиа
хтисчезе
рлтцмыии
сколькоцелыхчетырёхзначныхчиселможнополучитьизцифрнольодиндватри


Шифр Хилла (с длиной блока = 2)

Криптосистема, основанная Хиллом, базируется на линейной алгебре.

Пространства исходных сообщений и криптотекстов совпадают: латинский алфавит. Перенумеруем буквы в порядке их следования в алфавите: A получает номер 0, B - номер 1, ... и Z - номер 25.

Все арифметические операции выполняются по модулю 26 (длина алфавита), то есть 26 отождествляется с 0, 27 - с единицей и т.д.

Выберем целое число D <= 2. Оно указывает размерность используемых матриц. В процедуре шифрования наборы из D букв шифруются вместе. Возьмем D = 2. Пусть ключ M - квадратная матрица порядка D, элементами которой являются числа 0 .. 25. Эта матрица должна удовлетворять требованию невырожденности, т.е. для нее должна существовать матрица M-1, например:
    | 3 3 |          |15 17 |
M = |     |, и M-1 = |      |
    | 2 5 |          |20  9 |
(вся арифметика ведется по модулю 26)

Шифрование осуществляется с помощью уравнения
MP = C
, где P и C - вектор столбцы длиной D. То есть, каждый набор из D букв исходного сообщения определяет вектор P, компонентами которого являются номера букв. В свою очередь, полученный вектор C также интерпретируется как набор из D букв.

Например:
исходное сообщение: HELP определяет 2 вектора (по 2 буквы в каждом):
     |H|   |7|          |L|   |11|
P1 = | | = | |  и  P2 = | | = |  |
     |E|   |4|          |P|   |15|
Из уравнений
       |7|                 | 0|
M*P1 = | | = C1  и  M*P2 = |  | = C2
       |8|                 |19|
получаем зашифрованный текст HIAT...

Для дешифровки сообщения используем матрицу M-1 [mod 26] и для шифротекста C вычисляем
P = M-1 * C [mod 26]
type
  very_long = longint;

  { Тип матрицы - ключа }
  tkey    = array[1 .. 2, 1 .. 2] of integer;
  { Матрица - столбец }
  tcolumn = array[1 .. 2] of integer;

  pmatrix = ^matrix;
  matrix  = array [1 .. maxint div sizeof(tcolumn)] of tcolumn;

function _inc(var x: integer): integer;
begin
  inc(x);
  _inc := x;
end;

{
  Реализация расширенного алгоритма Евклида
  (используется для нахождения числа, обратного данному по модулю
   при вычислении определителя матрицы)
}
procedure extended_euclid(a, b: very_long;
          var x, y, d: very_long);
var q, r, x1, x2, y1, y2: very_long;
begin

  if b = 0 then begin

    d := a; x := 1; y := 0;
    exit

  end;

  x2 := 1; x1 := 0; y2 := 0; y1 := 1;
  while b > 0 do begin

    q := a div b; r := a - q * b;
    x := x2 - q * x1; y := y2 - q * y1;
    a := b; b := r;
    x2 := x1; x1 := x; y2 := y1; y1 := y;

  end;

  d := a; x := x2; y := y2;

end;

(* Вычисление числа, обратного A по модулю N *)
function inverse(a, n: very_long): very_long;
var d, x, y: very_long;
begin

  extended_euclid(a, n, x, y, d);
  if d = 1 then inverse := x
  else inverse := 0;

end;

{ Алфавит криптосистемы }
const
  alpha: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

{ Преобразование массива столбцов длины Count в строку символов }
function make_str(const arr: array of tcolumn;
         const count: integer): string;
var
  res: string;
  i, j: integer;
begin
  res := '';

  for i := 0 to pred(count) do
    for j := 1 to 2 do res := res + alpha[succ(arr[i][j])];

  make_str := res;
end;
{ Преобразование строки символов S в массив столбцов (возвращается длина массива) }
function make_columns(var arr: array of tcolumn;
         const s: string): integer;
var
  i, count: integer;
  col: tcolumn;
begin
  count := -1;
  for i := 1 to length(s) do begin

    col[2 - (i mod 2)] := pred(pos(s[i], alpha));
    if not odd(i) then
      arr[_inc(count)] := col;

  end;
  make_columns := count + 1;
end;

{ Функция шифрования сообщения S ключом K }
function EncodeHill(const k: Tkey; const s: string): string;
var
  i, j, count: integer;
  mx, Y: pmatrix;
  len: integer;

begin
  len := sizeof(tcolumn) * ( (length(s) div 2) + byte(odd(length(s))) );
  getmem(mx, len);
  getmem( Y, len);

  count := make_columns(mx^, s);
  for i := 1 to count do
    for j := 1 to 2 do
      Y^[i][j] := (K[j, 1] * mx^[i][1] + K[j, 2] * mx^[i][2]) mod length(alpha);

  EncodeHill := make_str(Y^, count);

  freemem( Y, len);
  freemem(mx, len);
end;

{ Функция расшифровки шифротекста S известным ключом K }
function DecodeHill(const k: Tkey; const s: string): string;

  function positive(X: integer): integer;
  begin
    repeat
      inc(X, length(alpha));
    until X >= 0;
    positive := X;
  end;

var
  inv_k: Tkey;
  det, i, j, count: integer;
  mx, Y: pmatrix;
  len: integer;

begin
  det := k[1, 1] * k[2, 2] - k[1, 2] * k[2, 1];
  if det < 0 then det := positive(det);

  det := inverse(det, length(alpha));
  for i := 1 to 2 do
    for j := 1 to 2 do begin

      if i = j then
        inv_k[i, j] := det * k[3 - i, 3 - j]
      else
        inv_k[i, j] := - det * k[i, j];

      if inv_k[i, j] < 0 then
        inv_k[i, j] := positive(inv_k[i, j])
      else inv_k[i, j] := inv_k[i, j] mod 26;
    end;

  len := sizeof(tcolumn) * ( (length(s) div 2) + byte(odd(length(s))) );
  getmem(mx, len);
  getmem( Y, len);

  count := make_columns(Y^, s);

  for i := 1 to count do
    for j := 1 to 2 do
      mx^[i][j] := (inv_k[j, 1] * Y^[i][1] + inv_k[j, 2] * Y^[i][2]) mod length(alpha);

  DecodeHill := make_str(mx^, count);

  freemem( Y, len);
  freemem(mx, len);
end;

{ Тестируем работу функций кодирования/декодирования }
const
  k_2: Tkey = ((1, 7), (3, 6));

begin
  writeln('encoding:');
  writeln(EncodeHill(k_2, 'AFINEAFTERNOON'));
  writeln('decoding:');
  { Декодируем результат работы предыдущей функции с тем же ключом }
  writeln(DecodeHill(k_2, 'JEVYEMIZTKHTBQ'));
end.




Free Web Hosting