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

Квадрат Полибия – метод шифрования текстовых данных с помощью замены символов, впервые предложен греческим историком и полководцем Полибием.

Описание алгоритма

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

Для английского алфавита квадрат может иметь вид:

1 2 3 4 5
1 A B C D E
2 F G H I/J K
3 L M N O P
4 Q R S T U
5 V W X Y Z

Для русского:

1 2 3 4 5 6
1 А Б В Г Д Е
2 Ё Ж З И Й К
3 Л М Н О П Р
4 С Т У Ф Х Ц
5 Ч Ш Щ Ъ Ы Ь
6 Э Ю Я 1 2 3

Использование ключа

Квадрат может заполнятся символами произвольно, а не строго в алфавитном порядке. Однако такое заполнение трудно запомнить, поэтому лучше использовать ключ, в котором нет повторяющихся символов(повторения также можно игнорировать), а все остальные – вписать в таблицу в порядке возрастания. К примеру мы используем слово-пароль PASSWORD, удалим из него повторения и впишем в таблицу, затем запишем оставшиеся значения, и получим:

1 2 3 4 5
1 P A S W O
2 R D B C E
3 F G H I/J K
4 L M N Q T
5 U V X Y Z

Методы шифрования

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

Метод 1. Использование соседнего снизу символа

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

Таблица координат
Исходный текст: P O L Y B I U S
Шифротекст: U T Q D G O Z X

Метод 2. Преобразование координат

Для начала необходимо выписать координаты символов исходного текста:

Координаты
Буква: P O L Y B I U S
Вертикальная координата: 5 4 1 4 2 4 5 3
Горизонтальная координата: 3 3 3 5 1 2 4 4

После этого координаты считываются подряд и преобразуются в текст:

54 ⇨ U, 14 ⇨ Q, 24 ⇨ R, 53 ⇨ P, 33 ⇨ N, 35 ⇨ X, 12 ⇨ F, 44 ⇨ T

UQRPNXFT

Реализация шифра Полибия

using System;

//метод шифрования из рассмотренных выше
public enum Method
{
    Method1,
    Method2
}

class PolybiusSquare
{
    char[,] square;
    string alphabet;
    Method encryptMethod;

    public PolybiusSquare(string alphabet = null, Method cipherMethod = Method.Method1)
    {
        this.alphabet = alphabet ?? "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
        encryptMethod = cipherMethod;
    }

    //возвращает квадрат Полибия
    char[,] GetSquare(string key)
    {
        var newAlphabet = alphabet;
        //удаляем из алфавита все символы которые содержит ключ
        for (int i = 0; i < key.Length; i++)
        {
            newAlphabet = newAlphabet.Replace(key[i].ToString(), "");
        }

        //добавляем пароль в начало алфавита, а в конец дополнительные знаки
        //для того чтобы избежать пустых ячеек
        newAlphabet = key + newAlphabet + "0123456789!@#$%^&*)_+-=<>?,.";

        //получаем размер стороны квадрата
        //округлением квадратного корня в сторону большего целого числа
        var n = (int)Math.Ceiling(Math.Sqrt(alphabet.Length));

        //создаем и заполняем массив
        square = new char[n, n];
        var index = 0;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (index < newAlphabet.Length)
                {
                    square[i, j] = newAlphabet[index];
                    index++;
                }
            }
        }

        return square;
    }

    //поиск символа в двухмерном массиве
    bool FindSymbol(char[,] symbolsTable, char symbol, out int column, out int row)
    {
        var l = symbolsTable.GetUpperBound(0) + 1;
        for (int i = 0; i < l; i++)
        {
            for (int j = 0; j < l; j++)
            {
                if (symbolsTable[i, j] == symbol)
                {
                    //значение найдено
                    row = i;
                    column = j;
                    return true;
                }
            }
        }

        //если ничего не нашли
        row = -1;
        column = -1;
        return false;
    }

    public string PolibiusEncrypt(string text, string password)
    {
        var outputText = "";
        var square = GetSquare(password);
        switch (encryptMethod)
        {
            case Method.Method1:
                for (int i = 0; i < text.Length; i++)
                {
                    if (FindSymbol(square, text[i], out int columnIndex, out int rowIndex))
                    {
                        var newRowIndex = rowIndex == square.GetUpperBound(1)
                            ? 0
                            : rowIndex + 1;
                        outputText += square[newRowIndex, columnIndex].ToString();
                    }
                }
                break;

            case Method.Method2:
                var m = text.Length;
                var coordinates = new int[m * 2];
                for (int i = 0; i < m; i++)
                {
                    if (FindSymbol(square, text[i], out int columnIndex, out int rowIndex))
                    {
                        coordinates[i] = columnIndex;
                        coordinates[i + m] = rowIndex;
                    }
                }

                for (int i = 0; i < m * 2; i += 2)
                {
                    outputText += square[coordinates[i + 1], coordinates[i]];
                }
                break;
        }

        return outputText;
    }

    public string PolybiusDecrypt(string text, string password)
    {
        var outputText = "";
        var square = GetSquare(password);
        var m = text.Length;
        switch (encryptMethod)
        {
            case Method.Method1:
                for (int i = 0; i < m; i++)
                {
                    if (FindSymbol(square, text[i], out int columnIndex, out int rowIndex))
                    {
                        var newRowIndex = rowIndex == 0
                            ? square.GetUpperBound(1)
                            : rowIndex - 1;
                        outputText += square[newRowIndex, columnIndex].ToString();
                    }
                }
                break;

            case Method.Method2:
                var coordinates = new int[m * 2];
                var j = 0;
                for (int i = 0; i < m; i++)
                {
                    if (FindSymbol(square, text[i], out int columnIndex, out int rowIndex))
                    {
                        coordinates[j] = columnIndex;
                        coordinates[j + 1] = rowIndex;
                        j += 2;
                    }
                }

                for (int i = 0; i < m; i++)
                {
                    outputText += square[coordinates[i + m], coordinates[i]];
                }
                break;
        }

        return outputText;
    }
}

Программа для шифрования и расшифровки текста

using System;

class Program
{
    static void Main(string[] args)
    {
        var polybius = new PolybiusSquare();
        Console.Write("Введите текст: ");
        var message = Console.ReadLine().ToUpper();
        Console.Write("Введите пароль(без повторов букв): ");
        var pass = Console.ReadLine().ToUpper();
        var cipherText = polybius.PolibiusEncrypt(message, pass);
        Console.WriteLine("Зашифрованный текст: {0}", cipherText);
        Console.WriteLine("Расшифрованный текст: {0}", 
            polybius.PolybiusDecrypt(cipherText, pass));
        Console.ReadLine();
    }
}

Результат работы программы:

Смотрите также: