Verschlüsseln und Entschlüsseln von Dateien in Java

Dateien in Java verschlüsseln und entschlüsseln

1. Überblick

In diesem Tutorial erfahren Sie, wie Sie eine Datei mit vorhandenen JDK-APIs verschlüsseln und entschlüsseln.

2. Zuerst einen Test schreiben

Wir beginnen mit dem Schreiben unseres Tests im TDD-Stil. Da wir hier mit Dateien arbeiten werden, scheint ein Integrationstest angemessen zu sein.

Da wir nur vorhandene JDK-Funktionen verwenden, sind keine externen Abhängigkeiten erforderlich.

Erstenswe’ll encrypt the content using a newly generated secret key (in diesem Beispiel wird AES,Advanced Encryption Standard als symmetrischer Verschlüsselungsalgorithmus verwendet).

Beachten Sie auch, dass wir die vollständige Transformationszeichenfolge im Konstruktor (AES/CBC/PKCS5Padding) definieren. Dies ist eine Verkettung der verwendeten Verschlüsselung, des Blockverschlüsselungsmodus und des Auffüllens (algorithm/mode/padding). JDK-Implementierungen unterstützen standardmäßig eine Reihe verschiedener Transformationen. Beachten Sie jedoch, dass nach den heutigen Standards nicht jede Kombination als kryptografisch sicher angesehen werden kann.

Wir gehen vonour FileEncrypterDecrypter class will write the output to a file called baz.enc aus. Anschließendwe decrypt this file using the same secret key und überprüfen Sie, ob der entschlüsselte Inhalt dem ursprünglichen Inhalt entspricht:

@Test
public void whenEncryptingIntoFile_andDecryptingFileAgain_thenOriginalStringIsReturned() {
    String originalContent = "foobar";
    SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();

    FileEncrypterDecrypter fileEncrypterDecrypter
      = new FileEncrypterDecrypter(secretKey, "AES/CBC/PKCS5Padding");
    fileEncrypterDecrypter.encrypt(originalContent, "baz.enc");

    String decryptedContent = fileEncrypterDecrypter.decrypt("baz.enc");
    assertThat(decryptedContent, is(originalContent));

    new File("baz.enc").delete(); // cleanup
}

3. Verschlüsselung

Wir initialisieren die Verschlüsselung im Konstruktor unsererFileEncrypterDecrypter-Klasse mit der angegebenen TransformationString.

Dies ermöglicht es uns, frühzeitig zu scheitern, falls eine falsche Transformation angegeben wurde:

FileEncrypterDecrypter(SecretKey secretKey, String transformation) {
    this.secretKey = secretKey;
    this.cipher = Cipher.getInstance(transformation);
}

Wir können dannuse the instantiated cipher and the provided secret key to perform the encryption:

void encrypt(String content, String fileName) {
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    byte[] iv = cipher.getIV();

    try (FileOutputStream fileOut = new FileOutputStream(fileName);
      CipherOutputStream cipherOut = new CipherOutputStream(fileOut, cipher)) {
        fileOut.write(iv);
        cipherOut.write(content.getBytes());
    }
}

Java erlaubt unsleverage the convenient CipherOutputStream class for writing the encrypted content into another OutputStream.

Bitte beachten Sie, dass wir die IV (Initialization Vector) an den Anfang der Ausgabedatei schreiben. In diesem Beispiel wird die IV automatisch generiert, wennCipher initialisiert werden.

Die Verwendung einer IV ist im CBC-Modus obligatorisch, um die verschlüsselte Ausgabe nach dem Zufallsprinzip zu sortieren. Die IV wird jedoch nicht als Geheimnis angesehen, daher ist es in Ordnung, sie am Anfang der Datei zu schreiben.

4. Entschlüsselung

Zum Entschlüsseln müssen wir ebenfalls zuerst die IV lesen. Anschließend können wir unsere Verschlüsselung initialisieren und den Inhalt entschlüsseln.

Wieder können wir eine spezielle Java-Klasse verwenden,CipherInputStream, which transparently takes care of the actual decryption:

String decrypt(String fileName) {
    String content;

    try (FileInputStream fileIn = new FileInputStream(fileName)) {
        byte[] fileIv = new byte[16];
        fileIn.read(fileIv);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(fileIv));

        try (
                CipherInputStream cipherIn = new CipherInputStream(fileIn, cipher);
                InputStreamReader inputReader = new InputStreamReader(cipherIn);
                BufferedReader reader = new BufferedReader(inputReader)
            ) {

            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            content = sb.toString();
        }

    }
    return content;
}

5. Fazit

Wir haben gesehen, dass wir eine grundlegende Ver- und Entschlüsselung mit Standard-JDK-Klassen wieCipher,CipherOutputStream undCipherInputStream durchführen können.

Wie üblich ist der vollständige Code für diesen Artikel in unserenGitHub repository verfügbar.

Darüber hinaus finden Sie eine Liste der in den JDKhere verfügbaren Chiffren.

Beachten Sie schließlich, dass die Codebeispiele hier nicht als Code für die Produktion gedacht sind und die Besonderheiten Ihres Systems bei der Verwendung sorgfältig berücksichtigt werden müssen.