Cifrado Vigenère en Java para todos los caracteres UTF-8
encryption cryptography (3)
Bueno, lo pediste y me dieron ganas de desconcertar, pero imprime el texto cifrado y sabrás lo que acabas de pedir ...
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();
}
EDITAR: Por favor, nunca lo use en el código de producción, ya que no tengo ni idea de si los puntos de código pueden codificarse / descodificarse. No se han definido todos los puntos, hasta donde yo sé, y el estándar es un objetivo en movimiento.
Tengo esta sencilla función para encriptar cadenas vía Vigenère en Java. Omití el descifrado ya que es solo un "-" en lugar de "+" en la línea donde se calcula el nuevo valor.
Pero esta función solo funciona para el alfabeto normal AZ. ¿Cómo puedo cambiar la función para que admita letras minúsculas, así como letras mayúsculas y todos los demás caracteres 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;
}
¡Muchas gracias por su ayuda!
Otra respuesta, que hace el cifrado Vigenere en caracteres en mayúscula y minúscula, simplemente insertando los otros caracteres. Use esta técnica para crear múltiples grupos de caracteres para codificar.
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();
}
De nuevo, este es un código inseguro ya que el cifrado utilizado se ha roto durante siglos. No use demasiados caracteres ''A'' en sus teclas :) Pero la codificación de caracteres debe ser sonido.
Si el soporte completo de Unicode no es posible y usted tiene que definir su lista de caracteres válidos, de todos modos, ¿por qué no simplemente usar una función como esta?
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();
}
Esta debería ser una versión muy corta y funcional. Y el alfabeto se puede almacenar fácilmente en una cadena que siempre se puede extender (lo que da como resultado diferentes textos cifrados).