前言
在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默认实现已优化)。
总结
到此这篇关于java对称加密与非对称加密区别、用途及工具类的文章就介绍到这了,更多相关java对称加密与非对称加密内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论