Toolbit
Guías

MD5, SHA-256 y bcrypt: qué función hash usar para cada cosa

Integridad, autenticación de mensajes y contraseñas necesitan herramientas distintas: cómo cayeron MD5 y SHA-1, por qué HMAC evita la extensión de longitud y por qué las contraseñas van con Argon2id o bcrypt.

Por Javier VallejoPublicado el 7 min de lectura

Tres tareas distintas, tres herramientas distintas

"Hashear" se usa para describir tres trabajos que no tienen nada que ver entre sí, y buena parte de los errores de seguridad con hashes vienen de usar la herramienta de uno para hacer otro:

  1. Verificar integridad: comprobar que un archivo o un mensaje no cambió. Herramienta: un hash rápido y resistente a colisiones, como SHA-256.
  2. Autenticar un mensaje: comprobar que un mensaje viene de quien tiene una clave secreta y no fue alterado. Herramienta: HMAC.
  3. Guardar contraseñas: poder verificar una contraseña sin almacenarla. Herramienta: una función deliberadamente lenta, con sal, como Argon2id o bcrypt.

Esta guía explica qué garantiza cada una, cómo cayeron MD5 y SHA-1, y qué usar en cada caso. Para calcular hashes o HMAC de un texto o un archivo, el generador de hash trabaja en el navegador.

Qué garantiza un hash criptográfico

Una función hash criptográfica tiene que resistir tres tipos de ataque, de menor a mayor dificultad para quien la diseña:

  • Preimagen: dado un hash, encontrar alguna entrada que lo produzca.
  • Segunda preimagen: dada una entrada concreta, encontrar otra con el mismo hash.
  • Colisión: encontrar dos entradas cualesquiera con el mismo hash.

La colisión es la más fácil de lograr por una razón estadística, la paradoja del cumpleaños: con un hash de n bits, basta con probar unas 2^(n/2) entradas para tener una probabilidad alta de encontrar dos que coincidan. Por eso la seguridad frente a colisiones es la mitad del tamaño del hash:

AlgoritmoTamañoSeguridad teórica frente a colisionesSituación real
MD5128 bits2⁶⁴Colisiones en segundos con un equipo común
SHA-1160 bits2⁸⁰Colisiones demostradas (2017) y con prefijo elegido (2020)
SHA-256256 bits2¹²⁸Sin ataques prácticos
SHA-512512 bits2²⁵⁶Sin ataques prácticos
SHA3-256256 bits2¹²⁸Sin ataques prácticos; diseño distinto (Keccak)

Cómo cayeron MD5 y SHA-1

MD5 fue diseñado por Ron Rivest en 1991. En 1996 aparecieron las primeras debilidades teóricas, y en 2004 el equipo de Xiaoyun Wang publicó colisiones reales. A partir de ahí los ataques mejoraron rápido: en 2008, un grupo de investigadores usó una colisión de MD5 para crear un certificado de autoridad de certificación falso que los navegadores aceptaban como válido. En 2012, el malware de espionaje Flame usó una técnica similar para falsificar una firma de Microsoft y distribuirse a través de Windows Update.

SHA-1 resistió más. En 2005 se publicó un ataque teórico, y en 2017 Google y el instituto CWI de Ámsterdam presentaron SHAttered: dos archivos PDF distintos con el mismo hash SHA-1, obtenidos tras unos 9 trillones (9 × 10¹⁸) de cálculos de SHA-1. Ese mismo año los navegadores dejaron de aceptar certificados firmados con SHA-1. En 2020 llegó la colisión con prefijo elegido, que permite fabricar colisiones a partir de dos documentos cualesquiera, el tipo de ataque más peligroso en la práctica. Git, que usaba SHA-1 para identificar todo su contenido, incorporó detección de colisiones y agregó soporte para repositorios con SHA-256.

La lección no es que MD5 y SHA-1 den resultados "incorrectos": siguen detectando perfectamente un archivo dañado por accidente. Lo que perdieron es la garantía frente a alguien que elige el contenido a propósito.

Integridad: checksums de descargas

Para verificar que un archivo descargado es idéntico al publicado, se compara su hash con el que publica el sitio. Con SHA-256, si coinciden, el archivo es el mismo bit a bit. Con MD5, si coinciden, el archivo es el mismo salvo que alguien haya preparado deliberadamente una versión distinta con el mismo hash, algo que hoy es factible.

Dos aclaraciones prácticas. Primero, un CRC32 (el que usan los archivos ZIP o Ethernet) detecta errores de transmisión pero no es criptográfico: fabricar una colisión es trivial. Segundo, el checksum solo vale tanto como el canal por el que se obtuvo: si el atacante controla el servidor, cambia el archivo y el checksum juntos. Por eso las distribuciones de Linux firman su archivo SHA256SUMS con GPG.

