Parte: 2 — Criptografía aplicada · Fuente: Real-World Cryptography (Wong) y OWASP Password Storage Cheat Sheet ⏱️ Duración estimada: 100 min · Nivel: Intermedio
Aprender a almacenar contraseñas de forma resistente a cracking usando funciones de derivación de clave lentas y con memoria intensiva (bcrypt, scrypt, Argon2), y por qué usar SHA-256 o MD5 para contraseñas es un error grave. El alumno entenderá el papel del salt, el pepper, el factor de coste y estimará el coste real de un ataque con hashcat en un entorno de laboratorio.
⚠️ Nota ética: el cracking de hashes se practica solo sobre contraseñas y volcados propios de laboratorio. Atacar credenciales ajenas sin autorización es ilegal.
Al finalizar, el alumno podrá:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | Por qué no SHA-256 para contraseñas | Demasiado rápido de crackear |
| 2 | Salt (por usuario) | Rompe rainbow tables |
| 3 | Pepper (secreto global) | Defensa adicional |
| 4 | bcrypt y factor de coste | Estándar histórico |
| 5 | scrypt y Argon2 (memory-hard) | Resisten GPU/ASIC |
| 6 | Verificación en tiempo constante | Evita timing |
| 7 | Ataques con hashcat (lab) | Medir la resistencia real |
pip install argon2-cffi bcrypt
# hashcat solo para laboratorio propio
hashcat --version 2>/dev/null || echo "instala hashcat para el lab de auditoría"
Usa únicamente hashes y contraseñas de prueba generados por ti.
python
from argon2 import PasswordHasher
ph = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=4)
h = ph.hash("contraseña-de-prueba")
print(h) # incluye salt y parámetros
ph.verify(h, "contraseña-de-prueba") # True o excepción
python
import bcrypt
h = bcrypt.hashpw(b"prueba", bcrypt.gensalt(rounds=12))
print(bcrypt.checkpw(b"prueba", h))
Compara la lentitud. Mide el tiempo de hashear con SHA-256 vs Argon2id; observa que Argon2 es órdenes de magnitud más lento (por diseño).
Ataque de diccionario en laboratorio. Genera unos pocos hashes bcrypt de contraseñas débiles propias y córrelos con hashcat contra una wordlist pequeña; mide cuántas caen y en cuánto tiempo. Repite subiendo el factor de coste y observa el encarecimiento del ataque.
Calibra parámetros. Ajusta time_cost/memory_cost para que un hash tarde ~250-500 ms en tu hardware de producción objetivo.
Implementa un módulo de registro/login que almacene contraseñas con Argon2id (salt automático, parámetros calibrados) y verifique en tiempo constante, más un migrador que rehashee credenciales antiguas al iniciar sesión. Criterio de aceptación: dos usuarios con la misma contraseña tienen hashes distintos, la verificación acepta la correcta y rechaza la incorrecta, y las cuentas legacy se actualizan transparentemente.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| Contraseñas con SHA-256/MD5 | Demasiado rápidas; migra a Argon2id/bcrypt/scrypt |
| Salt reutilizado o global | Debilita; usa salt aleatorio por usuario |
| Factor de coste demasiado bajo | Fácil de crackear; calíbralo a cientos de ms |
Comparar hashes con == |
Timing; usa la verificación de la librería |
| bcrypt con contraseña >72 bytes | Se trunca; considera pre-hash o Argon2 |
❓ ¿Cuál elijo: bcrypt, scrypt o Argon2? Argon2id por defecto en diseños nuevos. bcrypt sigue siendo aceptable; scrypt es válido donde ya se usa.
❓ ¿El salt debe ser secreto? No; el salt puede ser público (se guarda con el hash). Lo secreto es el pepper.
❓ ¿Puedo "cifrar" contraseñas en vez de hashearlas? No; hashea con una KDF. Cifrar implica poder descifrar, un riesgo innecesario para autenticación.
Clase 056 — TLS/SSL en profundidad