Шифрование / дешифрование строки с использованием аффинного шифра с использованием исходной таблицы 128 ASCII - PullRequest
0 голосов
/ 08 февраля 2019

Итак, я пытаюсь зашифровать сообщение с помощью аффинного шифра.Я хочу использовать все 128 символов ASCII, чтобы сделать это.Я получаю сообщение об ошибке, когда речь идет о конкретных буквах, Q, R, S, T и U. Они неправильно конвертируют и отображают неправильное дешифрование.Есть идеи, что происходит?

Зашифрованное сообщение

RUX[^adgjmpsvy|

Расшифрованное сообщение

ABCDEFGHIJKLMNOP/.-,+VWXYZ

Мой код;

public class EncryptionProject {

   public static void main(String[] args) {

        StringBuilder s = new StringBuilder("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

        System.out.println("Encrypted Message");
        StringBuilder encryptedMessage = affineEncryption(s);
        System.out.print(encryptedMessage);

        System.out.println("\nDecrypted Message");
        StringBuilder decryptedMessage = affineDecryption(encryptedMessage);
        System.out.print(decryptedMessage);
    }

    /* use affine cipher to encrypt message */
    public static StringBuilder affineEncryption(StringBuilder s) {
        StringBuilder encryption = new StringBuilder();
        final int A = 3, B = 15, M = 128; // a * p + b (mod m)

        /* loop through string and compute affine cipher */
        for (int i = 0; i < s.length(); i++) {
            encryption.append((char)((A * s.charAt(i) + B) % M));
        }

        return encryption;
    }

    /* decryption method */
    public static StringBuilder affineDecryption(StringBuilder s) {
        final int A = 43, B = 15, M = 128;
        StringBuilder decryption = new StringBuilder();

        /* loop through and undo affine cipher using inverse of A */
        for (int i = 0; i < s.length(); i++) {
            decryption.append((char)((A * Math.abs((s.charAt(i) - B))) % M));
        }

        return decryption;
    }
}

1 Ответ

0 голосов
/ 08 февраля 2019

Причина проблемы заключается в том, что для отрицательных дивидендов a и / или делителей n математическое определение операции по модулю обычно может отличаться от определения в соответствующем языке программирования.

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

a mod n = a - n * floor(a/n) 

, где floor(a/n) - это floor -функция , которая дает на выходе наибольшее целое число, меньшее или равноеего вход (я не рассматриваю отрицательные делители n, поскольку n = 128 > 0 в вопросе).

Примеры положительного делителя n = 128 с положительным дивидендом a = 559 (вверху) и отрицательного дивиденда a = -559 (внизу):

559 mod 128 = 559 - 128 * floor(559/128) = 559 - 128 * floor(4.37) = 559 -128 * 4 = 47
-559 mod 128 = -559 - 128 * floor(-559/128) = -559 - 128 * floor(-4.37) = -559 -128 * (-5) = 81

Однако во многих языках программирования(включая Java) используется другое определение для операции по модулю (иногда упоминается как симметричный вариант):

a mod n = a - n * trunc(a/n) 

Здесь trunc(a/n) означает усеченное деление, где частное a/n округлено в сторонунуль.

Пример положительного делителя n = 128 с положительным дивидендом a = 559 (вверху) и отрицательным дивидендом a = -559 (внизу):

559 mod 128 = 559 - 128 * trunc(559/128) = 559 - 128 * trunc(4.37) = 559 -128 * 4 = 47      
-559 mod 128 = -559 - 128 * trunc(-559/128) = -559 - 128 * trunc(-4.37) = -559 -128 * (-4) = -47

Как видно, обаопределения, математические и симметричные, дают разные результаты для отрицательных дивидендов.

Непосредственной причиной проблемы является то, что в формуле аффинного шифра подразумевается математическое определение, тогда как вВ вашем коде используется симметричный вариант (потому что Java использует симметричный вариант).Это хорошо видно на примере буквы Q: в вашем коде буква Q (= 81 dec) зашифрована (A = 3, B = 15, M = 128) до

(3 * 81 + 15) % 128 = 2

Расшифровка (A = 43, B = 15, M = 128) равна

(43 * (2 - 15)) % 128 = -559 % 128

В зависимости от варианта по модулю результат равен -47 и 81 для симметричного и математическоговариант соответственно (см. выше).Поскольку в коде используется симметричный вариант, вы получите «неправильный» результат -47.

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

a mMod n  = ((a sMod n) + n) sMod n

, где mMod и sMod обозначают математический и симметричный оператор по модулю соответственно.Для этого определите новый метод:

private static int mathematicalMod(int a, int n) {
    return ((a % n) + n) % n;
}

и замените affineEncryption -метод

encryption.append((char)((A * s.charAt(i) + B) % M));

на

encryption.append((char)mathematicalMod(A * s.charAt(i) + B, M));

и affineDecryption -method

decryption.append((char)((A * Math.abs((s.charAt(i) - B))) % M));

с

decryption.append((char)mathematicalMod(A * (s.charAt(i) - B),  M));

Обратите внимание, что при последней замене также удаляется Math.abs -метод, поскольку он не принадлежит аффинности -cipher-decrypt-алгоритм .

С этими изменениями и следующим вводом

StringBuilder s = new StringBuilder("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0=1!2\"34$5%6&7/8(9)^`+*#'-_.:,;<>\\[]~{}|@");

вывод в консоль становится:

enter image description here

В Java также существует реализация симметричного варианта: int Math.floorMod(int a, int n), который, конечно же, также можно использовать вместо пользовательской реализации int mathematicalMod(int a, int n).

...