java中常用的幾種加密方式舉例詳解
一、介紹
在 Java 開發(fā)中,加密方式主要分為 對(duì)稱加密、非對(duì)稱加密、哈希算法(摘要算法) 三大類,各自有不同的應(yīng)用場(chǎng)景(如數(shù)據(jù)傳輸、存儲(chǔ)加密、簽名驗(yàn)證等)。
二、哈希算法(摘要算法)
特點(diǎn):
- 不可逆(無法從摘要反推原始數(shù)據(jù));
- 相同輸入必然得到相同輸出,不同輸入大概率得到不同輸出(抗碰撞);
- 輸出長(zhǎng)度固定(與輸入長(zhǎng)度無關(guān));
- 主要用于 數(shù)據(jù)完整性校驗(yàn)(如文件校驗(yàn))、密碼存儲(chǔ)(如用戶密碼加密存儲(chǔ))。
常用算法及實(shí)現(xiàn):
1. MD5(Message-Digest Algorithm 5)
- 輸出長(zhǎng)度:128 位(16 字節(jié),通常轉(zhuǎn) 32 位十六進(jìn)制字符串);
- 特點(diǎn):速度快,但安全性較低(已被破解,存在碰撞風(fēng)險(xiǎn));
- 適用場(chǎng)景:非敏感數(shù)據(jù)的完整性校驗(yàn)(如文件校驗(yàn)),不推薦用于密碼存儲(chǔ)。
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Utils {
public static String md5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes()); // 生成摘要字節(jié)數(shù)組
// 轉(zhuǎn)16進(jìn)制字符串
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b)); // 02x確保不足兩位補(bǔ)0
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5算法不存在", e);
}
}
public static void main(String[] args) {
System.out.println(md5("123456")); // 輸出:e10adc3949ba59abbe56e057f20f883e
}
}2. SHA 系列(Secure Hash Algorithm)
- 包括 SHA-1(160 位)、SHA-256(256 位)、SHA-512(512 位)等;
- 特點(diǎn):安全性比 MD5 高,SHA-256/SHA-512 抗碰撞性強(qiáng),速度略慢于 MD5;
- 適用場(chǎng)景:敏感數(shù)據(jù)的完整性校驗(yàn)、密碼存儲(chǔ)(推薦 SHA-256 + 鹽值)。
public class SHA256Utils {
public static String sha256(String input) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(input.getBytes());
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-256算法不存在", e);
}
}
public static void main(String[] args) {
System.out.println(sha256("123456")); // 輸出:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c9
}
}3. 加鹽哈希(Salted Hash)
- 問題:純哈希算法存在 “彩虹表破解” 風(fēng)險(xiǎn)(通過預(yù)計(jì)算的哈希值反查原始密碼);
- 解決:給原始數(shù)據(jù)添加 隨機(jī)鹽值(Salt) 后再哈希,鹽值需與哈希結(jié)果一起存儲(chǔ);
- 推薦方案:使用
PBKDF2、BCrypt、Argon2(Java 需引入第三方庫如spring-security-crypto)。
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class BCryptUtils {
private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
// 加密(自動(dòng)生成鹽值)
public static String encrypt(String password) {
return encoder.encode(password);
}
// 校驗(yàn)(自動(dòng)提取鹽值比對(duì))
public static boolean verify(String password, String encryptedPassword) {
return encoder.matches(password, encryptedPassword);
}
public static void main(String[] args) {
String pwd = "123456";
String encrypted = encrypt(pwd);
System.out.println("加密后:" + encrypted); // 格式如 $2a$10$xxx...(包含鹽值)
System.out.println("校驗(yàn)結(jié)果:" + verify(pwd, encrypted)); // true
}
}所引入的依賴(Maven):
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
<version>5.7.3</version>
</dependency>三、對(duì)稱加密
特點(diǎn):
- 加密和解密使用 同一個(gè)密鑰(對(duì)稱密鑰);
- 速度快、效率高,適合 大量數(shù)據(jù)加密(如文件加密、數(shù)據(jù)庫字段加密);
- 缺點(diǎn):密鑰傳輸和存儲(chǔ)風(fēng)險(xiǎn)高(需安全通道傳輸密鑰)。
常用算法及實(shí)現(xiàn):
1. AES(Advanced Encryption Standard)
- 替代 DES 的標(biāo)準(zhǔn)算法,安全性高、速度快;
- 密鑰長(zhǎng)度:128 位(默認(rèn))、192 位、256 位(需 JCE 無限制權(quán)限文件);
- 模式:ECB(不推薦,無 IV)、CBC(需 IV 向量,推薦)、GCM(帶認(rèn)證,更安全);
- 填充方式:PKCS5Padding(常用)。
public class AESUtils {
// 密鑰(16字節(jié)=128位,24字節(jié)=192位,32字節(jié)=256位)
private static final String KEY = "1234567890abcdef"; // 16字節(jié)
// IV向量(CBC模式必需,16字節(jié),需與密鑰長(zhǎng)度一致)
private static final String IV = "abcdef9012345678";
// 算法/模式/填充
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
// 加密
public static String encrypt(String input) {
try {
SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(input.getBytes());
return Base64.getEncoder().encodeToString(encrypted); // 轉(zhuǎn)Base64方便存儲(chǔ)傳輸
} catch (Exception e) {
throw new RuntimeException("AES加密失敗", e);
}
}
// 解密
public static String decrypt(String encryptedInput) {
try {
SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = Base64.getDecoder().decode(encryptedInput);
byte[] decrypted = cipher.doFinal(encrypted);
return new String(decrypted);
} catch (Exception e) {
throw new RuntimeException("AES解密失敗", e);
}
}
public static void main(String[] args) {
String input = "Hello AES!";
String encrypted = encrypt(input);
System.out.println("加密后:" + encrypted);
String decrypted = decrypt(encrypted);
System.out.println("解密后:" + decrypted); // Hello AES!
}
}2. DES / 3DES
- DES:密鑰長(zhǎng)度 56 位,安全性低,已淘汰;
- 3DES:使用 3 個(gè) DES 密鑰(168 位),兼容性強(qiáng),但速度慢;
- 推薦優(yōu)先使用 AES。
四、非對(duì)稱加密
特點(diǎn):
- 生成一對(duì)密鑰:公鑰(公開) 和 私鑰(保密);
- 公鑰加密的數(shù)據(jù)只能用私鑰解密,私鑰加密的數(shù)據(jù)只能用公鑰解密;
- 速度慢、效率低,適合 小量數(shù)據(jù)加密(如對(duì)稱密鑰傳輸、數(shù)字簽名);
- 優(yōu)點(diǎn):無需安全通道傳輸密鑰(公鑰可公開)。
常用算法及實(shí)現(xiàn):
1. RSA
- 應(yīng)用最廣泛的非對(duì)稱加密算法;
- 密鑰長(zhǎng)度:1024 位(安全性不足)、2048 位(推薦)、4096 位(更安全但速度慢);
- 適用場(chǎng)景:密鑰交換(如 AES 密鑰用 RSA 加密傳輸)、數(shù)字簽名、小數(shù)據(jù)加密。
public class RSAUtils {
// 密鑰對(duì)(實(shí)際開發(fā)中需提前生成并存儲(chǔ),不硬編碼)
private static KeyPair keyPair;
static {
try {
// 生成RSA密鑰對(duì)(2048位)
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
keyPair = generator.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("RSA密鑰對(duì)生成失敗", e);
}
}
// 獲取公鑰(Base64編碼)
public static String getPublicKey() {
return Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
}
// 獲取私鑰(Base64編碼)
public static String getPrivateKey() {
return Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
}
// 公鑰加密
public static String encryptByPublicKey(String input, String publicKeyStr) {
try {
// 解碼公鑰
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
// 加密(RSA加密長(zhǎng)度有限制,2048位密鑰最多加密245字節(jié))
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encrypted = cipher.doFinal(input.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
throw new RuntimeException("RSA公鑰加密失敗", e);
}
}
// 私鑰解密
public static String decryptByPrivateKey(String encryptedInput, String privateKeyStr) {
try {
// 解碼私鑰
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// 解密
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] encrypted = Base64.getDecoder().decode(encryptedInput);
byte[] decrypted = cipher.doFinal(encrypted);
return new String(decrypted);
} catch (Exception e) {
throw new RuntimeException("RSA私鑰解密失敗", e);
}
}
public static void main(String[] args) {
String input = "AES密鑰1234567890abcdef"; // 小數(shù)據(jù)示例
String publicKey = getPublicKey();
String privateKey = getPrivateKey();
System.out.println("公鑰:" + publicKey);
System.out.println("私鑰:" + privateKey);
String encrypted = encryptByPublicKey(input, publicKey);
System.out.println("公鑰加密后:" + encrypted);
String decrypted = decryptByPrivateKey(encrypted, privateKey);
System.out.println("私鑰解密后:" + decrypted); // AES密鑰1234567890abcdef
}
}2. ECC(Elliptic Curve Cryptography)
- 基于橢圓曲線數(shù)學(xué),相同安全性下,密鑰長(zhǎng)度遠(yuǎn)小于 RSA(如 256 位 ECC ≈ 3072 位 RSA);
- 速度快、占用資源少,適合移動(dòng)設(shè)備、物聯(lián)網(wǎng)等場(chǎng)景;
- Java 支持(需 JDK 1.7+),但使用較少,推薦在資源受限場(chǎng)景使用。
五、數(shù)字簽名(非對(duì)稱加密的延伸)
特點(diǎn):
- 用于 身份認(rèn)證 和 數(shù)據(jù)完整性校驗(yàn)(防止數(shù)據(jù)篡改和偽造);
- 原理:發(fā)送方用 私鑰 對(duì)數(shù)據(jù)摘要簽名,接收方用 公鑰 驗(yàn)證簽名。
常用算法:RSA-SHA256、ECDSA
public class SignatureUtils {
private static final String ALGORITHM = "SHA256withRSA"; // RSA+SHA256簽名
// 私鑰簽名
public static String sign(String data, String privateKeyStr) {
try {
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Signature signature = Signature.getInstance(ALGORITHM);
signature.initSign(privateKey);
signature.update(data.getBytes());
byte[] signBytes = signature.sign();
return Base64.getEncoder().encodeToString(signBytes);
} catch (Exception e) {
throw new RuntimeException("簽名失敗", e);
}
}
// 公鑰驗(yàn)簽
public static boolean verify(String data, String signStr, String publicKeyStr) {
try {
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(ALGORITHM);
signature.initVerify(publicKey);
signature.update(data.getBytes());
byte[] signBytes = Base64.getDecoder().decode(signStr);
return signature.verify(signBytes);
} catch (Exception e) {
throw new RuntimeException("驗(yàn)簽失敗", e);
}
}
public static void main(String[] args) {
String data = "需要簽名的數(shù)據(jù)";
String privateKey = RSAUtils.getPrivateKey(); // 復(fù)用RSA密鑰對(duì)
String publicKey = RSAUtils.getPublicKey();
String sign = sign(data, privateKey);
System.out.println("簽名:" + sign);
boolean verifyResult = verify(data, sign, publicKey);
System.out.println("驗(yàn)簽結(jié)果:" + verifyResult); // true
// 篡改數(shù)據(jù)后驗(yàn)簽
boolean fakeVerify = verify(data + "篡改", sign, publicKey);
System.out.println("篡改后驗(yàn)簽結(jié)果:" + fakeVerify); // false
}
}六、常用加密方式選型建議
| 實(shí)際業(yè)務(wù)場(chǎng)景 | 推薦加密方式 | 使用原因 |
|---|---|---|
| 用戶密碼存儲(chǔ) | BCrypt/PBKDF2 | 不可逆、加鹽、防彩虹表破解 |
| 數(shù)據(jù)庫敏感字段(手機(jī)號(hào) / 身份證) | AES-256-CBC/GCM | 可逆、速度快、適合短文本 |
| 大文件加密(合同 / 報(bào)表) | AES-256-GCM | 速度快、帶認(rèn)證、防篡改 |
| 客戶端 - 服務(wù)器密鑰傳輸 | RSA-2048 | 公鑰公開、私鑰保密、無需安全通道 |
| 第三方接口調(diào)用(防篡改 / 身份認(rèn)證) | RSA-SHA256 數(shù)字簽名 | 驗(yàn)證身份、防止數(shù)據(jù)篡改和重放攻擊 |
| 數(shù)據(jù)完整性校驗(yàn)(文件校驗(yàn)) | SHA-256 | 不可逆、相同輸入固定輸出 |
七、注意
- 密鑰管理:避免硬編碼密鑰,使用配置中心、密鑰倉(cāng)庫(如 Vault)存儲(chǔ);
- 算法選擇:淘汰 MD5、DES、RSA-1024 等弱算法,優(yōu)先選擇 AES-256、RSA-2048+、SHA-256+;
- 填充和模式:AES 避免使用 ECB 模式,推薦 CBC(需隨機(jī) IV)或 GCM(帶認(rèn)證);
- 鹽值:密碼存儲(chǔ)必須加鹽,鹽值需隨機(jī)且唯一(如 BCrypt 自動(dòng)生成);
- 權(quán)限:AES-256 需 JCE 無限制權(quán)限文件(JDK 8u161+ 默認(rèn)開啟)。
八、補(bǔ)充
1.什么是碰撞風(fēng)險(xiǎn)?
兩個(gè)不同的輸入數(shù)據(jù)(明文),經(jīng)過加密 / 哈希計(jì)算后,得到了相同的輸出結(jié)果(密文 / 摘要) —— 這種 “不同輸入→相同輸出” 的現(xiàn)象被稱為 “哈希碰撞”,而碰撞風(fēng)險(xiǎn)就是這種現(xiàn)象發(fā)生的概率及帶來的安全隱患。
舉個(gè)簡(jiǎn)單的例子:
哈希算法就像一臺(tái) “壓縮機(jī)器”,無論輸入的是一張 10GB 的電影、一段文字,還是一個(gè)數(shù)字,都會(huì)被壓縮成固定長(zhǎng)度的 “壓縮包”(摘要)。正常情況下,不同輸入應(yīng)該對(duì)應(yīng)不同壓縮包,但如果出現(xiàn) “兩個(gè)完全不同的文件,壓縮后得到一模一樣的壓縮包”,這就是 “碰撞”;而 “碰撞風(fēng)險(xiǎn)” 就是你擔(dān)心這種情況發(fā)生的概率,以及如果發(fā)生會(huì)造成什么問題。
本質(zhì):數(shù)學(xué)底層原因:“鴿巢原理”
哈希算法的輸出長(zhǎng)度是固定的(比如 MD5 輸出 128 位,SHA-256 輸出 256 位),而輸入數(shù)據(jù)的可能性是無限的(比如任意長(zhǎng)度的字符串、文件)。
這就像:用 100 個(gè)鴿巢(固定輸出)容納無限多的鴿子(輸入數(shù)據(jù))—— 無論鴿巢再多,最終必然會(huì)有 “多只鴿子擠同一個(gè)鴿巢” 的情況,這就是數(shù)學(xué)上的 “鴿巢原理”,也是碰撞風(fēng)險(xiǎn)存在的根本原因。
常見場(chǎng)景舉例:
數(shù)字簽名場(chǎng)景(非對(duì)稱加密 + 哈希)
數(shù)字簽名的核心是 “用私鑰對(duì)數(shù)據(jù)摘要簽名,公鑰驗(yàn)簽”:
- 若哈希算法存在碰撞風(fēng)險(xiǎn),攻擊者可找到兩個(gè)不同數(shù)據(jù)(比如 “轉(zhuǎn)賬 0.01 元” 和 “轉(zhuǎn)賬 10000 元”),其摘要相同;
- 攻擊者誘導(dǎo)用戶對(duì) “轉(zhuǎn)賬 0.01元” 簽名,然后將簽名用于 “轉(zhuǎn)賬 10000 元” 的請(qǐng)求中,服務(wù)端驗(yàn)簽時(shí)因摘要相同而通過,造成用戶財(cái)產(chǎn)損失。
2.什么是鹽值?
鹽值(Salt)是一串隨機(jī)生成、與原始數(shù)據(jù)(如密碼)結(jié)合后再進(jìn)行哈希計(jì)算的字符串—— 它就像烹飪時(shí)加的 “調(diào)味料”,相同的食材(原始密碼)加不同的 “調(diào)味料”(鹽值),會(huì)得到完全不同的 “成品”(哈希摘要)。
舉個(gè)例子:
用戶注冊(cè)(加密存儲(chǔ))
- 用戶輸入明文密碼:
123456aB!; - 系統(tǒng)生成隨機(jī)鹽值:
f8d2e1c3b4a59607(16 字節(jié)); - 計(jì)算哈希:
SHA-256(密碼 + 鹽值)→ 得到摘要8d969eef...; - 存儲(chǔ)結(jié)果:將 “鹽值 + 哈希摘要” 一起存入數(shù)據(jù)庫(如拼接為
f8d2e1c3b4a59607:8d969eef...)。
常見誤區(qū):
- 鹽值需要保密?→ 可以不需要,鹽值的作用是 “破壞哈希固定性”,而非 “加密”,必須明文存儲(chǔ)才能校驗(yàn);
- 鹽值可以重復(fù)使用?→ 不推薦,同一系統(tǒng)中鹽值重復(fù)會(huì)降低安全性,建議每個(gè)用戶 / 每次修改密碼都生成新鹽值;
- 用用戶 ID、手機(jī)號(hào)當(dāng)鹽值?→ 不推薦,這類值可預(yù)測(cè),攻擊者可針對(duì)特定用戶生成定制彩虹表,破解難度大幅降低;
- 鹽值越長(zhǎng)越好?→ 不是,16 字節(jié)(128 位)已足夠安全,過長(zhǎng)的鹽值會(huì)增加存儲(chǔ)和計(jì)算成本,性價(jià)比極低。
使用原則:鹽值必須 “隨機(jī)、唯一、足夠長(zhǎng)”,且明文存儲(chǔ)。
簡(jiǎn)單場(chǎng)景:可手動(dòng)用 SecureRandom 生成鹽值,搭配 SHA-256 使用;
實(shí)際開發(fā)場(chǎng)景:優(yōu)先使用 BCrypt、PBKDF2 等自動(dòng)加鹽算法,無需關(guān)注鹽值的生成和存儲(chǔ),安全性更高、使用更高效。
3.什么是彩虹表?
彩虹表(Rainbow Table)是一種預(yù)計(jì)算的、包含海量 “明文→哈希值” 映射關(guān)系的數(shù)據(jù)庫
舉個(gè)例子:
裸哈希場(chǎng)景:MD5("123456") = e10adc3949ba59abbe56e057f20f883e;
彩虹表中會(huì)提前存儲(chǔ) e10adc3949ba59abbe56e057f20f883e → 123456 這個(gè)映射關(guān)系;
攻擊者從數(shù)據(jù)庫拿到該哈希值后,查詢彩虹表,1 秒內(nèi)就能得到明文 “123456”。
4.什么是 JCE 無限制權(quán)限文件?(Java 加密的 “權(quán)限解鎖包”)
JCE(Java Cryptography Extension,Java 加密擴(kuò)展)是 Java 平臺(tái)提供的一套加密相關(guān) API 和算法實(shí)現(xiàn)(如 AES、RSA 等)。而 JCE 無限制權(quán)限文件(Unlimited Strength Jurisdiction Files),是用來解除 Java 對(duì) “強(qiáng)加密算法”(如 AES-256、RSA-4096)密鑰長(zhǎng)度限制的補(bǔ)丁文件
為什么需要 “解鎖”?
早年由于國(guó)際加密技術(shù)出口管制政策(部分國(guó)家限制高強(qiáng)度加密算法出口),Oracle JDK 默認(rèn)內(nèi)置了 “受限的 JCE 策略文件”,對(duì)加密算法的密鑰長(zhǎng)度做了嚴(yán)格限制:
- AES 密鑰長(zhǎng)度最多只能用 128 位(AES-128),無法使用更安全的 192 位、256 位;
- 其他算法(如 3DES、RC2)也有類似的密鑰長(zhǎng)度限制。
JCE 無限制權(quán)限文件的適用范圍:
| JDK 版本 | 是否需要手動(dòng)安裝? | 說明 |
|---|---|---|
| JDK 1.7 及以下 | 是(必須手動(dòng)安裝) | 需下載對(duì)應(yīng)版本的無限制策略文件,替換系統(tǒng)文件 |
| JDK 1.8(8u161 之前) | 是(需手動(dòng)安裝) | 8u161 是關(guān)鍵版本,之后默認(rèn)解鎖 |
| JDK 1.8u161 及以上 | 否(默認(rèn)解鎖) | 無需手動(dòng)操作,直接支持強(qiáng)加密算法 |
| JDK 9 及以上(JDK 11/17) | 否(默認(rèn)解鎖) | 徹底移除了 JCE 策略限制,原生支持強(qiáng)加密 |
注意:OpenJDK(如 AdoptOpenJDK、Eclipse Temurin)默認(rèn)無此限制(從誕生起就支持強(qiáng)加密),只有 Oracle JDK 存在歷史限制 —— 這也是很多項(xiàng)目選擇 OpenJDK 的原因之一。
5.什么是IV/IV向量?
IV 向量(Initialization Vector,初始化向量),本質(zhì)就是對(duì)稱加密算法(如 AES、DES)中,用于初始化加密流程的一串固定長(zhǎng)度隨機(jī)字節(jié)數(shù)組—— 它不是密鑰,也無需保密,核心作用是讓 “相同明文 + 相同密鑰” 產(chǎn)生不同密文,破壞密文的規(guī)律性,抵御攻擊。
可以把它理解為:對(duì)稱加密的 “隨機(jī)啟動(dòng)參數(shù)”—— 就像用同一臺(tái)打印機(jī)(密鑰)打印同一篇文檔(明文),每次用不同的 “打印設(shè)置參數(shù)”(IV 向量),最終打印出的 “成品”(密文)會(huì)完全不同,避免攻擊者通過重復(fù)密文推斷明文。
對(duì)稱加密若沒有 IV 向量(如 AES-ECB 模式),會(huì)存在致命缺陷:相同明文 → 相同密文 ,即使明文和密鑰完全相同,只要 IV 向量不同,最終密文就不同,攻擊者無法通過密文的重復(fù)性推斷明文,加密安全性大幅提升。
IV 向量的適用場(chǎng)景
| 加密模式 | 是否需要 IV 向量 | 說明 | 推薦度 |
|---|---|---|---|
| ECB(電子密碼本模式) | 不需要 | 無 IV,相同明文→相同密文,易被破解 | 不推薦使用 |
| CBC(密碼分組鏈接模式) | 需要 | 依賴 IV 啟動(dòng)加密,IV 隨機(jī)即可,兼容性好 | 推薦(常用) |
| GCM(伽羅瓦 / 計(jì)數(shù)器模式) | 需要 | 不僅需要 IV,還自帶 “認(rèn)證標(biāo)簽”(防篡改),IV 推薦 12 字節(jié)(最優(yōu)實(shí)踐) | 推薦(更安全) |
| CTR(計(jì)數(shù)器模式) | 需要 | IV 作為計(jì)數(shù)器初始值,需保證同一密鑰下不重復(fù) | 可選(適合流式數(shù)據(jù)) |
誤區(qū):
- IV 向量是密鑰? → 并不是,IV 僅用于初始化加密,無需保密;密鑰是加密核心,必須嚴(yán)格保密(如用密鑰倉(cāng)庫存儲(chǔ))。
- 用固定 IV 更方便? → 不建議,固定 IV 會(huì)讓相同明文的密文一致,攻擊者可通過密文規(guī)律破解,完全失去 IV 的意義。
- IV 越長(zhǎng)越安全? → IV 長(zhǎng)度必須與算法塊大小一致(AES 固定 16 字節(jié)),過長(zhǎng) / 過短都會(huì)報(bào)錯(cuò),且不會(huì)提升安全性。
- IV 可以重復(fù)使用? → 同一密鑰下重復(fù)使用 IV 會(huì)導(dǎo)致密文被破解(如 CBC 模式的 “重放攻擊” 漏洞)。
- IV 需要加密存儲(chǔ)? → IV 可隨密文公開傳輸 / 存儲(chǔ)(如拼接在密文前),解密時(shí)必須提取原始 IV 才能還原明文。
總結(jié)
到此這篇關(guān)于java中常用的幾種加密方式的文章就介紹到這了,更多相關(guān)java加密方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合clickhouse配置多分片地址的示例詳解
這篇文章主要為大家詳細(xì)介紹了SpringBoot整合clickhouse配置多分片地址的相關(guān)方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-10-10
關(guān)于重寫equals()方法和hashCode()方法及其簡(jiǎn)單的應(yīng)用
這篇文章主要介紹了關(guān)于重寫equals()方法和hashCode()方法及其簡(jiǎn)單的應(yīng)用,網(wǎng)上的知識(shí)有些可能是錯(cuò)誤的,關(guān)于?equals()?方法的理解,大家討論不一樣,需要的朋友可以參考下2023-04-04
springboot + rabbitmq 如何實(shí)現(xiàn)消息確認(rèn)機(jī)制(踩坑經(jīng)驗(yàn))
這篇文章主要介紹了springboot + rabbitmq 如何實(shí)現(xiàn)消息確認(rèn)機(jī)制,本文給大家分享小編實(shí)際開發(fā)中的一點(diǎn)踩坑經(jīng)驗(yàn),內(nèi)容簡(jiǎn)單易懂,需要的朋友可以參考下2020-07-07
Spring Cloud下實(shí)現(xiàn)用戶鑒權(quán)的方案
Java下常用的安全框架主要有Spring Security和shiro,都可提供非常強(qiáng)大的功能,但學(xué)習(xí)成本較高。但在微服務(wù)下鑒權(quán)又會(huì)對(duì)服務(wù)有一定的入侵性。 因此,本文將介紹Spring Cloud下實(shí)現(xiàn)用戶鑒權(quán)的方案,感興趣的同學(xué)可以關(guān)注一下2021-11-11
openEuler?搭建java開發(fā)環(huán)境的詳細(xì)過程
這篇文章主要介紹了openEuler?搭建java開發(fā)環(huán)境,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
SpringCloud如何創(chuàng)建一個(gè)服務(wù)提供者provider
這篇文章主要介紹了SpringCloud如何創(chuàng)建一個(gè)服務(wù)提供者provider,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07