Autenticar mensajes: por qué HMAC y no hash(clave + mensaje)

Supongamos una API que firma cada petición calculando SHA-256(clave_secreta + mensaje) y la envía junto al mensaje. Parece seguro: sin la clave, nadie puede calcular la firma. Pero MD5, SHA-1, SHA-256 y SHA-512 comparten una construcción interna (Merkle–Damgård) que permite un ataque de extensión de longitud: quien conoce el hash de clave + mensaje y el largo de la clave puede calcular el hash de clave + mensaje + relleno + datos_agregados sin conocer la clave. En 2009, la API de Flickr fue vulnerable exactamente a esto: un atacante podía agregar parámetros a una petición firmada y producir una firma válida.

La solución estándar es HMAC (RFC 2104), que aplica el hash dos veces con la clave combinada de una forma que neutraliza el ataque. HMAC-SHA256 es lo que usan los webhooks de la mayoría de las plataformas, la firma de JWT con HS256 y la autenticación de muchas APIs. Un ejemplo de prueba del RFC 4231: con la clave Jefe y el mensaje what do ya want for nothing?, el HMAC-SHA256 es 5bdcc146bf60754e…64ec3843. Puede comprobarse en el generador escribiendo la clave en el campo HMAC.

Al verificar un HMAC recibido, la comparación debe hacerse en tiempo constante (crypto.timingSafeEqual en Node.js, hmac.compare_digest en Python). Una comparación normal termina en el primer carácter distinto, y medir esa diferencia de tiempo permite adivinar la firma de a un carácter.

Contraseñas: por qué un hash rápido es un error

Para guardar contraseñas no hay que guardarlas, sino algo que permita verificarlas: al iniciar sesión se calcula lo mismo con la contraseña ingresada y se compara. La tentación es usar SHA-256(contraseña). El problema es la velocidad:

FunciónOrden de magnitud en una GPU moderna
MD5más de 100.000 millones de intentos por segundo
SHA-256decenas de miles de millones por segundo
bcrypt (costo 10–12)miles por segundo
Argon2id (19 MiB de memoria)comparable a bcrypt, y además exige 19 MiB de memoria por intento

Si se filtra una base de datos con hashes SHA-256, un atacante prueba diccionarios de miles de millones de contraseñas conocidas en segundos. Las funciones diseñadas para contraseñas agregan tres defensas:

  • Sal: un valor aleatorio distinto por usuario, guardado junto al hash. Hace que dos usuarios con la misma contraseña tengan hashes distintos e inutiliza las tablas precalculadas (rainbow tables).
  • Costo ajustable: se pueden configurar para que cada cálculo tarde, por ejemplo, 100 ms en el servidor. Para el usuario es imperceptible; para el atacante significa millones de veces menos intentos.
  • Uso de memoria (Argon2id, scrypt): obligan a usar decenas de megas por intento, lo que limita cuántos cálculos puede hacer en paralelo una GPU.

Las recomendaciones actuales de OWASP, en orden de preferencia:

FunciónParámetros mínimos recomendados
Argon2id19 MiB de memoria, 2 iteraciones, paralelismo 1
scryptN = 2¹⁷, r = 8, p = 1
bcryptcosto 10 o más; tiene un límite de 72 bytes de contraseña
PBKDF2-HMAC-SHA256600.000 iteraciones (cuando se requiere cumplir FIPS-140)

Cuánto resiste una contraseña depende también de su entropía, que se explica en Cómo crear contraseñas seguras: la entropía explicada. Una función lenta convierte una contraseña de 40 bits de "minutos" en "años", pero no salva a 123456, que está primera en cualquier diccionario.

Qué usar para cada cosa

TareaUsarEvitar
Verificar una descarga o un archivoSHA-256MD5 y SHA-1 si hay posibilidad de manipulación
Detectar duplicados o cambios accidentalesSHA-256; MD5 aceptable sin adversarioCRC32 si importa la seguridad
Firmar mensajes con una clave compartidaHMAC-SHA256hash(clave + mensaje)
Guardar contraseñasArgon2id, scrypt o bcryptCualquier hash rápido, con o sin sal
Firmas digitales y certificadosSHA-256 o superiorMD5 y SHA-1
Identificar contenido (Git, caches)SHA-256SHA-1 en sistemas nuevos

Resumen

Un hash criptográfico resume cualquier entrada en una huella de tamaño fijo, y su valor depende de que nadie pueda fabricar dos entradas con la misma huella: MD5 y SHA-1 perdieron esa propiedad, SHA-256 la conserva. Para autenticar mensajes, el hash solo no es suficiente y se usa HMAC. Para contraseñas, la velocidad que hace útil a SHA-256 se vuelve su peor defecto, y la respuesta son funciones lentas con sal: Argon2id, scrypt o bcrypt.

Herramientas usadas en esta guía

Guías relacionadas