Panduan ke Kelas Cipher

1. Gambaran keseluruhan

Sederhananya, enkripsi adalah proses pengekodan mesej sehingga hanya pengguna sah yang dapat memahami atau mengaksesnya.

Mesej, disebut sebagai teks biasa , dienkripsi menggunakan algoritma enkripsi - cipher - menghasilkan ciphertext yang hanya dapat dibaca oleh pengguna yang sah melalui penyahsulitan.

Dalam artikel ini, kami menerangkan secara terperinci inti kelas Cipher , yang menyediakan fungsi penyulitan dan penyahsulitan kriptografi di Java.

2. Kelas Cipher

Java Cryptography Extension (JCE) adalah bagian dari Java Cryptography Architecture (JCA) yang menyediakan aplikasi dengan cipher kriptografi untuk enkripsi dan penyahsulitan data serta hashing data peribadi.

The Cipher kelas - yang terletak di javax.crypto pakej - membentuk teras rangka kerja JCE, menyediakan fungsi untuk penyulitan dan penyahsulitan.

2.1. Instantasi Cipher

Untuk mewujudkan objek Cipher , kami memanggil kaedah getInstance statik , meneruskan nama transformasi yang diminta . Secara pilihan, nama penyedia boleh ditentukan.

Mari tulis kelas contoh yang menggambarkan keadaan Cipher :

public class Encryptor { public byte[] encryptMessage(byte[] message, byte[] keyBytes) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException { Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); //... } }

Transformasi AES / ECB / PKCS5Padding memberitahu kaedah getInstance untuk menunjukkan objek Cipher sebagai cipher AES dengan mod operasi ECB dan skema padding PKCS5.

Kita juga dapat memberi contoh objek Cipher dengan menentukan hanya algoritma dalam transformasi:

Cipher cipher = Cipher.getInstance("AES");

Dalam kes ini, Java akan menggunakan nilai lalai khusus penyedia untuk mod dan skema padding.

Perhatikan bahawa getInstance akan membuang NoSuchAlgorithmException jika transformasi adalah null , kosongkan, atau dalam format yang tidak sah, atau jika pembekal tidak menyokongnya.

Ia akan membuang NoSuchPaddingException jika transformasi mengandungi skema padding yang tidak disokong.

2.2. Keselamatan Benang

The Cipher kelas adalah satu yang stateful tanpa sebarang bentuk penyelarasan dalaman. Sebenarnya, kaedah seperti init () atau kemas kini () akan mengubah keadaan dalaman contoh Cipher tertentu .

Oleh itu, kelas Cipher tidak selamat menggunakan benang. Oleh itu, kita harus membuat satu contoh Cipher setiap keperluan penyulitan / penyahsulitan.

2.3. Kekunci

Antara muka Kunci mewakili kunci untuk operasi kriptografi. Kekunci adalah bekas legap yang memegang kunci yang dikodkan, format pengekodan kunci, dan algoritma kriptografi.

Kunci biasanya diperoleh melalui penjana kunci, sijil, atau spesifikasi utama menggunakan kilang utama.

Mari buat Kunci simetri dari bait kunci yang dibekalkan:

SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");

2.4. Permulaan Cipher

Kami memanggil kaedah init () untuk menginisialisasi objek C ipher dengan Kunci atau Sijil dan opmode yang menunjukkan mod operasi cipher.

Sebagai pilihan, kita dapat menyampaikan sumber keacakan . Secara lalai, pelaksanaan SecureRandom penyedia terpasang dengan keutamaan tertinggi digunakan. Jika tidak, ia akan menggunakan sumber yang disediakan sistem.

Kita boleh menentukan satu set parameter khusus algoritma secara pilihan. Sebagai contoh, kita boleh lulus IvParameterSpec untuk menentukan vektor inisialisasi .

Berikut adalah mod operasi cipher yang tersedia:

