Criptografía
Cifrado, codificación y hash: diferencias explicadas
Separa codificación, cifrado y hash con laboratorios de Base64, SHA-256 y OpenSSL. Entiende por qué Base64 no protege y el hash es de un solo sentido.
Crea un cifrado César en Python, pruébalo con unittest y comprueba por qué no ofrece confidencialidad real.
Vas a escribir una función caesar(). Desplaza las letras del alfabeto inglés una cantidad de posiciones, deja intactos los demás caracteres y revierte el desplazamiento cuando recibe un número negativo. Después ejecutarás un pequeño conjunto de pruebas y leerás qué comprueba cada una.
Solo necesitas Python 3. Si la idea de un cifrado por desplazamiento te resulta nueva, lee primero ¿Qué es el cifrado César?.
Instala Python 3 desde python.org. El código usa solo la biblioteca estándar, así que no hay nada que instalar con pip. Crea una carpeta para el laboratorio y guarda los archivos allí.
La salida de este artículo proviene de Python 3.12.10 en Windows 11. No probé otras versiones.
La función ord() de Python devuelve el punto de código Unicode de un carácter. chr() hace lo contrario y convierte un punto de código de nuevo en carácter. Para la letra mayúscula A, el punto de código es 65.
Ejecuta en la terminal:
python -I -c "print(ord('A'), chr(65))"Salida:
65 ALa opción -I ejecuta Python en modo aislado. Se ignoran las variables de entorno que empiezan con PYTHON, y la carpeta actual no se añade a la ruta de búsqueda de módulos. Úsala cuando ejecutes código de una carpeta que no escribiste tú.
El desplazamiento trabaja con posiciones que empiezan en cero. Restar 65 convierte la A en 0 y la Z en 25. El paso % 26 hace que el resultado vuelva al inicio del alfabeto, y sumar 65 devuelve el rango de mayúsculas:
chr((ord(letter) - 65 + shift) % 26 + 65)Las minúsculas empiezan en 97, así que la misma idea usa 97 en lugar de 65.
El operador % de Python nunca devuelve un número negativo cuando el divisor es positivo. Por eso un desplazamiento negativo funciona sin código adicional:
python -I -c "print((0 - 3) % 26)"Salida:
23Cero menos tres da la vuelta y cae en la posición 23, que es la letra X.
Guarda este código como caesar_cipher.py. Es el mismo contenido que el archivo del laboratorio.
"""Educational Caesar cipher only. NOT secure encryption.
Shift ASCII English A-Z/a-z; preserve every other Unicode character as-is.
"""
def caesar(text: str, shift: int) -> str:
shift %= 26
result = []
for character in text:
if 'A' <= character <= 'Z':
result.append(chr((ord(character) - 65 + shift) % 26 + 65))
elif 'a' <= character <= 'z':
result.append(chr((ord(character) - 97 + shift) % 26 + 97))
else:
result.append(character)
return ''.join(result)
if __name__ == '__main__':
print(caesar('HELLO, World!', 3)) # KHOOR, Zruog!
print(caesar('KHOOR, Zruog!', -3)) # HELLO, World!La primera línea de la función, shift %= 26, reduce cualquier desplazamiento al rango de 0 a 25. Un desplazamiento de 29 se comporta como uno de 3, y uno de -3 pasa a ser 23.
Ejecuta el archivo:
python -I caesar_cipher.pySalida:
KHOOR, Zruog!
HELLO, World!La función solo cambia las letras de la A a la Z y de la a a la z. Los dígitos, los espacios, la puntuación y las letras acentuadas pasan sin cambios. Así el código se mantiene corto. Un cifrado que tratara las letras acentuadas necesitaría una regla para cada una, y este laboratorio no define ninguna.
El laboratorio también incluye test_caesar_cipher.py. Abre la terminal en la carpeta que contiene los dos archivos y ejecuta:
python -I -m unittest discover -p 'test_*.py' -vSalida:
test_large_shift (test_caesar_cipher.CaesarCipherTest.test_large_shift) ... ok
test_lower (test_caesar_cipher.CaesarCipherTest.test_lower) ... ok
test_negative (test_caesar_cipher.CaesarCipherTest.test_negative) ... ok
test_roundtrip (test_caesar_cipher.CaesarCipherTest.test_roundtrip) ... ok
test_upper (test_caesar_cipher.CaesarCipherTest.test_upper) ... ok
test_wrap (test_caesar_cipher.CaesarCipherTest.test_wrap) ... ok
----------------------------------------------------------------------
Ran 6 tests in 0.001s
OKCada prueba comprueba un comportamiento:
test_upper y test_lower confirman que HELLO se convierte en KHOOR y que attack se convierte en dwwdfn.test_wrap confirma que Z avanza hasta C. Eso solo funciona si la vuelta al alfabeto está bien hecha.test_large_shift confirma que un desplazamiento de 29 da el mismo resultado que uno de 3.test_negative comprueba el descifrado desplazando DEF en -3.test_roundtrip cifra un texto con desplazamiento 7, lo descifra con -7 y espera recibir el original. El texto de ejemplo incluye puntuación, un dígito y la á, así que también verifica que los caracteres que no son letras se conservan.Si cambias el código y una prueba falla, el mensaje muestra la entrada, el valor esperado y el valor obtenido. Lee ese mensaje antes de cambiar cualquier otra cosa.
Un cifrado César tiene solo 25 desplazamientos útiles. El desplazamiento 0 y el 26 devuelven el texto original. Una persona puede probar todos a mano, y un programa los prueba todos en un instante.
El análisis de frecuencias es un segundo problema. En inglés, letras como la E y la T aparecen más que la Q o la Z. En un mensaje más largo, las letras más comunes del texto cifrado suelen señalar las letras más comunes del texto original.
Por eso este cifrado no ofrece confidencialidad real. No lo uses para contraseñas, registros de clientes, tokens ni nada que importe. Si necesitas cifrado de verdad, usa una biblioteca bien probada y un algoritmo estándar. La OWASP Cryptographic Storage Cheat Sheet reúne las reglas básicas para proteger datos almacenados.
Usa este ejercicio para aprender aritmética modular, códigos de caracteres y la diferencia entre una transformación de juguete y un cifrado real.
Cuando las pruebas pasen, puedes pedirle a un modelo de lenguaje que explique la línea del módulo, sugiera casos límite o escriba más pruebas. Una buena consulta deja claros los límites desde el principio:
Revisa este cifrado César educativo. ¿Qué pasa con los desplazamientos negativos, las letras acentuadas y los textos que no usan el alfabeto latino? No lo describas como cifrado seguro.
Ejecuta cualquier prueba que proponga el modelo antes de aceptarla. Los modelos se equivocan, y una prueba que falla dice más que una explicación muy convincente.
Cuando el laboratorio funcione, guarda la carpeta en un sistema de control de versiones para seguir los cambios. El siguiente artículo, ¿Qué es GitHub?, explica cómo hacerlo.
Criptografía
Separa codificación, cifrado y hash con laboratorios de Base64, SHA-256 y OpenSSL. Entiende por qué Base64 no protege y el hash es de un solo sentido.
Criptografía
Por qué los hashes rápidos fallan con contraseñas, qué hacen la sal y el factor de trabajo, y cómo hashear y verificar con Argon2id en Python.
Criptografía
Claves pública y privada desde cero: qué prueba una firma, por qué la privada no sale de su dueño y un lab Ed25519 donde un archivo alterado falla.