Saltar al contenido

Cifrado César en Java

Un programa completo que puedes compilar ya mismo. Cópialo, o escribe tu propio texto y mira qué hace el código con cada letra.

CaesarCipher.java
public class CaesarCipher {     public static String caesar(String text, int shift) {        StringBuilder result = new StringBuilder();        for (char c : text.toCharArray()) {            if (c < 128 && Character.isLetter(c)) {                char base = Character.isUpperCase(c) ? 'A' : 'a';                int index = Math.floorMod(c - base + shift, 26);                result.append((char) (base + index));            } else {                result.append(c);            }        }        return result.toString();    }     public static void main(String[] args) {        System.out.println(caesar("¡Hola, mundo!", 3));        // ¡Krod, pxqgr!    }}
anuncio

Compilar y ejecutar

Guarda el programa como CaesarCipher.java, porque el nombre del archivo debe coincidir con el de la clase. Después ejecuta estos dos comandos en la misma carpeta:

Terminal
javac CaesarCipher.javajava CaesarCipher

El primero compila el código y el segundo lo ejecuta e imprime el texto cifrado. Si el cifrado en sí es nuevo para ti, la guía lo explica sin código.

Cómo funciona el código

En Java un char también es un número, así que puedes operar con él directamente: 'H' - 'A' da 7, la posición de la letra en el alfabeto. Tras sumar el desplazamiento, Math.floorMod mantiene el resultado entre 0 y 25, de modo que con un desplazamiento de 3 la Z cae en la C.

base + index devuelve un int, y por eso aparece la conversión (char). El resultado se acumula en un StringBuilder, ya que añadir a un String dentro de un bucle crea un objeto nuevo cada vez.

Espacios, signos y cifras pasan por la rama else sin cambios. La comprobación c < 128 hace falta porque Character.isLetter también acepta la ñ y las vocales con tilde: sin ella se convertirían en otra letra cualquiera y el texto ya no se podría descifrar bien.

Descifrar en Java

No hace falta un segundo método. Descifrar es desplazar en sentido contrario, así que basta con pasar un número negativo:

Java
System.out.println(caesar("¡Krod, pxqgr!", -3));// ¡Hola, mundo!

Para esto sirve Math.floorMod. El % de Java conserva el signo del número de la izquierda: -3 % 26 da -3, que ni siquiera es una letra. Math.floorMod(-3, 26) da 23, y la A vuelve a la X. En la versión en Python, el propio % ya se comporta así.

Leer datos con Scanner

Muchos ejercicios piden un programa que lea el texto y el desplazamiento por teclado. Coloca el import al principio del archivo y sustituye main por esto:

Java
import java.util.Scanner; public static void main(String[] args) {    Scanner scanner = new Scanner(System.in);    System.out.print("Texto: ");    String text = scanner.nextLine();    System.out.print("Desplazamiento: ");    int shift = scanner.nextInt();    System.out.println(caesar(text, shift));}

Lee primero el texto. nextInt() deja pendiente el salto de línea, y un nextLine() posterior devolvería una cadena vacía.

Romper el cifrado por fuerza bruta

Con 26 letras solo hay 25 desplazamientos posibles, y un bucle corto basta para leer el mensaje sin la clave. Busca en la salida la línea que tenga sentido:

Java
public static void crack(String text) {    for (int shift = 1; shift < 26; shift++) {        System.out.println(shift + " " + caesar(text, -shift));    }} public static void main(String[] args) {    crack("¡Krod, pxqgr!");    // 1 ¡Jqnc, owpfq!    // 2 ¡Ipmb, nvoep!    // 3 ¡Hola, mundo!    // ...}

El artículo sobre el ataque de fuerza bruta entra en más detalle, y el descifrador en línea hace lo mismo en tu navegador.

Cifrado César con la ñ

Para desplazar también la ñ, guarda el alfabeto en un String y busca cada carácter con indexOf(). Son las mismas 27 letras que usa nuestra herramienta:

Java
static final String ALPHABET = "abcdefghijklmnñopqrstuvwxyz"; public static String caesarAlphabet(String text, int shift) {    StringBuilder result = new StringBuilder();    for (char c : text.toCharArray()) {        int position = ALPHABET.indexOf(Character.toLowerCase(c));        if (position == -1) {            result.append(c);        } else {            int index = Math.floorMod(position + shift, ALPHABET.length());            char next = ALPHABET.charAt(index);            result.append(Character.isUpperCase(c) ? Character.toUpperCase(next) : next);        }    }    return result.toString();} public static void main(String[] args) {    System.out.println(caesarAlphabet("El niño", 3));    // Hñ plqr}

Ahora la vuelta depende de ALPHABET.length(), así que no tienes que escribir el 27 en ningún sitio. Puedes comparar el resultado en la herramienta de cifrado César con el alfabeto español.

Cifrar un archivo de texto

Files.readString y Files.writeString leen y escriben un archivo entero en una línea, en UTF-8 por defecto, de manera que la ñ y las tildes se conservan. Pueden fallar, por lo que main debe declarar throws IOException.

Java
import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path; public static void main(String[] args) throws IOException {    String text = Files.readString(Path.of("message.txt"));    Files.writeString(Path.of("encrypted.txt"), caesar(text, 3));}

Probar el código

Pon estas líneas en main para detectar los errores habituales. Java ignora assert si no lo activas, así que ejecuta el programa con java -ea CaesarCipher. Si todo va bien, imprime OK.

Java
assert caesar("ABC", 3).equals("DEF");assert caesar("xyz", 3).equals("abc");assert caesar("Hello, World!", 5).equals("Mjqqt, Btwqi!");assert caesar(caesar("Java", 7), -7).equals("Java");assert caesar("A", 26).equals("A");assert caesar("é", 3).equals("é");System.out.println("OK");

Errores frecuentes

El más común es usar % con un desplazamiento negativo, como vimos antes. Otro es olvidar la conversión: result.append(base + index) añade el número 75 cuando querías la letra K. Y compara las cadenas de tus pruebas con equals(), porque == solo mira si son el mismo objeto.

Preguntas frecuentes

¿Qué versión de Java necesito?

El programa principal funciona en Java 8 y posteriores. El ejemplo de archivos necesita Java 11, que añadió Files.readString. Hemos compilado y ejecutado el código de esta página con Java 21.

¿Sirve para proteger datos reales?

No. El bucle de arriba lo rompe en segundos. Úsalo para aprender y para pasatiempos. Para datos reales, Java incluye cifrado moderno como AES en el paquete javax.crypto.

¿Cómo compruebo que mi resultado es correcto?

Introduce el mismo texto y desplazamiento en nuestra herramienta de cifrado César y compara. También puedes llamar a la API REST gratuita desde tus pruebas.

Sigue aprendiendo