Kennwort in Konfigurationsdateien verschlüsseln in Java

Rashmi Patidar 12 Oktober 2023
Kennwort in Konfigurationsdateien verschlüsseln in Java

Bei der Verschlüsselung werden Klartextinformationen mithilfe eines Verschlüsselungsalgorithmus in Kombination mit einem Parameter namens Verschlüsselungsschlüssel in eine unlesbare Form umgewandelt. Das unlesbare Format wird häufig als ciphertext-Format bezeichnet. Nur wer den Entschlüsselungsschlüssel besitzt, kann die Daten entschlüsseln und den ursprünglichen Klartext wiederherstellen.

Wir können das Problem der Verschlüsselung von Passwörtern in Konfigurationsdateien in zwei folgende Unteraufgaben aufteilen.

  1. Verschlüsseln Sie das in der Datei enthaltene Klartextkennwort.
  2. Entschlüsseln Sie das aus der Datei eingelesene verschlüsselte Passwort.

Lassen Sie uns zuerst eine Konfigurationsdatei mit dem Namen config.properties im Pfad src/conf/ erstellen.

password = TestPassword123

Um nun die Konfigurationsdatei zu lesen, instanziieren Sie die Klasse Properties. Wir können eine Instanz der Klasse FileInputStream mit ihrem Konstruktor erstellen. Es nimmt den Pfad der Konfigurationsdatei als Eingabe. Jetzt wird eine Instanz der Eigenschaftenklasse verwendet, um die Eigenschaften zu laden. Verwenden Sie die Methode load, um die Eigenschaftendatei in die Klasse zu laden. Dabei wird die Instanz InputStreamReader als Parameter verwendet. Es wird IllegalArgumentException ausgelöst, wenn dieser Eingabestream eine fehlerhafte Unicode-Escape-Sequenz enthält, und IOException, wenn beim Lesen aus dem Eingabestream ein Fehler aufgetreten ist.

Verwenden Sie nach dem erfolgreichen Laden der Eigenschaften die Methode getProperty(), um nach der Eigenschaft mit dem angegebenen Schlüssel in der Eigenschaftenliste zu suchen. Die Methode gibt null zurück, wenn die Eigenschaften nicht gefunden werden können. Führen Sie eine externe Prüfung durch, um eine solche Situation zu behandeln, und lösen Sie IllegalArgumentException aus, wenn in der Datei ein Kennwort gefunden wird, das null ist.

salt wird mit einer beliebigen zufälligen Zeichenkette erstellt, die der KennwortZeichenkette hinzugefügt wird.

createSecretKey ist eine benutzerdefinierte Methode, die den SecretKeySpec-Schlüssel zurückgibt. Mit dem Schlüssel wird das Kennwort verschlüsselt und entschlüsselt. Die Methoden encrypt und decrypt sind benutzerdefinierte static Methoden, die in der Klasse Encryption angegeben wurden.

Unten finden Sie den Beispielcode, der dasselbe demonstriert.

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

