Jag tillkännagav just den nya Learn Spring- kursen, med fokus på grunderna i Spring 5 och Spring Boot 2:
>> KONTROLLERA KURSET1. Ö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