  • ENCRYPT_MODE : mulakan objek cipher ke mod penyulitan
  • DECRYPT_MODE : Memula cipher objek ke mod penyahsulitan
  • WRAP_MODE : inisialisasi objek cipher ke mod pembungkus kunci
  • UNWRAP_MODE : mulakan objek cipher ke mod buka kunci

Mari kita mulakan objek Cipher :

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey secretKey = new SecretKeySpec(keyBytes, "AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); // ...

Sekarang, kaedah init melemparkan InvalidKeyException jika kunci yang diberikan tidak sesuai untuk memulakan cipher, seperti ketika panjang kunci / pengekodan tidak sah.

Ia juga dilemparkan apabila cipher memerlukan parameter algoritma tertentu yang tidak dapat ditentukan dari kunci, atau jika kunci mempunyai ukuran kunci yang melebihi ukuran kunci maksimum yang dibenarkan (ditentukan dari fail dasar bidang kuasa JCE yang dikonfigurasi).

Mari lihat contoh menggunakan Sijil :

public byte[] encryptMessage(byte[] message, Certificate certificate) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, certificate); // ... }

The Cipher objek mendapat kunci awam untuk penyulitan data dari sijil dengan menghubungi getPublicKey kaedah.

2.5. Penyulitan dan Penyahsulitan

Setelah memulakan objek Cipher , kami memanggil kaedah doFinal () untuk melakukan operasi penyulitan atau penyahsulitan. Kaedah ini mengembalikan array bait yang mengandungi mesej yang dienkripsi atau didekripsi.

Kaedah doFinal () juga mengatur ulang objek Cipher ke keadaan ketika sebelumnya diinisialisasi melalui kaedah panggilan ke init () , menjadikan objek Cipher tersedia untuk mengenkripsi atau mendekripsi mesej tambahan.

Mari panggil doFinal dalam kaedah encryptMessage kami :

public byte[] encryptMessage(byte[] message, byte[] keyBytes) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException { Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey secretKey = new SecretKeySpec(keyBytes, "AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); return cipher.doFinal(message); }

Untuk menjalankan operasi dekripsi , kami menukar opmode menjadi DECRYPT_MODE :

public byte[] decryptMessage(byte[] encryptedMessage, byte[] keyBytes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey secretKey = new SecretKeySpec(keyBytes, "AES"); cipher.init(Cipher.DECRYPT_MODE, secretKey); return cipher.doFinal(encryptedMessage); }

2.6. Penyedia

Direka untuk menggunakan seni bina berasaskan penyedia, JCE memungkinkan perpustakaan kriptografi yang berkelayakan seperti BouncyCastle dipasang sebagai penyedia keselamatan dan algoritma baru untuk ditambahkan dengan lancar .

Now let's add BouncyCastle as a security provider. We can add a security provider either statically or dynamically.

To add BouncyCastle statically, we modify the java.security file located in /jre/lib/security folder.

We add the line at the end of the list:

... security.provider.4=com.sun.net.ssl.internal.ssl.Provider security.provider.5=com.sun.crypto.provider.SunJCE security.provider.6=sun.security.jgss.SunProvider security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider

When adding the provider property, the property key is in the format security.provider.N where the number N is one more than the last one on the list.

We can also add the BouncyCastle security provider dynamically without having to modify the security file:

Security.addProvider(new BouncyCastleProvider());

We can now specify the provider during cipher initialization:

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");

BC specifies BouncyCastle as the provider. We can get the list of registered providers via the Security.getProviders() method.

3. Testing Encryption and Decryption

Let's write an example test to illustrate message encryption and decryption.

In this test, we use AES encryption algorithm with a 128-bit key and assert that the decrypted result is equal to the original message text:

@Test public void whenIsEncryptedAndDecrypted_thenDecryptedEqualsOriginal() throws Exception { String encryptionKeyString = "thisisa128bitkey"; String originalMessage = "This is a secret message"; byte[] encryptionKeyBytes = encryptionKeyString.getBytes(); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey secretKey = new SecretKeySpec(encryptionKeyBytes, "AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encryptedMessageBytes = cipher.doFinal(message.getBytes()); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] decryptedMessageBytes = cipher.doFinal(encryptedMessageBytes); assertThat(originalMessage).isEqualTo(new String(decryptedMessageBytes)); }

4. Conclusion

In this article, we discussed the Cipher class and presented usage examples. More details on the Cipher class and the JCE Framework can be found in the class documentation and the Java Cryptography Architecture (JCA) Reference Guide.

Pelaksanaan semua contoh dan coretan kod ini boleh didapati di GitHub . Ini adalah projek berasaskan Maven, jadi mudah diimport dan dijalankan sebagaimana adanya.