Un sitio bien hecho no sabe tu contraseña. No es que no quiera: es que no puede.
Suena a truco, porque cada vez que la escribes el sistema te deja pasar, y para dejarte pasar tiene que comprobar algo. Pero comprobar no es saber. El servidor guarda una huella calculada a partir de tu contraseña; cuando escribes, vuelve a calcular la huella y compara. Si coinciden, adelante. En ningún momento hace falta que la contraseña esté escrita en ningún sitio.
De ahí sale la señal más clara para distinguir un servicio serio de uno que no lo es: si al olvidarla te la envían por correo, la tenían guardada. Y lo que está guardado acaba, antes o después, en manos de alguien más.
1979 la idea de no guardarlas — y la de hacerlo despacio
En 1979, Robert Morris y Ken Thompson publicaron en Communications of the ACM «Password Security: A Case History», contando lo que habían hecho en Unix. Es un relato de lo aprendido, y en él quedan asentadas dos ideas que hoy damos por evidentes.
La primera no la inventaron ellos —guardar el hash en lugar de la contraseña ya se hacía antes—, pero la explicaron mejor que nadie: no guardar la contraseña, guardar su hash. Una función que convierte tu contraseña en un valor de aspecto arbitrario y que no se puede desandar: del hash no se vuelve a la contraseña.
La segunda sí es suya: la sal. Un valor aleatorio distinto para cada usuario, que se mezcla con la contraseña antes de calcular el hash. Sin sal, dos personas con la misma contraseña tienen el mismo hash —el fichero robado se convierte en un juego de buscar repetidos— y, peor, alguien puede precalcular una tabla gigante una vez y usarla contra todas las bases de datos del mundo. La sal no hace tu contraseña más difícil de adivinar: hace que adivinarla no sirva para nadie más.
Pero en ese mismo artículo hay una tercera idea, mucho menos citada, y es la que importa aquí: hicieron la función deliberadamente lenta. No por descuido. A propósito. Encriptar una contraseña costaba mucho más de lo que técnicamente hacía falta, porque a quien entra una vez cada mañana le da igual, y a quien prueba millones de candidatas no.
Ahí está todo el asunto en una frase de hace casi cincuenta años.
Por qué la lentitud es la única defensa honesta
Casi todas las defensas informáticas son asimétricas: cuestan poco al que se defiende y mucho al que ataca. Cifrar es barato; descifrar sin la clave es inviable. El defensor juega con ventaja estructural.
El almacenamiento de contraseñas no. Aquí defensor y atacante ejecutan exactamente la misma función. Tú calculas el hash para comprobar que has acertado; él lo calcula para comprobar si ha acertado. Es la única carrera de la seguridad donde los dos corren con las mismas piernas.
Cuando no puedes correr más que tu rival, solo queda una jugada: encarecer la pista para los dos. Tú pagas ese coste una vez por inicio de sesión. Él, una vez por intento. Como necesita órdenes de magnitud más intentos que tú, la misma factura os afecta de forma incomparable. Eso es lo que hace un hash de contraseñas.
Por eso las funciones rápidas y buenísimas para otras cosas —SHA-256, por ejemplo— son una elección pésima aquí. Son rápidas. Rápido es exactamente lo que no queremos.
1999 bcrypt, y el coste como pieza ajustable
El problema de una función lenta es que el hardware no se queda quieto. Lo que en 1979 era lento, después es instantáneo. Una defensa calibrada contra los ordenadores de una década envejece sola, sin que nadie la toque.
En 1999, Niels Provos y David Mazières presentaron bcrypt en la USENIX Annual Technical Conference, con un título que ya lo dice todo: A Future-Adaptable Password Scheme.
La idea: que el coste no esté en la función, sino en un parámetro. bcrypt lleva un factor de coste que decides tú y que se guarda junto al hash. Si el hardware se vuelve mucho más rápido, subes el número y las contraseñas nuevas vuelven a costar lo que deben, sin cambiar de algoritmo.
Es un diseño que asume su propia obsolescencia y se prepara para ella. Hay poquísimo software que haga eso.
2009 scrypt, y el descubrimiento de que el tiempo no basta
bcrypt encarece el tiempo de cálculo, y funcionó. Hasta que el atacante dejó de usar el mismo tipo de máquina que el defensor.
Un servidor tiene unos pocos núcleos rápidos y de propósito general. Una GPU tiene una barbaridad de núcleos pequeños haciendo lo mismo en paralelo, y un ASIC va más lejos: silicio fabricado para ejecutar una sola operación. Si tu defensa consiste en «esta operación cuesta X», alguien puede construir hardware que haga muchas X a la vez. El defensor sigue con su servidor.
En 2009, Colin Percival presentó scrypt con otro argumento: Stronger Key Derivation via Sequential Memory-Hard Functions. Si el coste está solo en el cálculo, se paraleliza. Pero la memoria no se regala. Obliga a la función a usar mucha RAM y a recorrerla de forma que no se pueda esquivar, y de pronto el atacante no puede multiplicar núcleos: cada núcleo necesitaría su propia memoria. Y los núcleos de una GPU tienen mucha potencia y muy poca RAM para cada uno.
Percival no encareció la operación. Encareció el hardware necesario para repetirla en masa. Es un cambio de nivel: se ataca al presupuesto del atacante, no a su reloj.
2015 Argon2, y el final del debate
Que existieran varias opciones razonables no ayudaba a nadie a elegir. Así que la comunidad criptográfica hizo lo que suele hacer cuando quiere zanjar algo: un concurso público. La Password Hashing Competition recibió candidatos, los sometió a análisis abierto durante años y en 2015 proclamó ganador a Argon2.
Argon2 hereda las dos lecciones: coste en tiempo y coste en memoria, ambos ajustables por separado, más el número de hilos. No es magia. Es la síntesis ordenada de 1979, 1999 y 2009, revisada por gente cuyo trabajo consistía en intentar romperla.
Qué significa esto para ti
Casi nada de esto está en tus manos, y conviene decirlo: el hash lo elige el sitio, no tú. Puedes tener la mejor contraseña del mundo y que la guarden en texto plano en un Excel.
Pero el otro lado de la ecuación sí depende de ti. Todo este edificio —la sal, el coste, la memoria— sirve para encarecer cada intento del atacante. Lo que decide cuántos intentos necesita es tu contraseña. Si está en un diccionario, ninguna función lenta te salva: caerá entre los primeros. Si es larga y no se parece a nada, ese precio por intento se multiplica por un número de intentos que no cabe en el tiempo disponible.
Por eso nuestro generador mide bits de entropía y no porcentajes, y por eso el comprobador busca tu contraseña en diccionarios antes que contar símbolos. Ellos ponen el precio por intento; tú pones el número de intentos. Ninguna de las dos mitades funciona sin la otra.
Y sí: sigue siendo la misma pregunta de siempre. Solo que ahora, del otro lado, alguien intenta responderla muchas veces por segundo, y llevamos desde 1979 intentando que cada una de esas veces le cueste dinero.
Fuentes: R. Morris y K. Thompson, «Password Security: A Case History», Communications of the ACM, 1979 · N. Provos y D. Mazières, «A Future-Adaptable Password Scheme», USENIX Annual Technical Conference, 1999 (bcrypt) · C. Percival, «Stronger Key Derivation via Sequential Memory-Hard Functions», 2009 (scrypt) · Password Hashing Competition, ganador Argon2, 2015.