Реализация шифра Виженера

Мне нужно реализовать вариант шифра Виженера. Я получил часть шифрования без проблем, но у меня есть ошибка в коде расшифровки, и я не понимаю, что я делаю неправильно.

Требования:

  • ключ может содержать только A - Z (верхний регистр)

  • кодовые значения для ключевых символов: 0 для A, 1 для B, ... и 25 для Z.

  • не кодировать символ, если код ‹ 32 (сохранить управляющие символы)

  • зашифрованный код символа = исходный код символа + ключевой код символа

  • окончательный зашифрованный символ должен быть между 32 и 126, исключительно поэтому, если окончательный зашифрованный символ> 126, его необходимо вернуть в диапазон 32–126, добавив 32 к значению, а затем вычтя 126

Код шифрования:

// it works ok
// I have tested it with some provided strings and the results are as expected

public String encrypt(String plainText)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < plainText.length(); i++) {
        char c = plainText.charAt(i);
        if (c >= 32) {
            int keyCharValue = theKey.charAt(i % theKey.length()) - 'A';
            c += keyCharValue;
            if (c > 126) {
                c = (char) (c + 32 - 126);
            }
        }
        sb.append(c);
    }
    return sb.toString();
}

Код расшифровки:

// there probably is an off-by-one error somewhere
// everything is decrypted ok, except '~' which gets decrypted to ' ' (space)

public String decrypt(String cipherText)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < cipherText.length(); i++) {
        char c = cipherText.charAt(i);
        if (c >= 32) {
            int keyCharValue = theKey.charAt(i % theKey.length()) - 'A';
            c -= keyCharValue;
            if (c < 32) {
                c = (char) (c + 126 - 32);
            }
        }
        sb.append(c);
    }
    return sb.toString();
}

Пример (с ключом ABCDEFGHIJKLMNOPQRSTUVWXYZ):

  • оригинал ~~~~~~~~~~~~~~~~~~~~~~~~~~

  • зашифровано ~!"#$%&'()*+,-./0123456789

  • расшифровано ~ ('~' с последующими пробелами)

РЕДАКТИРОВАТЬ:

Вот код, который я использую для тестирования (он проверяет каждый символ от 0 до 126, повторяющийся как строка):

public static void main(String[] args) {
    int passed = 0;
    int failed = 0;
    String key = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    for (int c = 0; c <= 126; c++) {
        StringBuilder sbString = new StringBuilder();
        for (int i = 0; i <= 25; i++) {
            sbString.append((char) c);
        }
        String original = sbString.toString();
        Cipher cipher = Cipher(key);
        String encrypted = cipher.encrypt(original);
        String decrypted = cipher.decrypt(encrypted);
        if (!original.equals(decrypted)) {
            failed++;
            System.out.println("--FAILED--");
            System.out.println(original);
            System.out.println(encrypted);
            System.out.println(decrypted);
        } else {
            passed++;
        }
    }
    int tests = passed + failed;
    System.out.println(tests + " tests");
    System.out.println("passed: " + passed);
    System.out.println("failed: " + failed);
}

person user2820314    schedule 26.09.2013    source источник
comment
@Pratik Похоже, это заглавный алфавит.   -  person Joachim Isaksson    schedule 26.09.2013
comment
Привет, я запустил вышеуказанные методы, и они работают правильно... Я получаю исходное сообщение обратно из метода расшифровки.   -  person Pratik Shelar    schedule 26.09.2013
comment
Эксклюзивный диапазон 32-126 будет означать, что ~ недопустимый результат. Вы имеете в виду инклюзивно?   -  person Joachim Isaksson    schedule 26.09.2013


Ответы (1)


Я считаю, что If(c ‹ 32) в расшифровке должно быть If (c ‹= 32).

Рассуждение: если вы возьмете случай Char(126) или '~', а затем добавите к нему единицу в шифровании, вы получите 127, которое проходит через преобразование шифрования и становится 33.

При расшифровке вы получаете 33 минус тот же самый 1, что оставляет вам 32, что не вызовет особого случая расшифровки. Включение 32 в этот оператор вызовет специальную расшифровку и изменит 32 ("") на 126 ("~").

Вы правы, это ошибка на одну ошибку, но это довольно тонко

РЕДАКТИРОВАТЬ: возникает ошибка столкновения, потому что char (32) и char (126) хешируются до одного и того же значения. В моем предыдущем примере это значение было бы 33, уравнение необходимо изменить так, чтобы Char(126) хэшировалось до 32.

Изменение c = (char) (c + 32 - 126); to c = (char) (c + 32 - 127); должен освободить дополнительное пространство, чтобы предотвратить столкновение. Расшифровка также должна быть изменена с c = (char) (c + 126 - 32); to c = (char) (c + 127 - 32);

И кто-то написал это в моем комментарии.

person orgtigger    schedule 26.09.2013
comment
Если я заменю c < 32 на c <= 32, это исправит этот конкретный случай, но только создаст другую проблему: ` ` (пробел) расшифровывается как ~. - person user2820314; 26.09.2013
comment
@user2820314 user2820314 Это разовое, но исправление не меняет лимит, оно меняет 32 - 126 на 32 - 127 и 126 - 32 на 127 - 32. - person Joachim Isaksson; 26.09.2013
comment
@Joachim Isaksson: Точно, это не исправляет. Я просматривал этот код уже несколько часов и до сих пор не вижу ошибки. Я в тупике. - person user2820314; 26.09.2013
comment
Что произойдет, если вы поменяете 126-е на 127-е? - person orgtigger; 26.09.2013
comment
@user2820314 user2820314 Думаю, вы меня неправильно поняли. Изменение значений, как в моем комментарии, устраняет проблему. Поскольку вы хотите, чтобы последовательность была 125, 126, 32, 33... (т.е. 127 должно превратиться в 32), вам нужно вычесть 127 вместо 126. - person Joachim Isaksson; 26.09.2013
comment
Я изменил 126 на 127 как в шифровании, так и в дешифровании, и это сработало! Спасибо, вы избавили меня от многих серых клеток. Это научит меня принимать инструкции как должное и не проверять их на достоверность. - person user2820314; 26.09.2013