4

我必须实现Vigenère cipher的变体。我得到了没有问题的加密部分,但我在解密代码中有一个错误,我不明白我做错了什么。

要求是:

  • 键只能包含A- Z(大写)

  • 关键字符的代码值为 A 为 0,B 为 1,...,Z 为 25

  • 如果代码 < 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);
}
4

1 回答 1

2

我相信解密中的 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); 到 c = (char) (c + 32 - 127); 应该释放额外的空间以防止发生碰撞。解密也必须从 c = (char) (c + 126 - 32); 到 c = (char) (c + 127 - 32);

有人在我的评论中发布了这一点。

于 2013-09-26T17:04:58.193 回答