用于所有UTF-8字符的Java中的Vigenère密码

时间:2012-04-23 12:34:21

标签: java encryption cryptography vigenere

我有这个简单的函数,用于通过Java中的Vigenère加密字符串。我省略了解密,因为这只是一个“ - ”而不是计算新值的行中的“+”。

但此功能仅适用于普通字母A-Z。如何更改函数以便它支持小写字母以及大写字母和所有其他UTF-8字符?

public static String vigenere_encrypt(String plaintext, String key) {
    String encryptedText = "";
    for (int i = 0, j = 0; i < plaintext.length(); i++, j++) {
        if (j == key.length()) { j = 0; } // use key again if end reached
        encryptedText += (char) ((plaintext.charAt(i)+key.charAt(j)-130)%26 + 65);
    }
    return encryptedText;
}

非常感谢你的帮助!

3 个答案:

答案 0 :(得分:4)

嗯,你要求它,我感到很困惑,但打印出密文,你会知道你刚要求的......

public static String vigenereUNICODE(String plaintext, String key, boolean encrypt) {

    final int textSize = plaintext.length();
    final int keySize = key.length();

    final StringBuilder encryptedText = new StringBuilder(textSize);
    for (int i = 0; i < textSize; i++) {
        final int plainNR = plaintext.codePointAt(i);
        final int keyNR = key.codePointAt(i % keySize);

        final long cipherNR;
        if (encrypt) {
            cipherNR = ((long) plainNR + (long) keyNR) & 0xFFFFFFFFL;
        } else {
            cipherNR = ((long) plainNR - (long) keyNR) & 0xFFFFFFFFL;
        }

        encryptedText.appendCodePoint((int) cipherNR);
    }

    return encryptedText.toString();
}

编辑:请不要在生产代码中使用,因为如果代码点确实可以编码/解码我还没有线索。据我所知,并非所有点都已定义,标准是一个移动目标。

答案 1 :(得分:4)

如果无法获得完整的unicode支持且您必须定义有效字符列表,那么为什么不使用这样的函数?

public static String vigenere_cipher(String plaintext, String key, boolean encrypt) {

    String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.-"; // including some special chars
    final int alphabetSize = alphabet.length();
    final int textSize = plaintext.length();
    final int keySize = key.length();
    final StringBuilder encryptedText = new StringBuilder(textSize);

    for (int i = 0; i < textSize; i++) {
        final char plainChar = plaintext.charAt(i); // get the current character to be shifted
        final char keyChar = key.charAt(i % keySize); // use key again if the end is reached
        final int plainPos = alphabet.indexOf(plainChar); // plain character's position in alphabet string
        if (plainPos == -1) { // if character not in alphabet just append unshifted one to the result text
            encryptedText.append(plainChar);
        }
        else { // if character is in alphabet shift it and append the new character to the result text
            final int keyPos = alphabet.indexOf(keyChar); // key character's position in alphabet string
            if (encrypt) { // encrypt the input text
                encryptedText.append(alphabet.charAt((plainPos+keyPos) % alphabetSize));
            }
            else { // decrypt the input text
                int shiftedPos = plainPos-keyPos;
                if (shiftedPos < 0) { // negative numbers cannot be handled with modulo
                    shiftedPos += alphabetSize;
                }
                encryptedText.append(alphabet.charAt(shiftedPos));
            }
        }
    }

    return encryptedText.toString();

}

这应该是一个非常简短且有效的版本。字母表可以很容易地存储在一个可以随时扩展的字符串中(这会导致不同的密文)。

答案 2 :(得分:3)

另一个答案是,确实在上面和下面做了Vigenere密码。小写字符,只需插入其他字符。使用此技术可以创建多个要编码的字符组。

public static String vigenere(String plaintext, String key, boolean encrypt) {

    final int textSize = plaintext.length();
    final int keySize = key.length();

    final int groupSize1 = 'Z' - 'A' + 1; 
    final int groupSize2 = 'z' - 'a' + 1;
    final int totalGroupSize = groupSize1 + groupSize2;

    final StringBuilder encryptedText = new StringBuilder(textSize);
    for (int i = 0; i < textSize; i++) {
        final char plainChar = plaintext.charAt(i);

        // this should be a method, called for both the plain text as well as the key
        final int plainGroupNumber; 
        if (plainChar >= 'A' && plainChar <= 'Z') {
            plainGroupNumber = plainChar - 'A';
        } else if (plainChar >= 'a' && plainChar <= 'z') {
            plainGroupNumber = groupSize1 + plainChar - 'a';
        } else {
            // simply leave spaces and other characters
            encryptedText.append(plainChar);
            continue;
        }

        final char keyChar = key.charAt(i % keySize);
        final int keyGroupNumber; 
        if (keyChar >= 'A' && keyChar <= 'Z') {
            keyGroupNumber = keyChar - 'A';
        } else if (keyChar >= 'a' && keyChar <= 'z') {
            keyGroupNumber = groupSize1 + keyChar - 'a';
        } else {
            throw new IllegalStateException("Invalid character in key");
        }

        // this should be a separate method
        final int cipherGroupNumber;
        if (encrypt) {
            cipherGroupNumber = (plainGroupNumber + keyGroupNumber) % totalGroupSize;
        } else {
            // some code to go around the awkward way of handling % in Java for negative numbers
            final int someCipherGroupNumber = plainGroupNumber - keyGroupNumber;
            if (someCipherGroupNumber < 0) {
                cipherGroupNumber = (someCipherGroupNumber + totalGroupSize);
            } else {
                cipherGroupNumber = someCipherGroupNumber;
            }
        }

        // this should be a separate method
        final char cipherChar;
        if (cipherGroupNumber < groupSize1) {
            cipherChar = (char) ('A' + cipherGroupNumber);
        } else {
            cipherChar = (char) ('a' + cipherGroupNumber - groupSize1);
        }
        encryptedText.append(cipherChar);
    }

    return encryptedText.toString();
}

同样,这是不安全的代码,因为使用的密码已经被打破了很长时间。不要在键中使用太多的“A”字符:)但字符编码应该是合理的。