Cincuenta y cinco minutos en clase; los minutos de cada ejercicio son un ritmo sugerido y el docente gestiona el tiempo, así que lo que no se cierre en el aula continúa como trabajo independiente. Las demostraciones corren en su navegador, sin conexión y sin instalar nada. Los ejercicios 1 y 3 se hacen con OpenSSL o con Python en su máquina: los comandos están aquí, con botón de copiar.
head, tail y cat), no en cmd ni en PowerShell, donde no existen. En macOS o Linux, la Terminal normal. La alternativa en Python corre en cualquier terminal.El escudo de la Institución, aplanado a dos colores y cifrado con AES-256 y una llave de 256 bits generada al azar. Se cifraron los bytes de los píxeles, no el archivo: por eso el resultado sigue siendo una imagen. Lo único que cambia entre las dos versiones cifradas es el modo de operación.
Una imagen impresiona, pero el problema real está en los registros. Este texto tiene cuatro bloques de dieciséis caracteres y tres de ellos son idénticos. Cífrelo en los dos modos y compare bloque contra bloque.
ECB cifra cada bloque de dieciséis bytes por separado y siempre de la misma forma. Bloques de entrada iguales producen bloques de salida iguales, así que la estructura del mensaje sobrevive al cifrado. En la imagen eso dibuja el escudo; en una tabla permite contar cuántos registros comparten un valor, y a partir de ahí deducir cuál es sin descifrar nada.
CBC encadena cada bloque con el anterior y arranca de un vector de inicialización aleatorio, así que dos bloques iguales producen salidas distintas. CTR hace lo propio combinando cada bloque con un contador distinto. Ninguno de los dos, sin embargo, detecta una alteración: eso es lo que van a comprobar en el ejercicio 2.
Tomen una imagen con zonas de color uniforme, cífrenla en ECB y en CBC conservando la cabecera del archivo, y comparen. Entreguen las dos imágenes y la explicación de la diferencia.
-nopad no dé error. Si prefieren traer la suya, que sea un BMP de 24 bits con pocos colores y zonas grandes de un solo tono: con degradados o fotografía el efecto no aparece, porque ECB solo delata lo que se repite.# llave de 256 bits y vector de 128, como el martes openssl rand -hex 32 > llave.hex openssl rand -hex 16 > vi.hex # separar cabecera (54 bytes) y píxeles head -c 54 escudo-plano.bmp > cabecera.bin tail -c +55 escudo-plano.bmp > pixeles.bin # cifrar SOLO los píxeles, sin relleno, con -K mayúscula openssl enc -aes-256-ecb -in pixeles.bin -out ecb.bin -K $(cat llave.hex) -nopad openssl enc -aes-256-cbc -in pixeles.bin -out cbc.bin -K $(cat llave.hex) -iv $(cat vi.hex) -nopad # volver a armar las imágenes cat cabecera.bin ecb.bin > escudo-ecb.bmp cat cabecera.bin cbc.bin > escudo-cbc.bmp
# pip install pillow cryptography import os from PIL import Image from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes img = Image.open("escudo-plano.bmp").convert("RGB") img = img.quantize(colors=2).convert("RGB") # aplanar: sin esto no se ve nada crudo = img.tobytes() assert (img.width * 3) % 16 == 0 # la fila debe cuadrar con el bloque llave, vi = os.urandom(32), os.urandom(16) def cifra(modo): c = Cipher(algorithms.AES(llave), modo).encryptor() return c.update(crudo) + c.finalize() Image.frombytes("RGB", img.size, cifra(modes.ECB())[:len(crudo)]).save("ecb.png") Image.frombytes("RGB", img.size, cifra(modes.CBC(vi))[:len(crudo)]).save("cbc.png")
Cifren un texto en CTR y en GCM, alteren un byte del texto cifrado en los dos casos e intenten descifrar. Documenten qué pasa en cada modo y por qué. Este panel hace el ataque completo en su navegador; el mismo ataque en Python está más abajo.
En CTR el cifrado consiste en combinar el mensaje con una secuencia que depende de la llave y de un contador. Esa combinación es reversible byte a byte: cambiar un byte del texto cifrado cambia exactamente ese byte del texto en claro, y ningún otro. El atacante no necesita la llave para saber qué va a salir; le basta saber qué decía el original en esa posición. Por eso la salida no es basura: es el mensaje que el atacante eligió.
En GCM el cifrado es el mismo —GCM usa CTR por dentro—, pero además calcula una etiqueta de autenticación sobre el texto cifrado y sobre los datos asociados. Al descifrar, la etiqueta se recalcula y se compara. Si no coincide, la librería no devuelve el texto: lanza un error. No devuelve el texto alterado, ni el texto a medias: no devuelve nada. Esa es la diferencia entre cifrar y proteger.
Los datos asociados del ejemplo —el número de cuenta— no van cifrados, pero sí entran en la etiqueta. Sirven para amarrar el mensaje a su contexto: un texto cifrado válido para la cuenta 4471 no se puede reutilizar en otra cuenta, porque la etiqueta ya no cuadra.
# pip install cryptography import os from cryptography.hazmat.primitives.ciphers.aead import AESGCM llave = AESGCM.generate_key(bit_length=256) nonce = os.urandom(12) # 96 bits, distinto cada vez c = AESGCM(llave).encrypt(nonce, b"VALOR=0000100000", b"cuenta=4471") alterado = bytearray(c); alterado[6] ^= 0x09 # el ataque de arriba AESGCM(llave).decrypt(nonce, bytes(alterado), b"cuenta=4471") # → InvalidTag
Esta es la línea real del programador de tareas de Coopaburrá: la que produce el respaldo diario que viaja a Sabaneta los viernes. Tiene tres problemas distintos y solo uno es evidente.
openssl enc -aes-256-cbc -in respaldo_diario.sql -out respaldo_diario.enc \ -k $(cat /opt/backup/llave.txt)
Las herramientas ofrecen dos formas de darles una llave y no son lo mismo, aunque se parezcan en la línea de comandos. Escriba una contraseña y compare.
Recibe la llave en hexadecimal: exactamente los bits que se van a usar. Es lo correcto cuando ya se tiene una llave generada al azar.
Recibe una contraseña de texto y la pasa por una función de derivación. La calidad depende de esa función y de sus parámetros.
Usa la minúscula con el contenido de un archivo. Trata una llave que ya era aleatoria como si fuera una contraseña.
Escriban los tres problemas. Este panel no los corrige: es para ordenar el trabajo antes de pasarlo al informe.
No son pistas de la respuesta, son las preguntas que la respuesta tiene que contestar. Sobre la llave: ¿quién puede leerla hoy, y en cuántos sitios distintos está? Cuenten los sitios; son más de uno. Sobre la derivación: si la llave ya venía de un generador aleatorio, ¿qué le aporta pasarla por una función pensada para contraseñas humanas, y qué le quita? Sobre el modo: si alguien modifica el archivo de respaldo mientras viaja en el carro del mensajero, ¿en qué momento lo notaría Coopaburrá, y cómo?
Y para la línea corregida, tres preguntas más: ¿de dónde sale la llave?, ¿cómo se la entregan a la herramienta sin que aparezca en la lista de procesos?, y ¿qué tendría que pasar al restaurar para que se sepa que el archivo llegó íntegro?
Seis situaciones. En una de ellas la respuesta correcta es que ningún modo sirve, porque el problema no es el modo.
Una página por equipo al final del bloque. Se evalúa el análisis, no el resultado.