Versleutelen en ontsleutelen van bestanden in Java

Java Top

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS

1. Overzicht

In deze zelfstudie bekijken we hoe u een bestand kunt coderen en decoderen met behulp van bestaande JDK-API's.

2. Eerst een test schrijven

We beginnen met het schrijven van onze test, TDD-stijl. Aangezien we hier met bestanden gaan werken, lijkt een integratietest op zijn plaats.

Omdat we alleen bestaande JDK-functionaliteit gebruiken, zijn er geen externe afhankelijkheden nodig.

Eerste, we versleutelen de inhoud met een nieuw gegenereerde geheime sleutel (we gebruiken AES, Advanced Encryption Standard, als het symmetrische versleutelingsalgoritme in dit voorbeeld).

Merk ook op dat we de volledige transformatiestring definiëren in de constructor (AES / CBC / PKCS5Padding), wat een aaneenschakeling is van gebruikte codering, blokcoderingsmodus en opvulling (algoritme / modus / opvulling). JDK-implementaties ondersteunen standaard een aantal verschillende transformaties, maar houd er rekening mee dat niet elke combinatie volgens de huidige standaarden nog steeds als cryptografisch veilig kan worden beschouwd.

We gaan ervan uit onze FileEncrypterDecrypter class schrijft de uitvoer naar een bestand met de naam baz.enc. Nadien, we decoderen dit bestand met dezelfde geheime sleutel en controleer of de gedecodeerde inhoud gelijk is aan de originele inhoud:

@Test openbare ongeldigheid whenEncryptingIntoFile_andDecryptingFileAgain_thenOriginalStringIsReturned () {String originalContent = "foobar"; SecretKey secretKey = KeyGenerator.getInstance ("AES"). GenerKey (); FileEncrypterDecrypter fileEncrypterDecrypter = nieuwe FileEncrypterDecrypter (secretKey, "AES / CBC / PKCS5Padding"); fileEncrypterDecrypter.encrypt (originalContent, "baz.enc"); String decryptedContent = fileEncrypterDecrypter.decrypt ("baz.enc"); assertThat (decryptedContent, is (originalContent)); nieuw bestand ("baz.enc"). delete (); // schoonmaken }

3. Versleuteling

We initialiseren het cijfer in de constructor van onze FileEncrypterDecrypter klasse met behulp van de opgegeven transformatie Draad.

Dit stelt ons in staat om vroegtijdig te falen in het geval een verkeerde transformatie werd gespecificeerd:

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

We kunnen dan gebruik het geïnstantieerde cijfer en de verstrekte geheime sleutel om de codering uit te voeren:

ongeldige codering (String-inhoud, String-bestandsnaam) {cipher.init (Cipher.ENCRYPT_MODE, secretKey); byte [] iv = cipher.getIV (); probeer (FileOutputStream fileOut = nieuwe FileOutputStream (bestandsnaam); CipherOutputStream cipherOut = nieuwe CipherOutputStream (fileOut, cipher)) {fileOut.write (iv); cipherOut.write (content.getBytes ()); }}

Java stelt ons in staat maak gebruik van het handige CipherOutputStream klasse voor het schrijven van de gecodeerde inhoud naar een andere OutputStream.

Houd er rekening mee dat we de IV (Initialization Vector) naar het begin van het uitvoerbestand schrijven. In dit voorbeeld wordt de IV automatisch gegenereerd bij het initialiseren van het Cijfer.

Het gebruik van een IV is verplicht in de CBC-modus om de gecodeerde uitvoer willekeurig te maken. De IV wordt echter niet als een geheim beschouwd, dus het is oké om deze aan het begin van het bestand te schrijven.

4. Decodering

Voor het decoderen moeten we eveneens eerst de IV lezen. Daarna kunnen we onze code initialiseren en de inhoud decoderen.

We kunnen weer gebruik maken van een speciale Java-klasse, CipherInputStream, die op transparante wijze zorgt voor de daadwerkelijke ontsleuteling:

String decoderen (String fileName) {String inhoud; probeer (FileInputStream fileIn = nieuwe FileInputStream (bestandsnaam)) {byte [] fileIv = nieuwe byte [16]; fileIn.read (fileIv); cipher.init (Cipher.DECRYPT_MODE, secretKey, nieuwe IvParameterSpec (fileIv)); probeer (CipherInputStream cipherIn = nieuwe CipherInputStream (fileIn, cipher); InputStreamReader inputReader = nieuwe InputStreamReader (cipherIn); BufferedReader-lezer = nieuwe BufferedReader (inputReader)) {StringBuilder sb = nieuwe StringBuilder (); String lijn; while ((line = reader.readLine ())! = null) {sb.append (regel); } content = sb.toString (); }} retourneer inhoud; }

5. Conclusie

We hebben gezien dat we basiscodering en decodering kunnen uitvoeren met behulp van standaard JDK-klassen, zoals Cijfer, CipherOutputStream en CipherInputStream.

Zoals gewoonlijk is de volledige code voor dit artikel beschikbaar in onze GitHub-repository.

Bovendien kunt u hier een lijst vinden van de Ciphers die beschikbaar zijn in de JDK.

Houd er ten slotte rekening mee dat de codevoorbeelden hier niet bedoeld zijn als code van productiekwaliteit en dat de specifieke kenmerken van uw systeem grondig moeten worden overwogen bij het gebruik ervan.

Java onderkant

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS