Saltar al contenido

Cifrado César en Python

La función completa tiene diez líneas. Cópiala, o escribe tu propio texto y mira qué hace el código con cada letra.

Python 3
def caesar(text, shift):    result = ""    for char in text:        if char.isascii() and char.isalpha():            base = ord("A") if char.isupper() else ord("a")            index = (ord(char) - base + shift) % 26            result += chr(index + base)        else:            result += char    return result print(caesar("¡Hola, mundo!", 3))# ¡Krod, pxqgr!
anuncio

Cómo funciona el código

El bucle recorre el texto carácter a carácter. ord() convierte una letra en su número: ord("A") es 65 y ord("a") es 97. Al restar esa base obtienes la posición de la letra en el alfabeto, de 0 a 25.

Después de sumar el desplazamiento, % 26 da la vuelta al alfabeto, de modo que con un desplazamiento de 3 la Z cae en la C. chr() devuelve el número a su forma de letra. Si el cifrado en sí es nuevo para ti, la guía lo explica sin código.

Espacios, signos y cifras pasan por la rama else y no cambian. Tampoco cambian la ñ ni las vocales con tilde, y para eso está isascii(): sin esa comprobación, Python trata la ñ como una minúscula normal, la convierte en otra letra cualquiera y el texto ya no se puede descifrar bien.

Descifrar en Python

No hace falta una segunda función. Descifrar es desplazar en sentido contrario, así que basta con pasar un número negativo:

Python
print(caesar("¡Krod, pxqgr!", -3))# ¡Hola, mundo!

Funciona porque aquí el % de Python nunca da un negativo: (0 - 3) % 26 da 23, y la A vuelve a la X. En C, Java y JavaScript saldría -3, por lo que la versión en JavaScript necesita un paso más.

Un programa que pide datos al usuario

Muchos ejercicios piden un programa que lea el texto y el desplazamiento por teclado. Añade esto debajo de la función:

Python
text = input("Texto: ")shift = int(input("Desplazamiento: "))mode = input("¿Cifrar o descifrar? (c/d): ") if mode == "d":    shift = -shift print(caesar(text, shift))

input() siempre devuelve una cadena, por lo que el desplazamiento debe pasar por int(). Si alguien escribe una palabra en lugar de un número, Python se detiene con un ValueError.

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:

Python
def crack(text):    for shift in range(1, 26):        print(shift, caesar(text, -shift)) 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.

Una versión más corta con str.translate

Cuando entiendas el bucle, puedes cambiarlo por una tabla de traducción. str.maketrans() empareja cada letra con su versión desplazada, y translate() aplica la tabla a todo el texto. La ñ tampoco se toca aquí.

Python
from string import ascii_lowercase as lower, ascii_uppercase as upper def caesar(text, shift):    shift %= 26    table = str.maketrans(        lower + upper,        lower[shift:] + lower[:shift] + upper[shift:] + upper[:shift],    )    return text.translate(table)

Los resultados son iguales y, en textos largos, suele ir más rápido porque la tabla se crea una sola vez. Para un primer ejercicio, el bucle se explica mejor.

Cifrado César con la ñ

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

Python
ALPHABET = "abcdefghijklmnñopqrstuvwxyz" def caesar_alphabet(text, shift):    result = ""    for char in text:        letter = char.lower()        if letter in ALPHABET:            index = (ALPHABET.index(letter) + shift) % len(ALPHABET)            new = ALPHABET[index]            result += new.upper() if char.isupper() else new        else:            result += char    return result print(caesar_alphabet("El niño", 3))# Hñ plqr

Ahora la vuelta depende de len(ALPHABET), 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

Lee el archivo, pasa su contenido a la función y guarda el resultado en un archivo nuevo. Con encoding="utf-8", la ñ y las tildes se conservan en cualquier sistema.

Python
with open("message.txt", encoding="utf-8") as source:    text = source.read() with open("encrypted.txt", "w", encoding="utf-8") as target:    target.write(caesar(text, 3))

El mismo cifrado como clase

Una clase resulta útil si usas la misma clave muchas veces o si te piden código orientado a objetos. Guarda el desplazamiento y aprovecha la función del principio de la página:

Python
class CaesarCipher:    def __init__(self, shift=3):        self.shift = shift     def encrypt(self, text):        return caesar(text, self.shift)     def decrypt(self, text):        return caesar(text, -self.shift) cipher = CaesarCipher(5)print(cipher.encrypt("¡Hola, mundo!"))# ¡Mtqf, rzsit!

Probar el código

Unas pocas líneas con assert detectan casi todos los errores: pasar de la Z, conservar mayúsculas y minúsculas, respetar los signos y recuperar el texto original. Si todo va bien, el programa imprime OK.

Python
assert caesar("ABC", 3) == "DEF"assert caesar("xyz", 3) == "abc"assert caesar("Hello, World!", 5) == "Mjqqt, Btwqi!"assert caesar(caesar("Python", 7), -7) == "Python"assert caesar("A", 26) == "A"assert caesar("é", 3) == "é"print("OK")

Errores frecuentes

El clásico es escribir chr(ord(char) + shift) sin módulo, y así la Z con desplazamiento 3 se convierte en el símbolo ]. También es habitual usar la base 65 para todas las letras, lo que estropea las minúsculas. Y si olvidas int() alrededor de input(), Python se detiene con un TypeError al sumar el desplazamiento.

Preguntas frecuentes

¿Qué versión de Python necesito?

Python 3.7 o posterior, que es cuando se añadió isascii(). Hemos ejecutado el código de esta página en Python 3.9. No necesita paquetes adicionales.

¿Sirve para proteger datos reales?

No. El bucle de arriba lo rompe en segundos. Úsalo para aprender y para pasatiempos, y protege contraseñas o datos privados con cifrado moderno de una librería mantenida.

¿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