一文盤點五種最常用的Java加密算法
前言
大家平時的工作中,可能也在很多地方用到了加密、解密,比如:
用戶的密碼不能明文存儲,要存儲加密后的密文
用戶的銀行卡號、身份證號之類的敏感數(shù)據(jù),需要加密傳輸
還有一些重要接口,比如支付,客戶端要對請求生成一個簽名,服務(wù)端要對簽名進行驗證
……
那么上面提到的這些能力,我們都可以利用哪些加密算法來實現(xiàn)呢?咱們接著往下看。
常見加密算法
算法整體上可以分為不可逆加密,以及可逆加密,可逆加密又可以分為對稱加密和非對稱加密。

不可逆算法
不可逆加密的算法的加密是不可逆的,密文無法被還原成原文。
散列算法,就是一種不可逆算法。散列算法中,明文通過散列算法生成散列值,散列值是長度固定的數(shù)據(jù),和明文長度無關(guān)。

散列算法的具體實現(xiàn)有很多種,常見的包括MD5、SHA1、SHA-224、SHA-256等等。
散列算法常用于數(shù)字簽名、消息認證、密碼存儲等場景。
散列算法是不需要密鑰的,當(dāng)然也有一些不可逆算法,需要密鑰,例如HMAC算法。
MD5
MD5,全稱為“Message-Digest Algorithm 5”,翻譯過來叫“信息摘要算法”。它可以將任意長度的數(shù)據(jù)通過散列算法,生成一個固定長度的散列值。MD5算法的輸出長度為128位,通常用32個16進制數(shù)表示。
我們來看下MD5算法的Java代碼實現(xiàn):
public class MD5 {
private static final String MD5_ALGORITHM = "MD5";
public static String encrypt(String data) throws Exception {
// 獲取MD5算法實例
MessageDigest messageDigest = MessageDigest.getInstance(MD5_ALGORITHM);
// 計算散列值
byte[] digest = messageDigest.digest(data.getBytes());
Formatter formatter = new Formatter();
// 補齊前導(dǎo)0,并格式化
for (byte b : digest) {
formatter.format("%02x", b);
}
return formatter.toString();
}
public static void main(String[] args) throws Exception {
String data = "Hello World";
String encryptedData = encrypt(data);
System.out.println("加密后的數(shù)據(jù):" + encryptedData);
}
}MD5有一些優(yōu)點,比如計算速度快、輸出長度固定、應(yīng)用廣泛等等。
但是作為一個加密算法,它有一個天大的缺點,那就是不安全。
MD5算法已經(jīng)被攻破,而且MD5算法的輸出長度有限,攻擊者可以通過暴力破解或彩虹表攻擊等方式,找到與原始數(shù)據(jù)相同的散列值,從而破解數(shù)據(jù)。
雖然可以通過加鹽,也就是對在原文里再加上一些不固定的字符串來緩解,但是完全可以用更安全的SHA系列算法替代。
SHA-256
SHA(Secure Hash Algorithm)系列算法是一組密碼散列函數(shù),用于將任意長度的數(shù)據(jù)映射為固定長度的散列值。SHA系列算法由美國國家安全局(NSA)于1993年設(shè)計,目前共有SHA-1、SHA-2、SHA-3三種版本。
其中SHA-1系列存在缺陷,已經(jīng)不再被推薦使用。
SHA-2算法包括SHA-224、SHA-256、SHA-384和SHA-512四種散列函數(shù),分別將任意長度的數(shù)據(jù)映射為224位、256位、384位和512位的散列值。
我們來看一下最常用的SHA-256的Java代碼實現(xiàn):
public class SHA256 {
private static final String SHA_256_ALGORITHM = "SHA-256";
public static String encrypt(String data) throws Exception {
//獲取SHA-256算法實例
MessageDigest messageDigest = MessageDigest.getInstance(SHA_256_ALGORITHM);
//計算散列值
byte[] digest = messageDigest.digest(data.getBytes());
StringBuilder stringBuilder = new StringBuilder();
//將byte數(shù)組轉(zhuǎn)換為15進制字符串
for (byte b : digest) {
stringBuilder.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
}
return stringBuilder.toString();
}
public static void main(String[] args) throws Exception {
String data = "Hello World";
String encryptedData = encrypt(data);
System.out.println("加密后的數(shù)據(jù):" + encryptedData);
}
}SHA-2算法之所以比MD5強,主要有兩個原因:
- 散列值長度更長:例如SHA-256算法的散列值長度為256位,而MD5算法的散列值長度為128位,這就提高了攻擊者暴力破解或者彩虹表攻擊的難度。
- 更強的碰撞抗性:SHA算法采用了更復(fù)雜的運算過程和更多的輪次,使得攻擊者更難以通過預(yù)計算或巧合找到碰撞。
當(dāng)然,SHA-2也不是絕對安全的,散列算法都有被暴力破解或者彩虹表攻擊的風(fēng)險,所以,在實際的應(yīng)用中,加鹽還是必不可少的。
對稱加密算法
對稱加密算法,使用同一個密鑰進行加密和解密。

