La primera vez que un usuario inicia sesión en nuestra aplicación, obtenemos una clave AES de su contraseña utilizando PBKDF2. La clave AES se guarda solo en la RAM y se utiliza para cifrar y envolver otras claves y datos durante la sesión.
Cuando finaliza la sesión actual, descartamos la clave pero conservamos los datos cifrados y la configuración de derivación (conteo de sal / iteración / etc.) para la próxima vez.
En los inicios de sesión posteriores, volvemos a derivar la clave según la contraseña y la configuración, pero queremos comprobar si la clave (contraseña) es válida (con un nivel de confianza razonable) antes de intentar usarla.
No queremos también calcular un hash sobre la contraseña porque la derivación de la clave ya es (deliberadamente) de larga ejecución y no queremos que ese proceso sea más largo con otro algoritmo de hash de larga duración.
He visto algunas soluciones a esto, pero me pregunto si hay algún estándar que deba seguirse. Lo que he visto hasta ahora:
- En Cryptography Engineering, Schneier et al. sugieren tomar datos de hash de la iteración n-1a de su función de derivación y hashing con la sal, contraseña, etc. para formar un código de verificación. Puede almacenar esto y calcular el mismo código para el candidato mientras deriva la clave. Si no coinciden, rechazas. Desventaja: Si utiliza bibliotecas criptográficas de terceros, probablemente no será posible obtener acceso al estado interno de PBKDF2 para hacer esto.
- Calcula algo como
SHA256(key+salt+password)
y almacena eso. Calcule para el candidato y rechace si no coinciden. -
Use la clave para cifrar algo con un patrón o sufijo conocido, y guárdelo. por ejemplo
E(key, <32 bytes random data> + <32 bytes of 0>'.
Almacene esto, descifre utilizando la clave candidata y verifique si el sufijo coincide. El número de 0 que elija determina la probabilidad de un falso positivo.
El último parece simple y efectivo, pero estoy buscando un consejo claro de un experto / autoridad al respecto.