AES加密解密工具類封裝(AESUtil)


 

 

 
         
package club.codeapes.common.utils;

import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* @version V1.0
* @desc AES 加密工具類
*/
public class AESUtil {

private static final String KEY_ALGORITHM = "AES";
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默認的加密算法
//自定義密碼
private static final String ASSETS_DEV_PWD_FIELD = "xxxx";

public static String getAssetsDevPwdField() {
return ASSETS_DEV_PWD_FIELD;
}

/**
* AES 加密操作
*
* @param content 待加密內容
* @param password 加密密碼
* @return 返回Base64轉碼后的加密數據
*/
public static String encrypt(String content, String password) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 創建密碼器

byte[] byteContent = content.getBytes("utf-8");

cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化為加密模式的密碼器

byte[] result = cipher.doFinal(byteContent);// 加密

return Base64Utils.encodeToString(result);//通過Base64轉碼返回
} catch (Exception ex) {
Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
}

return null;
}

/**
* AES 解密操作
*
* @param content
* @param password
* @return
*/
public static String decrypt(String content, String password) {

try {
//實例化
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);

//使用密鑰初始化,設置為解密模式
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));

//執行操作
byte[] result = cipher.doFinal(Base64Utils.decodeFromString(content));
String s = new String(result, "utf-8");
return s;
} catch (Exception ex) {
ex.printStackTrace();
Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
}

return null;
}

/**
* 生成加密秘鑰
*
* @return
*/
private static SecretKeySpec getSecretKey(String password) {
//返回生成指定算法密鑰生成器的 KeyGenerator 對象
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(password.getBytes());
//AES 要求密鑰長度為 128
kg.init(128, random);
//生成一個密鑰
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 轉換為AES專用密鑰
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}

public static void main(String[] args) {
String origin = "my test string";
String encrypt = AESUtil.encrypt(origin, AESUtil.ASSETS_DEV_PWD_FIELD);
String decrypt = AESUtil.decrypt(encrypt, AESUtil.ASSETS_DEV_PWD_FIELD);
System.out.println(origin);
System.out.println(encrypt);
System.out.println(decrypt);
}

}
 

 

關於過程中,為什么可以用base64對產生的數組進行編碼,以及解碼。使用的時候可能產生異常:解密的字節數組必須是16的倍數

 

發現當把字節數組轉為字符串后,在把字符串.getBytes()獲得數組,發現兩個字節數組前后不一樣了

強調一下:new String(byte[]),和"str".getBytes(),兩個方法使用的編碼一樣,然后換成其他編碼也出現這樣情況

 

原因:

1. 為什么數組轉字符串,字符串然后轉數組會出現,前后兩個字節數組的值會不同,因為並不是每個字節數和編碼集上的字符都有對應關系,如果一個字節數在編碼集上沒有對應,編碼new String(byte[]) 后,往往解出來的會是一些亂碼無意義的符號:例如:��,

但是解碼的時候,�這個字符也是一個字符在編碼表中也有固定的字節數用來表示,所有解碼出來的值必定是編碼表中對應的值,除非你的字節數組中的字節數正好在編碼表中有對應的值,否則編碼,解碼后的字節數組會不一樣

誤區: 誤以為所有的字節數組都可以new String(),然后在通過String.getBytes()還原

2.再說這個異常報:解密的字節數組必須是16的倍數,這得從AES的原理說起,AES是把數據按16字節分組加密的,所有如果數組長度不是16的倍數會報錯

AES原理:AES是對數據按128位,也就是16個字節進行分組進行加密的,每次對一組數據加密需要運行多輪。而輸入密鑰的長度可以為128、192和256位,也就是16個字節、24個字節和32個字節,如果用戶輸入的密鑰長度不是這幾種長度,也會補成這幾種長度。無論輸入密鑰是多少字節,加密還是以16字節的數據一組來進行的,密鑰長度的不同僅僅影響加密運行的輪數。

 可以用base64對參生的數組進行編碼,然后在解碼,這樣不會像new String(byte[]),getBytes()那樣造成數組前后不一致,一開始,我看到大部分人都是用base64,我也只是以為多一層編碼看起來安全一些而已,沒想到base64對數組的處理是不會造成誤差的

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM