Programa Java para cifrar contraseñas en archivos de configuración

Las contraseñas brindan la primera línea de defensa contra el acceso no autorizado a su computadora e información personal. Cuanto más segura sea su contraseña, más protegida estará su computadora de piratas informáticos y software malicioso. Cada sitio web o aplicación de software requiere una contraseña para autenticar al usuario válido. Pero al crear una contraseña, se debe tener mucho cuidado porque una persona con credenciales válidas puede obtener acceso no autorizado a sistemas informáticos e información privada. Cuanto más segura sea su contraseña, más protegida estará su computadora de piratas informáticos y software malicioso.

El cifrado es un sistema de algoritmos matemáticos que codifica los datos del usuario para que solo el destinatario previsto pueda leerlos. El cifrado mejora la seguridad de un mensaje o archivo al codificar el contenido. Es la forma más efectiva de ocultar la comunicación donde el remitente y el destinatario tienen la clave para descifrar los datos. El formato codificado e ilegible a menudo se conoce como formato de texto cifrado. 

Ilustración: configuración de Amazon EC2

AMazon EC2 Encryption And Decryption

 

Analicemos primero la necesidad de cifrado. Por lo tanto, cuando un usuario envía una solicitud de registro con nombre de usuario y contraseña, se transfiere al servidor de destino a través de Internet o mediante conexiones inalámbricas o por cable, donde se almacena en la base de datos. Dado que no hay encriptación, un pirata informático puede interceptar o robar los datos en el medio cuando se transfieren a través de la red. Además, almacenar el texto sin formato en la base de datos no es seguro en absoluto, los piratas informáticos pueden ingresar al sistema y robar las contraseñas de la base de datos.

Cifrado de contraseña en archivos de configuración

El cifrado basado en contraseña en Java nos permite cifrar y descifrar un texto mediante el uso de una contraseña. Básicamente, esto significa inicializar un javax.crypto.Cipher con el algoritmo «AES/CBC/PKCS5Padding» y obtener una clave de javax.crypto.SecretKeyFactory con el algoritmo «PBKDF2WithHmacSHA512» .

Primero creemos un archivo de configuración llamado archivo config.properties en src/config.properties y coloquemos esto dentro del archivo: 

Password = I Love KirikoChan
  1. Ahora primero cree una instancia de la clase de propiedades para que pueda leer el archivo de configuración.
  2.  Cree una instancia de la clase FileInputStream pasando la ruta del archivo de configuración como argumento.
  3.  Invoque el método .load() para cargar las propiedades del archivo de configuración en la clase, y este toma la instancia de FileInputStream como parámetro. Lanza IllegalArgumentException si este flujo de entrada contiene una secuencia de escape Unicode con formato incorrecto y IOException si se produjo un error al leer el flujo de entrada.
  4. Ahora use el método .getProperty() para buscar la propiedad con la clave especificada de la lista de propiedades en el archivo de configuración. Devuelve nulo si no puede encontrar las propiedades.
  5. Ahora cree un Salt con cualquier string aleatoria para agregar a la string de contraseña. Una sal criptográfica se compone de bits aleatorios agregados a cada instancia de contraseña antes de su hashing. Salts crea contraseñas únicas incluso en el caso de que dos usuarios elijan las mismas contraseñas. Salts nos ayuda a mitigar los ataques de tablas hash al obligar a los atacantes a volver a calcularlos utilizando Salts para cada usuario.
  6. Ahora llame a .generateSecretKey() es un método definido por el usuario que devuelve la clave SecretKeySpec . Esta clave se utiliza para cifrar y descifrar la contraseña. El método .generateSecretKey() se define en la clase secretKey definida por el usuario .

A continuación se muestra la implementación del archivo de clase Encryption.java :

Java

// Java Program to Implement Encryption Class 
  
package Exploit.org;
  
// Importing required classes 
import java.io.FileInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Properties;
import javax.crypto.spec.SecretKeySpec;
  
// Class 
public class Encryption {
  
    // Main driver method 
    public static void main(String[] args)
        throws IOException, GeneralSecurityException
    {
        Properties properties = new Properties();
        FileInputStream fileInputStream
            = new FileInputStream("src/config.properties");
        properties.load(fileInputStream);
        String password
            = properties.getProperty("Password");
  
        if (password == null) {
            throw new IllegalArgumentException(
                "Parameter is not present in configuration file");
        }
  
        byte[] salt = new String("622836429").getBytes();
        int iterationCount = 10000;
        int keyLength = 128;
        
        secretKey object = new secretKey();
        SecretKeySpec key = object.generateSecretKey(
            password.toCharArray(), salt, iterationCount,
            keyLength);
  
        String originalPassword = password;
        System.out.println("Original password: "
                           + originalPassword);
        String encryptedPassword
            = object.encrypt(originalPassword, key);
        
        System.out.println("Encrypted password: "
                           + encryptedPassword);
    }
}

Ahora vamos a crear la clase secretKey que contiene dos métodos .generateSecretKey() y .encrypt().

  1. Los . generarSecretKey() es una función que toma los parámetros contraseña, sal, número de iteraciones y longitud de la clave . Usamos el conteo de iteraciones como el número de iteraciones que debe tomar un algoritmo. La variable de longitud de clave es la longitud de la clave que finalmente necesitamos derivar. Este método genera las excepciones NoSuchAlgorithmException e InvalidKeySpecException .
  2. El método .getInstance() toma el nombre estándar del algoritmo de clave secreta solicitado y devuelve el nuevo objeto SecretKeyFactory .
  3. Ahora creamos una instancia de PBEKeySpec . El constructor toma una contraseña, sal, recuento de iteraciones y la longitud de la clave que se derivará para generar PBEKey de cifrados PBE de tamaño de clave variable.
  4. El método de encriptación toma dos parámetros, los datos a encriptar y la clave. Este método lanza dos excepciones GeneralSecurityException y UnsupportedEncodingException.
  5. El método .init() inicializa el Cipher para una de las cuatro operaciones siguientes: cifrado, descifrado, encapsulado de clave o desencapsulado de clave, según el valor del modo de operación. 
  6. También necesitamos un . método base64Encoder(byte[] bytes) . Es un método privado que codifica la array de bytes especificada en una string utilizando el esquema de codificación Base64 .

Ejemplo:

Java

// Java Program to Illustrate Class that Contains
  
package Exploit.org;
  
// Importing required classes 
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;
  
// Class 
public class secretKey {
    
    // Method  
    public SecretKeySpec
    generateSecretKey(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 tempKey
            = keyFactory.generateSecret(keySpec);
        return new SecretKeySpec(tempKey.getEncoded(),
                                 "AES");
    }
  
    // Method 
    private String base64Encoder(byte[] bytes)
    {
        return Base64.getEncoder().encodeToString(bytes);
    }
  
    // Method 
    public 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 base64Encoder(iv) + ":"
            + base64Encoder(cryptoText);
    }
}

Salida: fragmentos de código anteriores

Producción 

Analicemos finalmente los constructores y los métodos utilizados en los dos archivos de clase anteriores que son cifrados y de la siguiente manera: 

Constructores/Métodos Acción realizada
Propiedades() {…} Crea una lista de propiedades vacía sin valores predeterminados.
load(InputStream inStream) lanza IOException {…} Lee una lista de propiedades (pares de clave y elemento) del flujo de bytes de entrada.
getInstance (algoritmo de string) arroja NoSuchAlgorithmException {..} Devuelve un objeto {@code SecretKeyFactory} que convierte claves secretas del algoritmo especificado.
PBEKeySpec(char[] contraseña, byte[] salt, int iterationCount, int keyLength) {…} Se utiliza para generar PBEKey de cifrados PBE de tamaño de clave variable.
SecretKey generar secreto (KeySpec keySpec) lanza InvalidKeySpecException {…}  Genera un objeto {@code SecretKey} a partir de la especificación de clave proporcionada (material de clave).
init (modo de operación int, clave clave) lanza InvalidKeyException {…} Inicializa este cifrado con una clave.
AlgorithmParameters getParameters() {…} Devuelve los parámetros utilizados con este cifrado.
byte[] doFinal(byte[] input)
         lanza IllegalBlockSizeException, BadPaddingException {…}
Cifra o descifra datos en una operación de una sola parte o finaliza una operación de varias partes.
byte[] getIV() {…} Devuelve el vector de inicialización (IV).

Publicación traducida automáticamente

Artículo escrito por kaalel y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *