Kryptera och dekryptera filer i Java

Java Top

Jag tillkännagav just den nya Learn Spring- kursen, med fokus på grunderna i Spring 5 och Spring Boot 2:

>> KONTROLLERA KURSET

1. Översikt

I den här handledningen tar vi en titt på hur man krypterar och dekrypterar en fil med befintliga JDK API: er.

2. Skriv ett test först

Vi börjar med att skriva vårt test, TDD-stil. Eftersom vi ska arbeta med filer här verkar ett integrationstest vara lämpligt.

Eftersom vi bara använder befintliga JDK-funktioner är inga externa beroenden nödvändiga.

Först krypterar vi innehållet med en nyskapad hemlig nyckel (vi använder AES, Advanced Encryption Standard, som den symmetriska krypteringsalgoritmen i detta exempel).

Observera också att vi definierar den fullständiga transformationssträngen i konstruktören ( AES / CBC / PKCS5Padding ), som är en sammankoppling av använd kryptering, blockkrypteringsläge och padding ( algoritm / läge / padding ). JDK-implementeringar stöder ett antal olika transformationer som standard, men observera att inte alla kombinationer fortfarande kan betraktas som kryptografiskt säkra enligt dagens standarder.

Vi antar att vår FileEncrypterDecrypter- klass skriver utdata till en fil som heter baz.enc . Därefter dekrypterar vi den här filen med samma hemliga nyckel och kontrollerar att det dekrypterade innehållet är lika med det ursprungliga innehållet:

@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. Kryptering

Vi initialiserar chiffran i konstruktören av vår FileEncrypterDecrypter- klass med den angivna transformationssträngen .

Detta gör att vi kan misslyckas tidigt om en felomvandling specificerades:

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

Vi kan sedan använda den instantierade chiffran och den medföljande hemliga nyckeln för att utföra krypteringen:

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 tillåter oss att utnyttja den bekväma CipherOutputStream- klassen för att skriva det krypterade innehållet till en annan OutputStream .

Observera att vi skriver IV (Initialization Vector) till början av utdatafilen. I det här exemplet genereras IV automatiskt när Cipher initieras .

Att använda en IV är obligatorisk när man använder CBC-läge för att randomisera den krypterade utdata. IV anses dock inte vara en hemlighet, så det är okej att skriva det i början av filen.

4. Dekryptering

För att dekryptera måste vi också läsa IV först. Därefter kan vi initialisera vår kryptering och dekryptera innehållet.

Återigen kan vi använda en speciell Java-klass, CipherInputStream , som transparent tar hand om den faktiska dekrypteringen :

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. Sammanfattning

Vi har sett att vi kan utföra grundläggande kryptering och dekryptering med standard JDK-klasser, som Cipher , CipherOutputStream och CipherInputStream .

Som vanligt är den fullständiga koden för den här artikeln tillgänglig i vårt GitHub-arkiv.

Dessutom kan du hitta en lista över de kodar som finns tillgängliga i JDK här.

Slutligen notera att kodexemplen här inte är avsedda som produktionskod och att detaljerna i ditt system måste övervägas noggrant när du använder dem.

Java-botten

Jag tillkännagav just den nya Learn Spring- kursen, med fokus på grunderna i Spring 5 och Spring Boot 2:

>> KONTROLLERA KURSET