紀錄一下 Java 使用 AES (Advanced Encryption Standard) 加解密的範例程式碼:
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; public class AESTest { public static void main(String[] args) { try { String seedForRandom = "TestSeed"; String plaintext = "TestPlaintext"; KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); // 設定特定的隨機數種子, // 如隨機數種子不變,就會得到相同的隨機數, // 這裡相當於每次都使用同樣的金鑰 SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); secureRandom.setSeed(seedForRandom.getBytes("UTF-8")); //產生 AES 金鑰 keyGenerator.init(256, secureRandom); SecretKey secretKey = keyGenerator.generateKey(); SecretKey AES_secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES"); // 取得 AES 加解密器 Cipher cipher = Cipher.getInstance("AES"); //進行加密 cipher.init(Cipher.ENCRYPT_MODE, AES_secretKey); byte[] encryptedText_byteArray = cipher.doFinal(plaintext.getBytes("UTF-8")); String encryptedText = new String(encryptedText_byteArray, "UTF-8"); System.out.println(encryptedText); // W?\?? ??? U]? //對加密後的 byte[] 進行解密 (再取得一個新的 AES 加解密器來做) cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, AES_secretKey); byte[] decryptedText_byteArray = cipher.doFinal(encryptedText_byteArray); String decryptedText = new String(decryptedText_byteArray, "UTF-8"); System.out.println(decryptedText); // TestPlaintext //注意! //加密後的 byte[] (decryptedText_byteArray) 不能與 String 互轉, //會流失一些東西,即上述的 encryptedText 會有轉不回 decryptedText_byteArray 的情況, //如果直接拿 encryptedText 來解密會出錯,例如以下例子會產生如下錯誤: //javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher //cipher = Cipher.getInstance("AES"); //cipher.init(Cipher.DECRYPT_MODE, AES_secretKey); //byte[] decryptedText_byteArray2 = cipher.doFinal(encryptedText.getBytes("UTF-8")); // ==> Execption : javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher //如上所述,替代方案可使用 base64 編碼, //因為加密後的 byte[] (即 decryptedText_byteArray) 可用 base64 編碼來在 byte[] 和 String 之間互轉, //如下所示: String base64Encoded_encryptedTextcryptedText = Base64.encodeBase64String(encryptedText_byteArray); System.out.println(base64Encoded_encryptedTextcryptedText); // V79c5vQIIP/R2wcWCVVdqA== cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, AES_secretKey); byte[] decryptedText_byteArray2 = cipher.doFinal(Base64.decodeBase64(base64Encoded_encryptedTextcryptedText)); String decryptedText2 = new String(decryptedText_byteArray2, "UTF-8"); System.out.println(decryptedText2); // TestPlaintext } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidKeyException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalBlockSizeException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BadPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
參考: