Parte: 2 — Criptografía aplicada · Fuente: Cryptography Engineering (Ferguson/Schneier/Kohno) y Real-World Cryptography (Wong) ⏱️ Duración estimada: 120 min · Nivel: Avanzado
Cerrar la parte con la lección que unifica todo lo anterior: la criptografía se rompe en la implementación, no en las matemáticas. El alumno recopilará el catálogo de errores criptográficos comunes (los del OWASP A02 "Cryptographic Failures"), aprenderá a auditarlos y evitarlos, y consolidará las reglas de oro: usa librerías auditadas, AEAD por defecto, nonces únicos, aleatoriedad segura, comparación en tiempo constante y no inventes tu propia cripto.
Al finalizar, el alumno podrá:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | OWASP A02 Cryptographic Failures | Marco de referencia |
| 2 | Primitivas obsoletas (DES, MD5, ECB, RC4) | Erradicarlas |
| 3 | Nonces/IV mal gestionados | Fuente recurrente de brechas |
| 4 | Aleatoriedad y claves hardcodeadas | Fallos silenciosos |
| 5 | Falta de autenticación (sin AEAD/MAC) | Manipulación |
| 6 | Comparaciones no constantes | Timing |
| 7 | Reglas de oro y "criptoagilidad" | Diseño robusto y migrable |
Las vulnerabilidades criptográficas reales casi nunca vienen de romper AES o RSA. Vienen de usarlos mal, y por eso OWASP colocó Cryptographic Failures en el segundo puesto de su Top 10. Esta clase recoge los patrones de fallo que se repiten y los convierte en una lista de comprobación aplicable.
El principio rector es incómodo para el ego pero salva sistemas: no diseñes ni
implementes primitivas propias. Usa bibliotecas maduras y, mejor todavía, bibliotecas
de alto nivel con pocas decisiones —libsodium, Tink, cryptography de Python en su capa
recipes, o la age para ficheros— que no te dejan elegir el modo, ni el relleno, ni el
IV, porque cada elección es una oportunidad de fallar. La API correcta de criptografía es
aquella en la que el camino fácil es el seguro.
Primitivas obsoletas. DES y 3DES por tamaño de bloque y de clave; MD5 y SHA-1 por colisiones prácticas (clase 051); RC4 por sus sesgos (clase 048); ECB por filtrar la estructura (clase 047). Todas siguen apareciendo en sistemas en producción, casi siempre por copiar un ejemplo antiguo de Internet.
IV y nonces mal gestionados. Un IV fijo o predecible en CBC; un nonce repetido en GCM o ChaCha20, que además de romper la confidencialidad permite falsificar tags (clases 048 y 059); contadores que se reinician al restaurar una máquina desde snapshot.
Aleatoriedad y claves. Usar el PRNG estadístico del lenguaje en vez del CSPRNG (clase 058); derivar una clave de algo con poca entropía; y sobre todo claves incrustadas en el código, que la clase 063 desmonta.
Falta de autenticación. Cifrar sin AEAD ni MAC, dejando el mensaje maleable; o componer mal, con MAC-then-encrypt en lugar de encrypt-then-MAC (clase 052).
Fugas por tiempo. Comparar etiquetas, tokens o contraseñas con ==, entregando un
oráculo byte a byte (clase 060).
Validación insuficiente. Aceptar cualquier certificado por comodidad —el
verify=False que aparece "provisionalmente" y se queda para siempre— destruye TLS por
completo, porque anula la autenticación que impide el MitM de la clase 040. Y en JWT, el
clásico aceptar el algoritmo que declara el propio token, incluido none.
La historia de esta parte —DES, MD5, SHA-1, RC4, y ahora RSA y ECC ante la amenaza cuántica— demuestra que toda primitiva acaba caducando. Un sistema bien diseñado lo asume: no incrusta el algoritmo en la lógica, sino que versiona sus datos cifrados guardando junto a ellos qué algoritmo y qué parámetros se usaron. Eso permite descifrar lo antiguo mientras se escribe lo nuevo con el algoritmo actual, y migrar sin una parada. Aplicado a contraseñas, es lo que permite recalcular el hash con parámetros más fuertes en el siguiente inicio de sesión de cada usuario.
Cierra la parte una comprobación honesta: revisar código real —el propio, o un ejemplo preparado— buscando estos patrones es el mejor ejercicio de criptografía aplicada que existe, porque enseña que la distancia entre "usa AES-256" y "es seguro" es exactamente todo lo que se ha estudiado en estas veinte clases.
==).| Término | Definición concisa |
|---|---|
| OWASP A02 | Cryptographic Failures: categoría del Top 10 |
| No inventes criptografía | Usar bibliotecas maduras en vez de implementaciones propias |
| API de alto nivel | Biblioteca que no deja elegir modo, relleno ni IV |
| libsodium / Tink / age | Bibliotecas con el camino fácil ya seguro |
| Primitiva obsoleta | DES, 3DES, MD5, SHA-1, RC4, ECB |
| IV predecible | Vector de inicialización fijo o adivinable en CBC |
| Nonce repetido | Fallo catastrófico en GCM y en cifrados de flujo |
| Clave incrustada | Credencial escrita en el código fuente |
| Cifrado sin autenticar | Deja el mensaje maleable; usar AEAD |
Comparación con == |
Fuga por timing en etiquetas y tokens |
verify=False |
Desactivar la validación de certificados; anula TLS |
JWT alg: none |
Aceptar el algoritmo que declara el propio token |
| Criptoagilidad | Poder cambiar de algoritmo sin rehacer el sistema |
| Versionado del cifrado | Guardar algoritmo y parámetros junto al dato |
| Rehash en login | Recalcular el hash de contraseña con parámetros más fuertes |
pip install cryptography bandit
which gitleaks semgrep 2>/dev/null || echo "opcional: escáneres estáticos"
Auditoría sobre código propio o autorizado.
python
import hashlib, random
KEY = b"1234567890123456" # clave hardcodeada
def cifrar(m):
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
iv = b"\x00" * 16 # IV fijo
c = Cipher(algorithms.AES(KEY), modes.ECB()) # ECB, sin auth
return c.encryptor().update(m)
def token():
return str(random.random()) # PRNG no seguro
def check(a, b):
return a == b # comparación no constante
def pwd_hash(p):
return hashlib.md5(p).hexdigest() # MD5 para contraseña
Identifica: clave en código, ECB, sin autenticación, IV fijo, PRNG inseguro, comparación no constante y MD5 para contraseñas.
Reescríbelo de forma segura: clave desde KMS/Vault o variable de entorno, AES-GCM (AEAD) con nonce del CSPRNG, secrets para tokens, hmac.compare_digest, Argon2id para contraseñas.
Escáneres estáticos. Corre bandit sobre el archivo y gitleaks/semgrep para detectar la clave hardcodeada; compara hallazgos con tu revisión manual.
Checklist de criptoagilidad. Verifica que tu diseño permite cambiar algoritmo/clave por configuración y versiona el formato de los mensajes cifrados.
Revisión de dependencias. Comprueba que usas librerías mantenidas (cryptography, libsodium) y no implementaciones caseras de primitivas.
bandit y explica cada advertencia relevante.Toma un módulo con al menos cinco fallos criptográficos (el del laboratorio u otro que construyas) y entrégalo corregido: AEAD, nonces del CSPRNG, claves fuera del código, Argon2id para contraseñas y comparaciones en tiempo constante, con versión de formato para criptoagilidad. Criterio de aceptación: bandit no reporta fallos cripto de severidad media/alta en el módulo corregido, los tests de cifrado/descifrado y de autenticación pasan, y ninguna clave o secreto aparece en el código.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| Clave/secreto en el repositorio | Muévelo a KMS/Vault/variables; escanea el histórico |
| ECB o cifrado sin autenticar | Usa AEAD (GCM/ChaCha20-Poly1305) |
| IV/nonce fijo o reutilizado | Genera con CSPRNG; garantiza unicidad |
| MD5/SHA-1/DES/RC4 en uso | Sustituye por SHA-256/3, AES-GCM, Argon2id |
Comparaciones con == de secretos |
Usa compare_digest/verificadores de la librería |
| "Cripto propia" sin auditar | Usa librerías estándar bien mantenidas |
❓ ¿Cuál es la regla más importante? No inventes tu propia cripto: usa primitivas y librerías auditadas con defaults seguros (AEAD, KDFs lentas, curvas modernas).
❓ ¿Cómo detecto estos fallos a escala? Combina revisión manual con escáneres (bandit, semgrep, gitleaks) integrados en CI, y auditorías periódicas de TLS y almacenamiento.
❓ ¿Qué es la criptoagilidad y por qué me importa ahora? Poder cambiar algoritmos y claves sin rediseñar; será imprescindible en la migración post-cuántica y ante cualquier primitiva que se debilite.
Clase 064 — Esteganografía y ocultación de datos