Шифроване и дешифриране на файлове в Java

Java Top

Току що обявих новия курс Learn Spring , фокусиран върху основите на Spring 5 и Spring Boot 2:

>> ПРЕГЛЕД НА КУРСА

1. Общ преглед

В този урок ще разгледаме как да шифровате и декриптирате файл, използвайки съществуващите API на JDK.

2. Писане на тест първо

Ще започнем с написването на нашия тест, TDD стил. Тъй като тук ще работим с файлове, интеграционният тест изглежда подходящ.

Тъй като просто използваме съществуваща функционалност JDK, не са необходими външни зависимости.

Първо ще шифроваме съдържанието, като използваме новосъздаден таен ключ (използваме AES, Advanced Encryption Standard, като алгоритъм за симетрично криптиране в този пример).

Също така обърнете внимание, че ние дефинираме пълния трансформационен низ в конструктора ( AES / CBC / PKCS5Padding ), който представлява конкатенация на използвано криптиране, режим на блоков шифър и подложка ( алгоритъм / режим / подложка ). Реализациите на JDK поддържат редица различни трансформации по подразбиране, но имайте предвид, че не всяка комбинация все още може да се счита за криптографски защитена от днешните стандарти.

Ще приемем, че нашият клас FileEncrypterDecrypter ще запише изхода във файл, наречен baz.enc . След това дешифрираме този файл с помощта на същия секретен ключ и проверяваме дали дешифрираното съдържание е равно на оригиналното съдържание:

@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. Шифроване

Ще инициализираме шифъра в конструктора на нашия клас FileEncrypterDecrypter, използвайки посочения низ за трансформация .

Това ни позволява да се провалим рано, в случай че е посочена грешна трансформация:

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

След това можем да използваме екземплярния шифър и предоставения таен ключ, за да извършим криптирането:

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 ни позволява да използваме удобния клас CipherOutputStream за запис на криптираното съдържание в друг OutputStream .

Моля, обърнете внимание, че пишем IV (инициализационен вектор) в началото на изходния файл. В този пример IV се генерира автоматично при инициализиране на шифъра .

Използването на IV е задължително, когато се използва режим CBC, за да се рандомизира криптираният изход. IV обаче не се счита за тайна, така че е добре да го напишете в началото на файла.

4. Дешифриране

За дешифриране също трябва първо да прочетем IV. След това можем да инициализираме нашия шифър и да дешифрираме съдържанието.

Отново можем да използваме специален Java клас, CipherInputStream , който прозрачно се грижи за действителното дешифриране :

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. Заключение

Видяхме, че можем да изпълняваме основно криптиране и декриптиране, използвайки стандартни JDK класове, като Cipher , CipherOutputStream и CipherInputStream .

Както обикновено, пълният код за тази статия е достъпен в нашето хранилище на GitHub.

Освен това тук можете да намерите списък с шифрите, налични в JDK.

И накрая, имайте предвид, че примерите за кодове тук не са предназначени като производствен код и спецификите на вашата система трябва да бъдат обмислени внимателно, когато ги използвате.

Дъно на Java

Току що обявих новия курс Learn Spring , фокусиран върху основите на Spring 5 и Spring Boot 2:

>> ПРЕГЛЕД НА КУРСА