Menyulitkan dan Mendekripsi Fail di Java

Java Teratas

Saya baru sahaja mengumumkan kursus Learn Spring yang baru , yang berfokus pada asas-asas Spring 5 dan Spring Boot 2:

>> SEMAK KURSUS

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan melihat bagaimana mengenkripsi dan mendekripsi fail menggunakan JDK API yang ada.

2. Menulis Ujian Pertama

Kami akan memulakan dengan menulis ujian kami, gaya TDD. Oleh kerana kita akan bekerjasama dengan fail di sini, ujian integrasi nampaknya sesuai.

Oleh kerana kami hanya menggunakan fungsi JDK yang ada, tidak diperlukan pergantungan luaran.

Pertama, kami akan menyulitkan kandungan menggunakan kunci rahsia yang baru dihasilkan (kami menggunakan AES, Advanced Encryption Standard, sebagai algoritma penyulitan simetri dalam contoh ini).

Perhatikan juga, bahawa kami menentukan rentetan transformasi lengkap dalam konstruktor ( AES / CBC / PKCS5Padding ), yang merupakan gabungan enkripsi yang digunakan, mod cipher blok, dan padding ( algoritma / mod / padding ). Pelaksanaan JDK menyokong sejumlah transformasi yang berbeza secara lalai, tetapi harap maklum, bahawa tidak semua kombinasi masih boleh dianggap selamat secara kriptografi mengikut standard masa kini.

Kami akan menganggap kelas FileEncrypterDecrypter kami akan menulis output ke fail yang disebut baz.enc . Selepas itu, kami menyahsulitkan fail ini menggunakan kunci rahsia yang sama dan memastikan bahawa kandungan yang didekripsi sama dengan kandungan asalnya:

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

Kami akan memulakan cipher dalam konstruktor kelas FileEncrypterDecrypter kami menggunakan String transformasi yang ditentukan .

Ini membolehkan kita gagal lebih awal sekiranya transformasi yang salah ditentukan:

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

Kami kemudian boleh menggunakan cipher yang disusun dan kunci rahsia yang disediakan untuk melakukan penyulitan:

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 membolehkan kita memanfaatkan kelas CipherOutputStream yang sesuai untuk menulis kandungan yang dienkripsi ke OutputStream yang lain .

Harap maklum bahawa kami sedang menulis IV (Initialization Vector) hingga awal fail output. Dalam contoh ini, IV dihasilkan secara automatik ketika memulakan Cipher .

Menggunakan IV adalah wajib ketika menggunakan mod CBC, untuk mengacak output yang disulitkan. Walau bagaimanapun, IV tidak dianggap rahsia, jadi tidak mengapa menulisnya di awal fail.

4. Penyahsulitan

Untuk menyahsulit, kita juga harus membaca IV terlebih dahulu. Selepas itu, kami dapat menginisialisasi penyekat dan mendekripsi kandungannya.

Sekali lagi kita dapat memanfaatkan kelas Java khas, CipherInputStream , yang secara telus mengurus penyahsulitan sebenarnya :

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

Kami telah melihat bahawa kami dapat melakukan penyulitan dan penyahsulitan asas menggunakan kelas JDK standard, seperti Cipher , CipherOutputStream dan CipherInputStream .

Seperti biasa, kod lengkap untuk artikel ini terdapat di repositori GitHub kami.

Di samping itu, anda boleh mendapatkan senarai Ciphers yang terdapat di JDK di sini.

Akhirnya, perhatikan bahawa contoh kod di sini tidak dimaksudkan sebagai kod gred pengeluaran dan spesifik sistem anda perlu dipertimbangkan secara menyeluruh ketika menggunakannya.

Bahagian bawah Java

Saya baru sahaja mengumumkan kursus Learn Spring yang baru , yang berfokus pada asas-asas Spring 5 dan Spring Boot 2:

>> SEMAK KURSUS