原理不難,但是要清楚自己用的什麼加密模式,本文用的CBC模式。
看CSDN的估計也沒人去糾結原理,直接上代碼。
package AES;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.UUID;
/**
* 本文中使用AES的最大秘鑰,32位元組=256位
*/
public class AES {
/**
* 生成秘鑰,傳回BASE64 處理之後的密鑰字元串
*/
public static String generateAESKey(){
UUID uuid = UUID.randomUUID();
String aesKey = Base64.getEncoder().encodeToString(uuid.toString().getBytes()).substring(2,34);
return aesKey;
}
/**
* 獲得一個初始化向量,傳回長度為16位元組大小的BASE64編碼字元串
* 至于為何要這個iv向量,因為本文使用的是CBC模式
*/
public static String generateAESIv(){
UUID uuid = UUID.randomUUID();
String iv = Base64.getEncoder().encodeToString(uuid.toString().getBytes()).substring(2,18);
return iv;
}
/**
* 加密
* @param content 待加密内容
* @param secretKeyStr 加密使用的 AES 密鑰,BASE64 編碼後的字元串
* @param iv 初始化向量,長度為 16 個位元組
* @return 加密後的密文,進行 BASE64 處理之後傳回
*/
public static String encryptAES(byte[] content, String secretKeyStr, String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
// 獲得一個加密規則 SecretKeySpec
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyStr.getBytes(), "AES");
// 獲得加密算法執行個體對象 Cipher
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //"算法/模式/補碼方式"
// 獲得一個 IvParameterSpec
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes()); // 使用 CBC 模式,需要一個向量 iv, 可增加加密算法的強度
// 根據參數初始化算法
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
// 執行加密并傳回經 BASE64 處助理之後的密文
return Base64.getEncoder().encodeToString(cipher.doFinal(content));
}
/**
* 解密
* @param content: 待解密内容,是 BASE64 編碼後的位元組數組
* @param secretKeyStr: 解密使用的 AES 密鑰,BASE64 編碼後的字元串
* @param iv: 初始化向量,長度 16 位元組,16*8 = 128 位
* @return 解密後的明文,直接傳回經 UTF-8 編碼轉換後的明文
*/
public static String decryptAES(byte[] content, String secretKeyStr, String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, UnsupportedEncodingException {
// 密文進行 BASE64 解密處理
byte[] contentDecByBase64 = Base64.getDecoder().decode(content);
// 獲得一個 SecretKeySpec
// SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(secretKeyStr), "AES");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyStr.getBytes(), "AES");
// 獲得加密算法執行個體對象 Cipher
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //"算法/模式/補碼方式"
// 獲得一個初始化 IvParameterSpec
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
// 根據參數初始化算法
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
// 解密
return new String(cipher.doFinal(contentDecByBase64), "utf8");
}
public static void main(String[] args) throws NoSuchPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
//原文
String context = "當我們建立一個node項目,意味着建立一個module子產品,這個子產品的描述檔案,叫package.json。";
//秘鑰
String key = generateAESKey();
//向量
String iv = generateAESIv();
//加密
String encryptContext = encryptAES(context.getBytes(),key,iv);
//解密
String decryptContext = decryptAES(encryptContext.getBytes(),key,iv);
System.out.println("原文:"+context);
System.out.println("密文:"+encryptContext);
System.out.println("解密文:"+decryptContext);
}
}
測試結果:注意,秘鑰以及向量每次都是随機的,是以加密後的密文每次都會不一樣。然後就産生了秘鑰保管的問題。