Vigenère密码实现

时间:2013-09-26 16:45:17

标签: java algorithm encryption vigenere

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

要求是:

  • 该密钥只能包含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);
}

1 个答案:

答案 0 :(得分: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);

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