Java AES加密和解密教程 - Baeldung
在本教程中,我們將看到如何使用JDK中的Java密碼體系結構(JCA)來實現AES加密和解密。對稱金鑰塊密碼在資料加密中起重要作用。這意味著同一金鑰可用於加密和解密。高階加密標準(AES)是一種廣泛使用的對稱金鑰加密演算法。
AES演算法是一種迭代的對稱金鑰塊密碼,它支援128、192和256位的加密金鑰(秘密金鑰),以對128位的塊中的資料進行加密和解密。
在AES中生成金鑰的方法有兩種:從隨機數生成或從給定密碼生成。
在第一種方法中,應該從像SecureRandom類這樣的加密安全(偽)隨機數生成器生成秘密金鑰。為了生成金鑰,我們可以使用KeyGenerator類。讓我們定義一種用於生成大小為n(128、192和256)位的AES金鑰的方法:
public static SecretKey generateKey(int n) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(n); SecretKey key = keyGenerator.generateKey(); return key; } |
在第二種方法中,可以使用基於密碼的金鑰派生功能(例如PBKDF2)從給定的密碼派生AES秘密金鑰。下面方法可透過65,536次迭代和256位金鑰長度從給定密碼生成AES金鑰:
public static SecretKey getKeyFromPassword(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256); SecretKey secret = new SecretKeySpec(factory.generateSecret(spec) .getEncoded(), "AES"); return secret; } |
加密字串
要實現輸入字串加密,我們首先需要根據上一節生成金鑰和初始化向量IV:
IV是偽隨機值,其大小與加密的塊相同。我們可以使用SecureRandom類生成隨機IV。
讓我們定義一種生成IV的方法:
public static IvParameterSpec generateIv() { byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); return new IvParameterSpec(iv); } |
下一步,我們使用getInstance()方法從Cipher類建立一個例項。
此外,我們使用帶有秘密金鑰,IV和加密模式的init()方法配置密碼例項。最後,我們透過呼叫doFinal()方法對輸入字串進行加密。此方法獲取輸入位元組並以位元組為單位返回密文:
public static String encrypt(String algorithm, String input, SecretKey key, IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, key, iv); byte[] cipherText = cipher.doFinal(input.getBytes()); return Base64.getEncoder() .encodeToString(cipherText); } |
為了解密輸入字串,我們可以使用DECRYPT_MODE初始化密碼來解密內容:
public static String decrypt(String algorithm, String cipherText, SecretKey key, IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.DECRYPT_MODE, key, iv); byte[] plainText = cipher.doFinal(Base64.getDecoder() .decode(cipherText)); return new String(plainText); } |
編寫一個用於加密和解密字串輸入的測試方法:
@Test void givenString_whenEncrypt_thenSuccess() throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException { String input = "baeldung"; SecretKey key = AESUtil.generateKey(128); IvParameterSpec ivParameterSpec = AESUtil.generateIv(); String algorithm = "AES/CBC/PKCS5Padding"; String cipherText = AESUtil.encrypt(algorithm, input, key, ivParameterSpec); String plainText = AESUtil.decrypt(algorithm, cipherText, key, ivParameterSpec); Assertions.assertEquals(input, plainText); } |
加密檔案
現在,讓我們使用AES演算法加密檔案。步驟是相同的,但是我們需要一些IO類來處理檔案。讓我們加密一個文字檔案:
public static void encryptFile(String algorithm, SecretKey key, IvParameterSpec iv, File inputFile, File outputFile) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, key, iv); FileInputStream inputStream = new FileInputStream(inputFile); FileOutputStream outputStream = new FileOutputStream(outputFile); byte[] buffer = new byte[64]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { byte[] output = cipher.update(buffer, 0, bytesRead); if (output != null) { outputStream.write(output); } } byte[] outputBytes = cipher.doFinal(); if (outputBytes != null) { outputStream.write(outputBytes); } inputStream.close(); outputStream.close(); } |
請注意,不建議嘗試將整個檔案(尤其是大檔案)讀入記憶體。相反,我們一次加密一個緩衝區。
為了解密檔案,我們使用類似的步驟,並使用DECRYPT_MODE初始化密碼,如前所述。
再次,讓我們定義一個用於加密和解密文字檔案的測試方法。在這種方法中,我們從測試資源目錄中讀取baeldung.txt檔案,將其加密為一個名為baeldung.encrypted的檔案,然後將該檔案解密為一個新檔案:
@Test void givenFile_whenEncrypt_thenSuccess() throws NoSuchAlgorithmException, IOException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException { SecretKey key = AESUtil.generateKey(128); String algorithm = "AES/CBC/PKCS5Padding"; IvParameterSpec ivParameterSpec = AESUtil.generateIv(); Resource resource = new ClassPathResource("inputFile/baeldung.txt"); File inputFile = resource.getFile(); File encryptedFile = new File("classpath:baeldung.encrypted"); File decryptedFile = new File("document.decrypted"); AESUtil.encryptFile(algorithm, key, ivParameterSpec, inputFile, encryptedFile); AESUtil.decryptFile( algorithm, key, ivParameterSpec, encryptedFile, decryptedFile); assertThat(inputFile).hasSameTextualContentAs(decryptedFile); } |
基於密碼加密解密
我們可以使用從給定密碼派生的金鑰進行AES加密和解密。
為了生成金鑰,我們使用getKeyFromPassword()方法。加密和解密步驟與字串輸入部分中顯示的步驟相同。然後,我們可以使用例項化的密碼和提供的金鑰來執行加密。
讓我們寫一個測試方法:
@Test void givenPassword_whenEncrypt_thenSuccess() throws InvalidKeySpecException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException { String plainText = "www.baeldung.com"; String password = "baeldung"; String salt = "12345678"; IvParameterSpec ivParameterSpec = AESUtil.generateIv(); SecretKey key = AESUtil.getKeyFromPassword(password,salt); String cipherText = AESUtil.encryptPasswordBased(plainText, key, ivParameterSpec); String decryptedCipherText = AESUtil.decryptPasswordBased( cipherText, key, ivParameterSpec); Assertions.assertEquals(plainText, decryptedCipherText); } |
加密物件
為了加密Java物件,我們需要使用SealedObject類。該物件應可序列化。讓我們從定義學生類開始:
public class Student implements Serializable { private String name; private int age; // standard setters and getters } |
接下來,讓我們加密Student物件:
public static SealedObject encryptObject(String algorithm, Serializable object, SecretKey key, IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException, IllegalBlockSizeException { Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, key, iv); SealedObject sealedObject = new SealedObject(object, cipher); return sealedObject; } |
稍後可以使用正確的密碼解密加密的物件:
public static Serializable decryptObject(String algorithm, SealedObject sealedObject, SecretKey key, IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, ClassNotFoundException, BadPaddingException, IllegalBlockSizeException, IOException { Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.DECRYPT_MODE, key, iv); Serializable unsealObject = (Serializable) sealedObject.getObject(cipher); return unsealObject; } |
讓我們寫一個測試用例:
@Test void givenObject_whenEncrypt_thenSuccess() throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException, IOException, BadPaddingException, ClassNotFoundException { Student student = new Student("Baeldung", 20); SecretKey key = AESUtil.generateKey(128); IvParameterSpec ivParameterSpec = AESUtil.generateIv(); String algorithm = "AES/CBC/PKCS5Padding"; SealedObject sealedObject = AESUtil.encryptObject( algorithm, student, key, ivParameterSpec); Student object = (Student) AESUtil.decryptObject( algorithm, sealedObject, key, ivParameterSpec); assertThat(student).isEqualToComparingFieldByField(object); } |
可以在GitHub上獲得本文的完整原始碼 。
相關文章
- AES加密解密加密解密
- AES 加密&解密加密解密
- JavaScript前端和Java後端的AES加密和解密JavaScript前端後端加密解密
- AES CBC 加密解密加密解密
- Python AES 加密和解密(qbit)Python加密解密
- golang AES-CBC 加密解密Golang加密解密
- python AES-CBC 加密解密Python加密解密
- AES位元組陣列加密解密流程陣列加密解密
- delphi加密C#解密(AES-256)加密C#解密
- AES線上加密解密-附AES128,192,256,CBC,CFB,ECB,OFB,PCBC各種加密解密原始碼加密解密原始碼
- app直播原始碼,android AES加密解密實現APP原始碼Android加密解密
- Python使用AES進行鹽值加密和解密Python加密解密
- 通過Go實現AES加密和解密工具Go加密解密
- android加密解密完美教程Android加密解密
- AES實現財務資料的加密解密儲存加密解密
- Python/Java AES 加解密方法互相轉換PythonJava解密
- AES加密加密
- 介面加密傳輸設計及AES加解密程式碼DEMO加密解密
- RSA der加密 p12解密以及配合AES使用詳解加密解密
- Java加密解密瞭解Java加密解密
- php中aes加密和rsa加密的區別PHP加密
- Golang AES加密Golang加密
- Windows10 VS2017 C++使用crypto++庫加密解密(AES)WindowsC++加密解密
- Vue使用AES加密Vue加密
- netcore AES同等效轉java語言 加密方法NetCoreJava加密
- Java 常用加密解密演算法Java加密解密演算法
- java書籍-《java加密解密的藝術》Java加密解密
- aes加密解密原始碼,含 128、192、256位,cbc、cfb、ecb、ofb、pcbc模式加密解密原始碼模式
- AES-CBC 模式加密模式加密
- AES加解密使用總結解密
- 加密解密加密解密
- [譯] 最佳安全實踐:在 Java 和 Android 中使用 AES 進行對稱加密JavaAndroid加密
- OpenSSL 使用AES對檔案加解密解密
- CryptoJs 使用 AES CBC 加解密資料JS解密
- VUE專案 AES加解密(小白版)Vue解密
- 記一次前端CryptoJS AES解密前端JS解密
- nodejs常用加密方式 RSA & AESNodeJS加密
- 逆向工程加密函式:AES加密函式