Primero lea la respuesta de @ D.W., está llena de buenos consejos. Luego, si aún desea realizar un cifrado basado en contraseña, considere lo siguiente:
- El cifrado basado en contraseña consiste en convertir una contraseña en una clave y luego usar esa clave para el cifrado simétrico.
- Java puede hacer un cifrado basado en contraseña, es decir, hacer los dos pasos en una API optimizada, como se muestra here . Sin embargo, solo permite algunas combinaciones de mecanismos de hashing de contraseñas y algoritmos de encriptación y, en particular, se informa que no se permite eso con AES, lo cual es un problema.
- Nada le impide realizar la transformación de contraseña a clave y luego el cifrado en dos pasos separados en su código.
Tenga en cuenta que los mecanismos de cifrado de contraseñas generalmente no están cubiertos por las leyes criptográficas y las regulaciones de exportación, ya que no "ocultan" los datos. Luego recomiendo que solo incluya una implementación de bcrypt en su código, por ejemplo. jBCrypt que está escrito en Java, OpenSource con una licencia fácil y razonablemente compacto ( one archivo fuente). Necesitaría alterar el código un poco, porque esa implementación quiere usar cadenas , mientras que usted quiere bits sin procesar; por lo tanto, haz lo siguiente:
- Use el método
crypt_raw()
para convertir la contraseña y el salt en la salida de bcrypt de 192 bits.
- Hash estos 192 bits con SHA-512 (Java 6 incluye una implementación SHA-512). Esto produce 512 bits.
- Utilice estos 512 bits para el cifrado AES de sus datos, con un MAC en el resultado (por ejemplo, con HMAC / SHA -256, entonces nuevamente soportado por Java 6). Vea a continuación para más detalles.
(Normalmente prefiero bcrypt sobre PBKDF2 por las razones explicadas allí , pero PBKDF2 tampoco es malo, así que si realmente desea PBKDF2 (o lo necesita por razones de cumplimiento), entonces hágalo.
Importante: hacer el cifrado correctamente, y agregar un MAC, puede verse afectado de muchas maneras sorprendentes. Usted está muy animado a no hacerlo usted mismo. Sin embargo, el siguiente método debería ser seguro:
- Tiene 512 bits de "datos derivados de contraseñas". Divídelo en cuatro bloques de 128 bits.
- Cifre los datos con AES-128 en modo CBC. CBC requiere un vector de inicialización , que es una matriz de 16 bytes aleatorios. Utilice el primer bloque de 128 bits (de la salida SHA-512) como clave, y el segundo bloque de 128 bits como IV. Además, use el relleno PKCS # 5 (ya que sus datos de entrada pueden tener una longitud que no es un múltiplo de 16).
- Cuando se realice el cifrado, calcule HMAC / SHA-256 sobre una entrada que consiste en el IV, luego el resultado del cifrado , en ese orden; la clave para HMAC será el tercer bloque de 128 bits de la salida SHA-512.
- El "archivo cifrado" debe contener la sal para bcrypt (128 bits, 16 bytes), la salida del cifrado AES / CBC y la salida HMAC (256 bits, 32 bytes).
- Para descifrar, use el salt (del archivo cifrado) y la contraseña para volver a calcular bcrypt, luego aplique SHA-512 para obtener la clave de cifrado, IV y clave para HMAC. Verifique el valor HMAC y, si es correcto, descifre los datos.
Y, recuerda: nunca, nunca , NUNCA reutiliza el valor salt para dos instancias de cifrado (ya sea que usen la misma contraseña o no). Siempre use java.security.SecureRandom
para generar un nuevo sal aleatorio cada vez que desee cifrar un archivo.