在Java开发中,加密是保障数据安全的核心手段,常用的加密方式主要分为对称加密和非对称加密。很多开发者刚接触时会混淆两者的用法,这篇文章就用通俗的语言讲清它们的区别、适用场景,再附上可直接复用的工具类,新手也能快速上手。
加密算法工具类
一、核心区别:一张表看懂
| 对比维度 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥特点 | 加密和解密用同一把密钥(密钥需严格保密) | 用公钥+私钥成对工作(公钥可公开,私钥必须保密) |
| 加密效率 | 速度极快(适合大数据量加密) | 速度较慢(数学运算复杂,适合小数据量加密) |
| 安全性 | 安全性依赖密钥保管(密钥泄露则数据全暴露) | 安全性更高(私钥不对外传输,仅需保管好私钥) |
| 密钥分发 | 密钥分发困难(需安全通道传输,否则易被拦截) | 密钥分发简单(公钥可公开传播,无需保密) |
| 典型算法 | AES、DES、3DES | RSA、DSA、ECC |
二、各自用途:什么时候用哪种?
1. 对称加密:适合“大数据量加密”场景
对称加密的核心优势是快,所以主要用于对大量数据进行加密,比如:
- 数据库中敏感字段加密(如用户手机号、身份证号);
- 文件传输加密(如上传/下载的Excel、PDF文件);
- 接口请求体加密(如APP向后端传输的用户行为数据)。
举个实际开发场景:用户在APP上提交实名认证信息(姓名+身份证号),后端接收后需要加密存储到MySQL。此时用AES对称加密,既能保证数据安全,又不会因为加密耗时影响接口响应速度。
2. 非对称加密:适合“密钥交换/数字签名”场景
非对称加密的核心优势是安全且密钥易分发,但速度慢,所以主要用于:
- 密钥交换(如对称加密的密钥,通过非对称加密传输);
- 数字签名(如接口防篡改、数据来源认证);
- 小数据加密(如加密用户登录密码的验证码)。
举个实际开发场景:APP与后端首次建立连接时,需要协商一个对称加密的密钥(用于后续数据传输加密)。此时后端生成RSA公钥和私钥,将公钥传给APP,APP用公钥加密自己生成的AES密钥,后端用私钥解密得到AES密钥,后续就用AES加密传输数据——既解决了对称密钥的安全分发问题,又保证了传输效率。
三、Java工具类实战(可直接复制使用)
1. 对称加密工具类(AES算法)
AES是目前最常用的对称加密算法,安全性高、效率快,推荐优先使用。以下工具类支持AES-128/256加密,包含加密、解密、生成密钥功能:
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
/**
* AES对称加密工具类(可直接复用)
* 说明:128位密钥无需额外配置,256位密钥需安装JCE无限制权限文件
*/
public class AesEncryptUtil {
// 加密算法:AES,模式:ECB,填充方式:PKCS5Padding(实际开发推荐用CBC模式,需加偏移量)
private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
private static final String KEY_ALGORITHM = "AES";
private static final int KEY_SIZE = 128; // 密钥长度:128/256
/**
* 生成AES密钥(返回Base64编码后的密钥字符串,方便存储)
*/
public static String generateKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
keyGenerator.init(KEY_SIZE);
SecretKey secretKey = keyGenerator.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
}
/**
* 加密:明文 -> Base64编码的密文
* @param plainText 明文(待加密的字符串)
* @param keyStr Base64编码后的密钥
*/
public static String encrypt(String plainText, String keyStr) throws Exception {
// 1. 解码密钥
byte[] keyBytes = Base64.getDecoder().decode(keyStr);
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
// 2. 初始化加密器
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// 3. 加密并返回Base64编码的密文
byte[] encryptBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encryptBytes);
}
/**
* 解密:Base64编码的密文 -> 明文
* @param cipherText Base64编码后的密文
* @param keyStr Base64编码后的密钥
*/
public static String decrypt(String cipherText, String keyStr) throws Exception {
// 1. 解码密钥和密文
byte[] keyBytes = Base64.getDecoder().decode(keyStr);
byte[] cipherBytes = Base64.getDecoder().decode(cipherText);
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
// 2. 初始化解密器
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
// 3. 解密并返回明文
byte[] decryptBytes = cipher.doFinal(cipherBytes);
return new String(decryptBytes, "UTF-8");
}
// 测试方法
public static void main(String[] args) throws Exception {
// 1. 生成密钥(实际开发中密钥需妥善保管,如配置在Nacos、Vault中)
String key = generateKey();
System.out.println("AES密钥(Base64编码):" + key);
// 2. 加密
String plainText = "用户身份证号:110101199001011234";
String cipherText = encrypt(plainText, key);
System.out.println("加密后的密文:" + cipherText);
// 3. 解密
String decryptText = decrypt(cipherText, key);
System.out.println("解密后的明文:" + decryptText);
}
}
2. 非对称加密工具类(RSA算法)
RSA是最常用的非对称加密算法,适合密钥交换和数字签名。以下工具类包含密钥对生成、公钥加密、私钥解密、私钥签名、公钥验签功能:
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* RSA非对称加密工具类(可直接复用)
* 说明:密钥长度推荐2048位(安全性足够),4096位加密速度较慢
*/
public class RsaEncryptUtil {
private static final String ALGORITHM = "RSA";
private static final int KEY_SIZE = 2048; // 密钥长度:2048/4096
// 签名算法:SHA256withRSA(SHA256哈希+RSA签名,安全性更高)
private static final String SIGN_ALGORITHM = "SHA256withRSA";
/**
* 生成RSA密钥对(公钥+私钥),返回Base64编码后的字符串
* @return 数组:[0]公钥,[1]私钥
*/
public static String[] generateKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 公钥编码为Base64字符串
String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
// 私钥编码为Base64字符串
String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
return new String[]{publicKey, privateKey};
}
/**
* 公钥加密(适合加密小数据,如AES密钥)
* @param plainText 明文(待加密的字符串)
* @param publicKeyStr Base64编码后的公钥
*/
public static String encryptByPublicKey(String plainText, String publicKeyStr) throws Exception {
// 1. 解码公钥
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
// 2. 初始化加密器
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 3. 加密(RSA加密有长度限制,需分段加密,这里简化处理短字符串)
byte[] encryptBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encryptBytes);
}
/**
* 私钥解密
* @param cipherText Base64编码后的密文
* @param privateKeyStr Base64编码后的私钥
*/
public static String decryptByPrivateKey(String cipherText, String privateKeyStr) throws Exception {
// 1. 解码私钥
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// 2. 初始化解密器
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 3. 解密
byte[] cipherBytes = Base64.getDecoder().decode(cipherText);
byte[] decryptBytes = cipher.doFinal(cipherBytes);
return new String(decryptBytes, "UTF-8");
}
/**
* 私钥签名(用于数据防篡改、来源认证)
* @param data 待签名的数据
* @param privateKeyStr Base64编码后的私钥
*/
public static String sign(String data, String privateKeyStr) throws Exception {
// 1. 解码私钥
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// 2. 生成签名
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initSign(privateKey);
signature.update(data.getBytes("UTF-8"));
byte[] signBytes = signature.sign();
return Base64.getEncoder().encodeToString(signBytes);
}
/**
* 公钥验签(验证数据是否被篡改、签名是否有效)
* @param data 原始数据
* @param sign 签名值(Base64编码)
* @param publicKeyStr Base64编码后的公钥
*/
public static boolean verifySign(String data, String sign, String publicKeyStr) throws Exception {
// 1. 解码公钥
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
// 2. 验证签名
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initVerify(publicKey);
signature.update(data.getBytes("UTF-8"));
return signature.verify(Base64.getDecoder().decode(sign));
}
// 测试方法
public static void main(String[] args) throws Exception {
// 1. 生成密钥对
String[] keyPair = generateKeyPair();
String publicKey = keyPair[0];
String privateKey = keyPair[1];
System.out.println("RSA公钥(Base64编码):" + publicKey);
System.out.println("RSA私钥(Base64编码):" + privateKey);
// 2. 加密解密(加密AES密钥示例)
String aesKey = "1234567890abcdef"; // 假设生成的AES密钥
String encryptAesKey = encryptByPublicKey(aesKey, publicKey);
System.out.println("公钥加密后的AES密钥:" + encryptAesKey);
String decryptAesKey = decryptByPrivateKey(encryptAesKey, privateKey);
System.out.println("私钥解密后的AES密钥:" + decryptAesKey);
// 3. 签名验签
String data = "接口返回数据:{\"code\":200,\"msg\":\"success\"}";
String sign = sign(data, privateKey);
System.out.println("私钥签名值:" + sign);
boolean verifyResult = verifySign(data, sign, publicKey);
System.out.println("公钥验签结果:" + verifyResult); // true表示验签通过
}
}
四、开发注意事项
- 密钥保管:对称加密的密钥和非对称加密的私钥,不能硬编码在代码里,建议存储在配置中心(如Nacos)或密钥管理工具(如Vault);
- 算法选择:对称加密优先用AES(避免用DES,安全性较低),非对称加密优先用RSA-2048(兼顾安全性和效率);
- 数据长度:RSA加密有长度限制(如2048位密钥最多加密245字节),加密大数据需分段,或用“非对称加密+对称加密”组合方案;
- 填充方式:对称加密推荐用PKCS5Padding(兼容性好),非对称加密无需手动指定填充方式(Java默认实现已优化)。
加密算法工具类
934

被折叠的 条评论
为什么被折叠?