加密和解密過程使用的是相同的密鑰,因此密鑰的安全性至關(guān)重要。如果密鑰泄露,攻擊者可以輕易地破解加密數(shù)據(jù)。
常見的對稱加密算法包括DES、3DES、AES等。其中,AES算法是目前使用最廣泛的對稱加密算法之一,具有比較高的安全性和加密效率。
DES
DES(Data Encryption Standard)算法是一種對稱加密算法,由IBM公司于1975年研發(fā),是最早的一種廣泛應(yīng)用的對稱加密算法之一。
DES算法使用56位密鑰對數(shù)據(jù)進行加密,加密過程中使用了置換、替換、異或等運算,具有較高的安全性。
我們來看下DES算法的Java代碼實現(xiàn):
public class DES {
private static final String DES_ALGORITHM = "DES";
/**
* DES加密
*
* @param data 待加密的數(shù)據(jù)
* @param key 密鑰,長度必須為8位
* @return 加密后的數(shù)據(jù),使用Base64編碼
*/
public static String encrypt(String data, String key) throws Exception {
// 根據(jù)密鑰生成密鑰規(guī)范
KeySpec keySpec = new DESKeySpec(key.getBytes());
// 根據(jù)密鑰規(guī)范生成密鑰工廠
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
// 根據(jù)密鑰工廠和密鑰規(guī)范生成密鑰
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
// 根據(jù)加密算法獲取加密器
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
// 初始化加密器,設(shè)置加密模式和密鑰
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// 加密數(shù)據(jù)
byte[] encryptedData = cipher.doFinal(data.getBytes());
// 對加密后的數(shù)據(jù)進行Base64編碼
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* DES解密
*
* @param encryptedData 加密后的數(shù)據(jù),使用Base64編碼
* @param key 密鑰,長度必須為8位
* @return 解密后的數(shù)據(jù)
*/
public static String decrypt(String encryptedData, String key) throws Exception {
// 根據(jù)密鑰生成密鑰規(guī)范
KeySpec keySpec = new DESKeySpec(key.getBytes());
// 根據(jù)密鑰規(guī)范生成密鑰工廠
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
// 根據(jù)密鑰工廠和密鑰規(guī)范生成密鑰
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
// 對加密后的數(shù)據(jù)進行Base64解碼
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
// 根據(jù)加密算法獲取解密器
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
// 初始化解密器,設(shè)置解密模式和密鑰
cipher.init(Cipher.DECRYPT_MODE, secretKey);
// 解密數(shù)據(jù)
byte[] decryptedData = cipher.doFinal(decodedData);
// 將解密后的數(shù)據(jù)轉(zhuǎn)換為字符串
return new String(decryptedData);
}
public static void main(String[] args) throws Exception {
String data = "Hello World";
String key = "12345678";
String encryptedData = encrypt(data, key);
System.out.println("加密后的數(shù)據(jù):" + encryptedData);
String decryptedData = decrypt(encryptedData, key);
System.out.println("解密后的數(shù)據(jù):" + decryptedData);
}
}DES的算法速度較快,但是在安全性上面并不是最優(yōu)選擇,因為DES算法的密鑰長度比較短,被暴力破解和差分攻擊的風(fēng)險比較高,一般推薦用一些更安全的對稱加密算法,比如3DES、AES。
AES
AES(Advanced Encryption Standard)即高級加密標準,是一種對稱加密算法,被廣泛應(yīng)用于數(shù)據(jù)加密和保護領(lǐng)域。AES算法使用的密鑰長度為128位、192位或256位,比DES算法的密鑰長度更長,安全性更高。
我們來看下AES算法的Java代碼實現(xiàn):
public class AES {
private static final String AES_ALGORITHM = "AES";
// AES加密模式為CBC,填充方式為PKCS5Padding
private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";
// AES密鑰為16位
private static final String AES_KEY = "1234567890123456";
// AES初始化向量為16位
private static final String AES_IV = "abcdefghijklmnop";
/**
* AES加密
*
* @param data 待加密的數(shù)據(jù)
* @return 加密后的數(shù)據(jù),使用Base64編碼
*/
public static String encrypt(String data) throws Exception {
// 將AES密鑰轉(zhuǎn)換為SecretKeySpec對象
SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
// 將AES初始化向量轉(zhuǎn)換為IvParameterSpec對象
IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
// 根據(jù)加密算法獲取加密器
Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
// 初始化加密器,設(shè)置加密模式、密鑰和初始化向量
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
// 加密數(shù)據(jù)
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
// 對加密后的數(shù)據(jù)使用Base64編碼
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* AES解密
*
* @param encryptedData 加密后的數(shù)據(jù),使用Base64編碼
* @return 解密后的數(shù)據(jù)
*/
public static String decrypt(String encryptedData) throws Exception {
// 將AES密鑰轉(zhuǎn)換為SecretKeySpec對象
SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
// 將AES初始化向量轉(zhuǎn)換為IvParameterSpec對象
IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
// 根據(jù)加密算法獲取解密器
Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
// 初始化解密器,設(shè)置解密模式、密鑰和初始化向量
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
// 對加密后的數(shù)據(jù)使用Base64解碼
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
// 解密數(shù)據(jù)
byte[] decryptedData = cipher.doFinal(decodedData);
// 返回解密后的數(shù)據(jù)
return new String(decryptedData, StandardCharsets.UTF_8);
}
public static void main(String[] args) throws Exception {
String data = "Hello World";
String encryptedData = encrypt(data);
System.out.println("加密后的數(shù)據(jù):" + encryptedData);
String decryptedData = decrypt(encryptedData);
System.out.println("解密后的數(shù)據(jù):" + decryptedData);
}
}AES算法采用的密鑰長度更長,密鑰空間更大,安全性更高,能夠有效地抵抗暴力破解攻擊。
當(dāng)然,因為密鑰長度較長,需要的存儲也更多。
對于對稱加密算法而言,最大的痛點就在于密鑰管理困難,相比而言,非對稱加密就沒有這個擔(dān)憂。
非對稱加密算法
非對稱加密算法需要兩個密鑰,這兩個密鑰互不相同,但是相互匹配,一個稱為公鑰,另一個稱為私鑰。
使用其中的一個加密,則使用另一個進行解密。例如使用公鑰加密,則需要使用私鑰解密。

RSA
RSA算法是是目前應(yīng)用最廣泛的非對稱加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman三人在1978年發(fā)明,名字來源三人的姓氏首字母。
我們看下RSA算法的Java實現(xiàn):
public class RSA {
private static final String RSA_ALGORITHM = "RSA";
/**
* 生成RSA密鑰對
*
* @return RSA密鑰對
*/
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
keyPairGenerator.initialize(2048); // 密鑰大小為2048位
return keyPairGenerator.generateKeyPair();
}
/**
* 使用公鑰加密數(shù)據(jù)
*
* @param data 待加密的數(shù)據(jù)
* @param publicKey 公鑰
* @return 加密后的數(shù)據(jù)
*/
public static String encrypt(String data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* 使用私鑰解密數(shù)據(jù)
*
* @param encryptedData 加密后的數(shù)據(jù)
* @param privateKey 私鑰
* @return 解密后的數(shù)據(jù)
*/
public static String decrypt(String encryptedData, PrivateKey privateKey) throws Exception {
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedData = cipher.doFinal(decodedData);
return new String(decryptedData, StandardCharsets.UTF_8);
}
public static void main(String[] args) throws Exception {
KeyPair keyPair = generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String data = "Hello World";
String encryptedData = encrypt(data, publicKey);
System.out.println("加密后的數(shù)據(jù):" + encryptedData);
String decryptedData = decrypt(encryptedData, privateKey);
System.out.println("解密后的數(shù)據(jù):" + decryptedData);
}
}RSA算法的優(yōu)點是安全性高,公鑰可以公開,私鑰必須保密,保證了數(shù)據(jù)的安全性;可用于數(shù)字簽名、密鑰協(xié)商等多種應(yīng)用場景。
缺點是加密、解密速度較慢,密鑰長度越長,加密、解密時間越長;密鑰長度過短容易被暴力破解,密鑰長度過長則會增加計算量和存儲空間的開銷。
總結(jié)
這一期就給大家簡單盤點了一下最常用的5種加密算法。
其實,論到加密解密算法的應(yīng)用,有一個東西,可以說是應(yīng)用到了極致,它是什么呢?
—— HTTPS

我們簡單回憶一下HTTPS的工作流程,和用到的加密算法:
客戶端發(fā)起HTTPS請求:用戶使用瀏覽器輸入網(wǎng)址訪問HTTPS站點,準備發(fā)起HTTPS請求
服務(wù)端提供證書:服務(wù)器返回公鑰證書,證書包含了服務(wù)器的公鑰、頒發(fā)者(證書頒發(fā)機構(gòu))等信息
客戶端驗證證書:瀏覽器驗證證書的有效性、合法性、來源等,校驗證書的過程用到了非對稱加密和散列算法
- 客戶端使用證書頒發(fā)機構(gòu)的公鑰對證書進行驗證,保證證書的真實性和合法性
- 客戶端使用證書中的公鑰對服務(wù)端的數(shù)字簽名進行驗證,保證服務(wù)器的身份和數(shù)據(jù)的完整性。
- 客戶端使用散列算法計算出散列值,和證書種的散列值進行對比,保證證書的完整性
客戶端生成對稱密鑰:客戶端生成一個隨機數(shù),作為對稱密鑰
對稱密鑰加密傳輸:客戶端使用服務(wù)器的公鑰對隨機數(shù)進行加密,然后將加密后的信息傳輸給服務(wù)器
服務(wù)端獲取對稱密鑰:服務(wù)端使用私鑰解密客戶端發(fā)送的對稱密鑰,得到對稱密鑰
客戶端與服務(wù)器使用對稱密鑰進行通信:服務(wù)器與瀏覽器都使用對稱密鑰對數(shù)據(jù)進行加密和解密,以此確保數(shù)據(jù)傳輸?shù)陌踩浴?/p>
在數(shù)據(jù)傳輸?shù)倪^程中,也用到了散列算法:
消息摘要:在數(shù)據(jù)傳輸過程中,客戶端和服務(wù)器都使用散列算法計算消息的散列值,對方收到消息后,會對散列值進行比較,確保傳輸數(shù)據(jù)的完整性。
總之,HTTPS使用了對稱加密算法、非對稱加密算法、散列算法來保證數(shù)據(jù)的安全性和完整性,從而確保了通信雙方的身份和數(shù)據(jù)的安全。
至于具體使用哪些加密算法,取決于SSL/TLS協(xié)議的版本以及協(xié)商過程中選定的加密套件。在實際的網(wǎng)絡(luò)環(huán)境中,很多加密算法可能會被淘汰,以適應(yīng)更高安全性的需要。
在我們的日常開發(fā)中,也可以借鑒相應(yīng)的思路,靈活運用各種加密算法,讓我們的應(yīng)用更加安全、更加健壯。
以上就是一文盤點五種最常用的Java加密算法的詳細內(nèi)容,更多關(guān)于Java加密算法的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
MyBatis中的循環(huán)插入insert foreach問題
這篇文章主要介紹了MyBatis中的循環(huán)插入insert foreach問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
Spring 定時任務(wù)@Scheduled 注解中的 Cron 表達式詳解
Cron 表達式是一種用于定義定時任務(wù)觸發(fā)時間的字符串表示形式,它由七個字段組成,分別表示秒、分鐘、小時、日期、月份、星期和年份,這篇文章主要介紹了Spring 定時任務(wù)@Scheduled 注解中的 Cron 表達式,需要的朋友可以參考下2023-07-07
Spring?Data?JPA實現(xiàn)審計功能過程詳解
Spring?Data?JPA為跟蹤持久性層的變化提供了很好的支持。通過使用審核,我們可以存儲或記錄有關(guān)實體更改的信息,例如誰創(chuàng)建或更改了實體以及何時進行更改2023-02-02

