前言
我們數據庫中有一條用户信息的數據,需要給到第三方,那麼在發送這條數據的時候,我們不能直接把用户的姓名、電話號、身份證號等一些信息發給第三方,不能暴露用户的個人信息,這個時候就需要用到數據加密進行傳輸。
什麼是AES
AES(Advanced Encryption Standard,高級加密標準)是一種用於保護電子數據的對稱加密算法。在 HTTPS 協議中使用的 TLS(傳輸層安全協議)就使用了 AES 加密。具體加密流程如下:
名詞的作用和意義
- 明文P
沒有經過加密的數據。 - 密鑰k
用來加密明文的密碼,在對稱加密算法中,加密與解密的密鑰是相同的。密鑰為接收方與發送方協商產生,但不可以直接在網絡上傳輸,否則會導致密鑰泄漏,通常是通過非對稱加密算法加密密鑰,然後再通過網絡傳輸給對方,或者直接面對面商量密鑰。密鑰是絕對不可以泄漏的,否則會被攻擊者還原密文,竊取機密數據。 - AES加密函數
設AES加密函數為E,則 C = E(K, P),其中P為明文,K為密鑰,C為密文。也就是説,把明文P和密鑰K作為加密函數的參數輸入,則加密函數E會輸出密文C。 - 密文C *
經加密函數處理後的數據 - AES
設AES解密函數為D,則 P = D(K, C),其中C為密文,K為密鑰,P為明文。也就是説,把密文C和密鑰K作為解密函數的參數輸入,則解密函數會輸出明文P。
為什麼要用 AES 而不用其他加密算法?
- 安全性高:AES 使用多輪的替換和排列操作,使得密文在很大程度上脱離了原始數據的特徵。
- 靈活性強:AES 支持多種密鑰長度(128 位、192 位、256 位)。
相比之下,其他加密算法如 DES(Data Encryption Standard,數據加密標準)已經被認為不夠安全,容易被暴力破解;RSA 雖然安全性高,但效率較低且密鑰管理複雜,更多用於密鑰交換和數字簽名。
demo
user實體
@Data
public class User {
String name;
int age;
String contactPhone;
String idCard;
}
實例化後調用AES進行加密。
User user = new User();
user.setName("張三");
user.setAge(18);
user.setContactPhone("1824783xxxx");
user.setIdCard("430626xxxxxxxxxxxxxxx");
String encryptDate = AesService.encrypt(user, "MDEyMzQ1Njc4OWFiY2RlZg==");
System.out.println(encryptDate);
String decryptDate = AesService.decrypt(encryptDate, AesService.base64StringToKey("MDEyMzQ1Njc4OWFiY2RlZg=="));
System.out.println(decryptDate);
最終加密信息為:
TKGywGIVhcLjKil4muBh7ROAp430b7n2TUSKH491PuMwa6Z6RDKQubo9ClNxk+yn5LVTOuPOP9Tt2hGr6/q2X+sxEGqPZvb+Ez4joFKSB/uw5t9AHsAi3BPQlAGSrQJG
解密信息為:
{"name":"張三","age":18,"contactPhone":"1824783xxxx","idCard":"430626xxxxxxxxxxxxxxx"}
encrypt(Object o, String key) 方法。
第一個參數接收一個對象,然後將對象轉換成json字符串。
第二個參數接收加密的密鑰(以Base64編碼的字符串形式)。
public static String encrypt(Object o, String key) {
return AesService.encrypt(new Gson().toJson(o), AesService.base64StringToKey(key));
}
base64StringToKey(String base64Key) 方法。
將一個Base64編碼的字符串轉換為一個SecretKey對象。
public static SecretKey base64StringToKey(String base64Key) {
try {
// 將base64Key解碼為一個字節數組
byte[] data = Base64.getDecoder().decode(base64Key);
return new SecretKeySpec(data, 0, data.length, "AES");
} catch (Exception e) {
throw new KeyFormatException();
}
}
- data:密鑰的字節數據。
- 0:偏移量,從數據數組的起始位置開始使用。
- data.length:使用數據數組的全部長度。
-
"AES":表示加密算法。
encrypt(String input, SecretKey key) 方法。
將base64Key輸入字符串input進行加密, key則就是密鑰。
public static String encrypt(String input, SecretKey key) { try { //創建Cipher對象,並且指定算法為AES Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key); // doFinal執行加密操作 byte[] cipherText = cipher.doFinal(input.getBytes()); // 返回密文 return Base64.getEncoder().encodeToString(cipherText); } catch (Exception e) { throw new RuntimeException(e); } } ENCRYPT_MODE表明是此時是加密模式DECRYPT_MODE表明此時是解密模式
decrypt(String cipherText, SecretKey key)方法。
解密一個用Base64編碼的密文字符串cipherText, key則就是密鑰
public static String decrypt(String cipherText, SecretKey key) {
try {
Cipher cipher = Cipher.getInstance("AES");
//初始化解密模式
cipher.init(Cipher.DECRYPT_MODE, key);
//將cipherText解碼為字節數組
byte[] plainText = cipher.doFinal(Base64.getDecoder()
.decode(cipherText));
return new String(plainText);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
為什麼得到加密數據後,還要使用base64進行編碼呢?
- 二進制數據的表示:
AES生成的數據是二進制數據,這些數據通常包含非打印字符和控制字符。這些字符在許多場景下(例如在 JSON、XML、URL 中)不能直接顯示或傳輸,因為這些格式通常只支持文本字符集(如 ASCII 或 UTF-8)。 - 避免數據傳輸損壞:
許多傳輸協議(如 HTTP、SMTP 等)是基於文本的,直接發送或存儲二進制數據可能會導致數據損壞或被截斷,Base64 編碼是一種將二進制數據轉換為文本字符的編碼方式,它只使用 A-Z、a-z、0-9、+、/ 這 64 個字符(以及填充字符 =),所有這些字符都在文本協議和存儲系統中是安全的,因此不會被誤處理。 - 數據完整性:
一些傳輸協議可能會對數據做一些自動的修改或處理,例如去掉空格、替換特殊字符等。Base64 編碼保證了數據不會因為這些自動處理而被篡改,確保數據完整性。
例如:
一個簡單的字符串 "Hello, World!",你對它進行 AES 加密後,得到的二進制數據可能是:
[-66, 77, 127, -15, 70, 58, -7, -100, -44, -37, 78, 124, 82, -117, 122, 35]
這些值是二進制數據,無法以字符串形式表示。通過 Base64 編碼後,它們會變成:
vk1/8UY6+ZzU2058Uot6Iw==
這個結果是一個可打印的字符串,可以安全地在各種文本協議和存儲中傳輸和存儲。
所以使用 Base64 編碼來表示加密後的二進制數據是一種常見的做法,它保證了數據在各種應用場景中的兼容性和完整性,簡化了數據的傳輸和存儲。
參考資料:
https://blog.csdn.net/qq_28205153/article/details/55798628
希望這篇文章對你有一定幫助。