Crittografa la password nei file di configurazione in Java

Rashmi Patidar 12 ottobre 2023
Crittografa la password nei file di configurazione in Java

La crittografia è il processo di trasformazione delle informazioni di testo in chiaro in una forma illeggibile utilizzando un algoritmo di crittografia combinato con un parametro chiamato “chiave di crittografia”. Il formato illeggibile è spesso noto come formato ciphertext. Solo chi possiede la chiave di decrittazione può decrittare i dati e recuperare il testo in chiaro originale.

Possiamo suddividere il problema della crittografia delle password nei file di configurazione in due sotto-attività seguenti.

  1. Crittografare la password in testo normale presente nel file.
  2. Decrittografare la password crittografata letta dal file.

Creiamo prima un file di configurazione chiamato file config.properties nel percorso src/conf/.

password = TestPassword123

Ora per leggere il file di configurazione, istanziare la classe Properties. Possiamo creare un’istanza della classe FileInputStream usando il suo costruttore. Prende il percorso del file di configurazione come input. Ora un’istanza della classe properties viene utilizzata per caricare le proprietà. Usa il metodo load per caricare il file delle proprietà nella classe, e questo prende l’istanza InputStreamReader come parametro. Genera IllegalArgumentException se questo flusso di input contiene una sequenza di escape Unicode non valida e IOException se si è verificato un errore durante la lettura dal flusso di input.

Una volta caricate con successo le proprietà, utilizzare il metodo getProperty() per cercare la proprietà con la chiave specificata nella lista delle proprietà. Il metodo restituisce null se non è in grado di trovare le proprietà. Posiziona un controllo esterno per gestire una situazione del genere e lancia IllegalArgumentException se una password viene trovata nulla dal file.

salt viene creato con qualsiasi stringa casuale da aggiungere alla stringa della password.

createSecretKey è un metodo definito dall’utente che restituisce la chiave SecretKeySpec e l’uso della chiave è crittografare e decrittografare la password. I metodi encrypt e decrypt sono metodi statici definiti usati che sono stati forniti, nella classe Encryption.

Di seguito è il codice di esempio che dimostra lo stesso.

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);
  }
}

Di seguito viene fornita una descrizione dettagliata dei metodi definiti dall’utente nella classe Encryption.

  1. createSecretKey è una funzione che accetta parametri come password, salt, iterationCount e keyLength. password è la password effettiva nel file di configurazione. In crittografia, un salt è un dato casuale che utilizziamo come input aggiuntivo che esegue l’hashing dei dati, una password o una passphrase. L’uso dei salts serve a salvaguardare le password in deposito. Usiamo la variabile iterationCount come numero di iterazioni che un algoritmo dovrebbe prendere. La diminuzione del valore della variabile accelera il tempo di avvio e quindi è utile durante i test, ma rende anche più facile per gli attaccanti di forza bruta. La variabile keyLength è la lunghezza della chiave che alla fine dobbiamo derivare. Genera l’eccezione generata dai metodi utilizzati.
  2. Il metodo getInstance attraversa la lista dei provider di sicurezza registrati, a partire dal provider più preferito. Prende il nome standard dell’algoritmo della chiave segreta richiesta e restituisce il nuovo oggetto SecretKeyFactory. Lancia NullPointerException se l’algoritmo specificato è nullo e NoSuchAlgorithmException se nessun Provider supporta un’implementazione SecretKeyFactorySpi per l’algoritmo specificato.
  3. PBEKeySpec è un costruttore di classi che accetta una password, salt, numero di iterazioni e lunghezza della chiave da derivare per generare PBEKey di cifrari PBE a dimensione di chiave variabile. Lancia NullPointerException se salt è null e IllegalArgumentException se salt è vuoto.
  4. generateSecret genera un oggetto SecretKey dalla specifica della chiave fornita o dal materiale della chiave. Accetta la specifica della chiave segreta. Genera InvalidKeySpecException se la specifica data non è appropriata per questa factory di chiavi segrete per produrre un valore chiave classificato.

Dettagli del metodo encrypt nella classe Encryption.

  1. Il metodo encrypt richiede due parametri, i dati da crittografare e la chiave. Questo metodo genera eccezioni generate da metodi figlio in esso.
  2. Il metodo getInstance attraversa la lista dei provider di sicurezza registrati, a partire dal provider più preferito. Prende il nome della trasformazione, ovvero AES / CBC / PKCS5Padding. Genera NoSuchAlgorithmException se una modifica è nulla, vuota, in un formato non valido e NoSuchPaddingException se la modifica contiene uno schema di riempimento non disponibile.
  3. Il metodo init inizializza il Cipher per una delle seguenti quattro operazioni: crittografia, decrittografia, avvolgimento della chiave o scartamento della chiave, a seconda del valore della modalità di operazione. ENCRYPT_MODE nel nostro caso. Il metodo genera UnsupportedOperationException se la modalità operativa non è valida e InvalidKeyException se la chiave fornita è inappropriata.
  4. Il getParameters restituisce i parametri usati con questo cifrario.
  5. Il getParameterSpec restituisce una specifica dell’oggetto parametro. Il parametro paramSpec identifica la classe di specifica in cui i parametri devono tornare. Ad esempio, potrebbe essere DSAParameterSpec.class per indicare che i parametri devono tornare in un’istanza della classe DSAParameterSpec.
  6. Il metodo doFinal crittografa o decrittografa i dati in una singola parte di lavoro o termina un’operazione in più parti. I dati vengono crittografati o decrittografati, a seconda di come inizializziamo la crittografia.
  7. base64Encode è un metodo privato che codifica l’array di byte specificato in una stringa utilizzando lo schema di codifica Base64. Le funzioni usate nel metodo decrypt sono simili al metodo sopra menzionato. L’unica differenza è che si comportano in modo diverso in base alla mode specificata nella funzione, DECRYPT_MODE come modalità operativa.
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);
  }
}

Di seguito è riportato l’output del codice scritto per crittografare e decrittografare la password nel file di configurazione.

Original password: TestPassword123
Encrypted password: Hy7fbIwpyKgp0oileu+oLg==:WNRknMJz/8u8GmWlCZFPFA==
Decrypted password: TestPassword123
Rashmi Patidar avatar Rashmi Patidar avatar

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