Cifrar contraseña en archivos de configuración en Java
El cifrado es el proceso de transformar información en texto plano en una forma ilegible utilizando un algoritmo de cifrado combinado con un parámetro llamado clave de cifrado
. El formato ilegible se conoce a menudo como formato de texto cifrado
. Solo aquellos que poseen la clave de descifrado
pueden descifrar los datos y recuperar el texto sin formato original.
Podemos dividir el problema de cifrar las contraseñas en los archivos de configuración en dos subtareas siguientes.
- Cifre la contraseña de texto sin formato que se encuentra en el archivo.
- Descifre la contraseña encriptada leída del archivo.
Primero hagamos un archivo de configuración llamado archivo config.properties
en la ruta src/conf/
.
password = TestPassword123
Ahora, para leer el archivo de configuración, cree una instancia de la clase Properties
. Podemos crear una instancia de la clase FileInputStream
usando su constructor. Toma la ruta del archivo de configuración como entrada. Ahora se usa una instancia de la clase de propiedades para cargar las propiedades. Utilice el método load
para cargar el archivo de propiedades en la clase, y esto toma la instancia InputStreamReader
como parámetro. Lanza IllegalArgumentException
si este flujo de entrada contiene una secuencia de escape Unicode mal formada y IOException
si ocurrió un error al leer del flujo de entrada.
Una vez que las propiedades se hayan cargado correctamente, utilice el método getProperty()
para buscar la propiedad con la clave especificada en la lista de propiedades. El método devuelve null
si no puede encontrar las propiedades. Coloque una verificación externa para manejar tal situación y arroje IllegalArgumentException
si una contraseña se encuentra nula en el archivo.
salt
se crea con cualquier cadena aleatoria para agregar a la cadena de contraseña.
createSecretKey
es un método definido por el usuario que devuelve la clave SecretKeySpec
, y el uso de la clave es para cifrar y descifrar la contraseña. Los métodos encrypt
y decrypt
son métodos estáticos
definidos por el uso que se han proporcionado en la clase Encryption
.
A continuación se muestra el código de muestra que demuestra lo mismo.
package fileDataEncryption;
import static fileDataEncryption.Encryption.*;
import java.io.FileInputStream;
import java.util.Properties;
import javax.crypto.spec.SecretKeySpec;
public class ConfigFileEncryption {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
FileInputStream inputStream = new FileInputStream("src/conf/config.properties");
properties.load(inputStream);
String password = properties.getProperty("password");
if (password == null) {
throw new IllegalArgumentException("No such parameter present in config file");
}
byte[] salt = new String("12345678").getBytes();
int iterationCount = 40000;
int keyLength = 128;
SecretKeySpec key = createSecretKey(password.toCharArray(), salt, iterationCount, keyLength);
String originalPassword = password;
System.out.println("Original password: " + originalPassword);
String encryptedPassword = encrypt(originalPassword, key);
System.out.println("Encrypted password: " + encryptedPassword);
String decryptedPassword = decrypt(encryptedPassword, key);
System.out.println("Decrypted password: " + decryptedPassword);
}
}
A continuación se ofrece una descripción detallada de los métodos definidos por el usuario en la clase Encryption
.
createSecretKey
es una función que toma parámetros comopassword
,salt
,iterationCount
ykeyLength
.Contraseña
es la contraseña real en el archivo de configuración. En criptografía, unsalt
son datos aleatorios que usamos como una entrada adicional que codifica datos, una contraseña o una frase de contraseña. El uso desalts
es para salvaguardar las contraseñas almacenadas. Usamos la variableiterationCount
como el número de iteraciones que debe tomar un algoritmo. Disminuir el valor de las velocidades variables durante el tiempo de inicio y, por lo tanto, es útil durante las pruebas, pero también lo hace más fácil para los atacantes de fuerza bruta. La variablekeyLength
es la longitud de la clave que finalmente necesitamos derivar. Lanza la excepción lanzada por los métodos que la usaron.- El método
getInstance
recorre la lista de proveedores de seguridad registrados, comenzando por el proveedor más preferido. Toma el nombre estándar del algoritmo de clave secreta solicitado y devuelve el nuevo objetoSecretKeyFactory
. LanzaNullPointerException
si el algoritmo especificado es nulo yNoSuchAlgorithmException
si ningún proveedor admite una implementación deSecretKeyFactorySpi
para el algoritmo especificado. PBEKeySpec
es un constructor de clases que toma una contraseña, sal, conteo de iteraciones y longitud de clave a derivar para generarPBEKey
de cifrados PBE de tamaño de clave variable. LanzaNullPointerException
sisalt
esnull
yIllegalArgumentException
si salt está vacío.generateSecret
genera un objetoSecretKey
a partir de la especificación de clave proporcionada o del material de clave. Toma la especificación de la clave secreta. LanzaInvalidKeySpecException
si la especificación dada es inapropiada para que esta fábrica de claves secretas produzca un valor de clave clasificada.
Detalles del método encrypt
en la clase Encryption
.
- El método
encrypt
toma dos parámetros, los datos a encriptar y la clave. Este método arroja excepciones lanzadas desde métodos secundarios en él. - El método
getInstance
recorre la lista de proveedores de seguridad registrados, comenzando por el proveedor más preferido. Toma el nombre de la transformación, es decir AES / CBC / PKCS5Padding. LanzaNoSuchAlgorithmException
si un cambio es nulo, vacío, en un formato no válido yNoSuchPaddingException
si el cambio contiene un esquema de relleno que no está disponible. - El método
init
inicializa elCipher
para una de las siguientes cuatro operaciones: cifrado, descifrado, encapsulado de claves o desencriptado de claves, según el valor del modo de operación.ENCRYPT_MODE
en nuestro caso. El método arrojaUnsupportedOperationException
si el modo de operación no es válido yInvalidKeyException
si la clave dada es inapropiada. - El
getParameters
devuelve los parámetros utilizados con este cifrado. - El
getParameterSpec
devuelve una especificación del objeto de parámetro. El parámetroparamSpec
identifica la clase de especificación en la que deben regresar los parámetros. Por ejemplo, podría ser la claseDSAParameterSpec.class
para indicar que los parámetros deben regresar en una instancia de la claseDSAParameterSpec
. - El método
doFinal
cifra o descifra datos en un trabajo de una sola parte o finaliza una operación de varias partes. Los datos se cifran o descifran, dependiendo de cómo inicialicemos el cifrado. base64Encode
es un método privado que codifica el array de bytes especificada en una cadena utilizando el esquema de codificaciónBase64
. Las funciones utilizadas en el métododecrypt
son similares al método mencionado anteriormente. La única diferencia es que se comportan de manera diferente según elmode
especificado en la función,DECRYPT_MODE
como modo de operación.
package fileDataEncryption;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class Encryption {
public static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount,
int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength);
SecretKey keyTmp = keyFactory.generateSecret(keySpec);
return new SecretKeySpec(keyTmp.getEncoded(), "AES");
}
public static String encrypt(String dataToEncrypt, SecretKeySpec key)
throws GeneralSecurityException, UnsupportedEncodingException {
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeCipher.init(Cipher.ENCRYPT_MODE, key);
AlgorithmParameters parameters = pbeCipher.getParameters();
IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class);
byte[] cryptoText = pbeCipher.doFinal(dataToEncrypt.getBytes("UTF-8"));
byte[] iv = ivParameterSpec.getIV();
return base64Encode(iv) + ":" + base64Encode(cryptoText);
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public static String decrypt(String string, SecretKeySpec key)
throws GeneralSecurityException, IOException {
String iv = string.split(":")[0];
String property = string.split(":")[1];
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
}
private static byte[] base64Decode(String property) throws IOException {
return Base64.getDecoder().decode(property);
}
}
A continuación se muestra la salida del código escrito para cifrar y descifrar la contraseña en el archivo de configuración.
Original password: TestPassword123
Encrypted password: Hy7fbIwpyKgp0oileu+oLg==:WNRknMJz/8u8GmWlCZFPFA==
Decrypted password: TestPassword123
Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.
LinkedIn