Eine detaillierte Beschreibung der benutzerdefinierten Methoden in der Klasse Verschlüsselung finden Sie unten.

  1. Der createSecretKey ist eine Funktion, die Parameter wie password, salt, iterationCount und keyLength akzeptiert. password ist das eigentliche Passwort in der Konfigurationsdatei. In der Kryptographie sind ein salt zufällige Daten, die wir als zusätzliche Eingabe verwenden, die Daten, ein Kennwort oder eine Passphrase hasht. Die Verwendung von salts dient zum Schutz von Passwörtern bei der Lagerung. Wir verwenden die Variable iterationCount als Anzahl der Iterationen, die ein Algorithmus ausführen soll. Das Verringern des Werts der Variablen beschleunigt die Startzeit und ist daher beim Testen hilfreich, erleichtert aber auch Brute-Force-Angreifern. Die Variable keyLength ist die Länge des Schlüssels, den wir letztendlich ableiten müssen. Löst die Ausnahme aus, die von den verwendeten Methoden ausgelöst wurde.
  2. Die Methode getInstance durchläuft die Liste der registrierten Sicherheitsanbieter, beginnend mit dem am meisten bevorzugten Anbieter. Es nimmt den Standardnamen des angeforderten Secret-Key-Algorithmus und gibt das neue Objekt SecretKeyFactory zurück. Es wird NullPointerException ausgelöst, wenn der angegebene Algorithmus null ist, und NoSuchAlgorithmException, wenn kein Anbieter eine SecretKeyFactorySpi-Implementierung für den angegebenen Algorithmus unterstützt.
  3. PBEKeySpec ist ein Klassenkonstruktor, der ein Kennwort, einen Salt, eine Iterationszahl und eine abzuleitende Schlüssellänge zum Generieren von PBEKey von PBE-Chiffren mit variabler Schlüsselgröße verwendet. Es wird NullPointerException ausgelöst, wenn salt null ist, und IllegalArgumentException, wenn salt leer ist.
  4. generateSecret generiert aus der angegebenen Schlüsselspezifikation oder dem Schlüsselmaterial ein SecretKey-Objekt. Es braucht die Angabe des geheimen Schlüssels. Es wird InvalidKeySpecException ausgelöst, wenn die angegebene Spezifikation für diese Fabrik mit geheimen Schlüsseln nicht geeignet ist, um einen klassifizierten Schlüsselwert zu erzeugen.

Details zur Methode encrypt in der Klasse Encryption.

  1. Die Methode encrypt verwendet zwei Parameter, die zu verschlüsselnden Daten und den Schlüssel. Diese Methode löst Ausnahmen aus, die von untergeordneten Methoden ausgelöst werden.
  2. Die Methode getInstance durchläuft die Liste der registrierten Sicherheitsanbieter, beginnend mit dem am meisten bevorzugten Anbieter. Es wird der Name der Transformation verwendet, dh AES / CBC / PKCS5Padding. Es wird NoSuchAlgorithmException ausgelöst, wenn eine Änderung null und leer in einem ungültigen Format ist, und NoSuchPaddingException, wenn die Änderung ein Auffüllschema enthält, das nicht verfügbar ist.
  3. Die Methode init initialisiert die Verschlüsselung für eine der folgenden vier Operationen: Verschlüsselung, Entschlüsselung, Schlüsselumbruch oder Schlüsselentpackung, abhängig vom Wert des Betriebsmodus. ENCRYPT_MODE in unserem Fall. Die Methode löst UnsupportedOperationException aus, wenn der Betriebsmodus ungültig ist, und InvalidKeyException, wenn der angegebene Schlüssel unangemessen ist.
  4. Der getParameters gibt die mit dieser Chiffre verwendeten Parameter zurück.
  5. Die getParameterSpec gibt eine Spezifikation des Parameterobjekts zurück. Der Parameter paramSpec gibt die Spezifikationsklasse an, in der die Parameter zurückgegeben werden müssen. Beispielsweise könnte es die DSAParameterSpec.class sein, die angibt, dass die Parameter in einer Instanz der Klasse DSAParameterSpec zurückgegeben werden müssen.
  6. Die Methode doFinal verschlüsselt oder entschlüsselt Daten in einer einteiligen Arbeit oder beendet eine mehrteilige Operation. Die Daten werden verschlüsselt oder entschlüsselt, je nachdem, wie wir die Verschlüsselung initialisieren.
  7. base64Encode ist eine private Methode, die das angegebene Bytearray mithilfe des Codierungsschemas Base64 in eine Zeichenkette codiert. Die in der Methode decrypt verwendeten Funktionen ähneln der oben genannten Methode. Der einzige Unterschied besteht darin, dass sie sich je nach dem in der Funktion DECRYPT_MODE als Betriebsmodus angegebenen Modus unterschiedlich verhalten.
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);
  }
}

Unten sehen Sie die Ausgabe des Codes, der zum Ver- und Entschlüsseln des Kennworts in der Konfigurationsdatei geschrieben wurde.

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

Verwandter Artikel - Java Encryption