文章目录
- AES / RSA
- 流程
- Code
- 生成AES密钥 和 生成RSA密钥对
- AES工具类,提供AES加密和解密功能
- RSA加密工具类
- 测试类
- 总结
AES / RSA
- AES:一种对称加密算法,意味着加密和解密使用相同的密钥。速度快,适合加密大量数据。
- RSA:一种非对称加密算法,有一对密钥:公钥和私钥。用公钥加密的数据只能用对应的私钥解密,反之亦然。
流程
-
客户端和服务端都生成一对RSA密钥:
- 客户端和服务端各自生成自己的RSA公钥和私钥。
- RSA公钥是公开的,可以共享;RSA私钥则要保密。
-
客户端和服务端分别生成AES密钥:
- 客户端和服务端都生成自己的AES密钥,用于加密实际的数据。
-
客户端发送请求给服务端:
- 客户端用服务端的RSA公钥加密它自己的AES密钥,并将加密后的AES密钥发送给服务端。
- 同时,客户端还会用AES密钥加密一份请求报文,然后将这个加密的报文和它自己的RSA公钥一起发送给服务端。
-
服务端解密并处理请求:
- 服务端接收到请求后,用自己的RSA私钥解密客户端发送的AES密钥。
- 然后,服务端用解密后的AES密钥解密客户端的请求报文,得到了客户端发送的实际信息。
- 服务端接下来会生成一个响应报文,用客户端的AES密钥加密该响应报文。
-
服务端发送响应给客户端:
- 服务端用客户端的RSA公钥加密自己的AES密钥,并将加密后的AES密钥和加密的响应报文一起发送给客户端。
-
客户端解密并获取响应:
- 客户端用自己的RSA私钥解密服务端发送过来的AES密钥。
- 然后,客户端用解密后的AES密钥解密服务端的响应报文,得到最终的回应内容。
Code
生成AES密钥 和 生成RSA密钥对
package com.artisan.shuangxiang_aesrsa;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
/**
* @author artisan
*/
public class KeyGeneration {
/**
* 生成AES密钥
*
* @return 生成的SecretKey对象,包含AES算法的密钥
* @throws Exception 如果密钥生成过程中出现错误
*/
public static SecretKey generateAESKey() throws Exception {
// 获取KeyGenerator实例,指定使用AES算法
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
// 初始化AES密钥的长度为128位
keyGen.init(128);
// 生成AES密钥
return keyGen.generateKey();
}
/**
* 生成RSA密钥对
*
* @return 生成的RSA密钥对
* @throws Exception 如果无法生成密钥对,则抛出异常
*/
public static KeyPair generateRSAKeyPair() throws Exception {
// 获取密钥对生成器实例
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器为2048位
keyPairGen.initialize(2048);
// 生成RSA密钥对
return keyPairGen.generateKeyPair();
}
}
AES工具类,提供AES加密和解密功能
package com.artisan.shuangxiang_aesrsa;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;
/**
* @author artisan
*/
/**
* AES工具类,提供AES加密和解密功能
* 使用AES/CBC/PKCS5Padding算法进行加密和解密
*/
public class AESUtil {
/**
* 定义加密算法类型为AES/CBC/PKCS5Padding
*/
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
/**
* 使用AES算法加密数据
*
* @param data 待加密的字符串
* @param key 加密使用的SecretKey
* @param iv 加密使用的初始化向量(IvParameterSpec)
* @return 加密后的字符串,以Base64编码
* @throws Exception 如果加密过程中发生错误,抛出异常
*/
public static String encryptAES(String data, SecretKey key, IvParameterSpec iv) throws Exception {
// 创建Cipher实例,指定使用AES/CBC/PKCS5Padding算法
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 初始化Cipher为加密模式,传入密钥和初始化向量
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
// 将待加密数据转换为字节数组,并执行加密操作
byte[] encryptedData = cipher.doFinal(data.getBytes());
// 将加密后的数据使用Base64编码,并返回
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* 使用AES算法解密数据
*
* @param encryptedData 待解密的字符串,以Base64编码
* @param key 解密使用的SecretKey
* @param iv 解密使用的初始化向量(IvParameterSpec)
* @return 解密后的字符串
* @throws Exception 如果解密过程中发生错误,抛出异常
*/
public static String decryptAES(String encryptedData, SecretKey key, IvParameterSpec iv) throws Exception {
// 创建Cipher实例,指定使用AES/CBC/PKCS5Padding算法
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 初始化Cipher为解密模式,传入密钥和初始化向量
cipher.init(Cipher.DECRYPT_MODE, key, iv);
// 将待解密数据从Base64解码为字节数组
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
// 执行解密操作
byte[] decryptedData = cipher.doFinal(decodedData);
// 将解密后的数据转换为字符串,并返回
return new String(decryptedData);
}
}
RSA加密工具类
package com.artisan.shuangxiang_aesrsa;
import javax.crypto.Cipher;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
/**
* RSA加密工具类
* @author artisan
*/
public class RSAUtil {
/**
* 定义加密算法类型为RSA
*/
private static final String ALGORITHM = "RSA";
/**
* 使用RSA算法和公钥加密数据
*
* @param data 待加密的字符串数据
* @param publicKey 用于加密的公钥
* @return 加密后的数据,以Base64编码的字符串形式表示
* @throws Exception 如果加密过程中发生错误,抛出异常
*/
public static String encryptRSA(String data, PublicKey publicKey) throws Exception {
// 获取Cipher实例,指定使用RSA算法
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 初始化Cipher为加密模式,并使用指定的公钥
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 将待加密的字符串转换为字节数组,并执行加密操作
byte[] encryptedData = cipher.doFinal(data.getBytes());
// 将加密后的字节数组使用Base64编码为字符串
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* 使用RSA算法和私钥解密数据
*
* @param encryptedData 待解密的字符串数据,预期是通过Base64编码的
* @param privateKey 用于解密的私钥
* @return 解密后的原始字符串数据
* @throws Exception 如果解密过程中发生错误,抛出异常
*/
public static String decryptRSA(String encryptedData, PrivateKey privateKey) throws Exception {
// 获取Cipher实例,指定使用RSA算法
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 初始化Cipher为解密模式,并使用指定的私钥
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 将Base64编码的字符串解码为字节数组
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
// 执行解密操作,得到原始的字节数组
byte[] decryptedData = cipher.doFinal(decodedData);
// 将解密后的字节数组转换为字符串
return new String(decryptedData);
}
}
测试类
package com.artisan.shuangxiang_aesrsa;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
/**
* @author artisan
*/
public class Main {
/**
* 使用RSA公钥加密AES密钥,以及使用RSA私钥解密AES密钥的全过程
* 同时展示了使用AES密钥加密和解密数据的应用
*
* @param args 命令行参数
* @throws Exception 可能抛出的异常
*/
public static void main(String[] args) throws Exception {
// 生成AES和RSA密钥
SecretKey aesKey = KeyGeneration.generateAESKey();
KeyPair rsaKeyPair = KeyGeneration.generateRSAKeyPair();
PublicKey rsaPublicKey = rsaKeyPair.getPublic();
PrivateKey rsaPrivateKey = rsaKeyPair.getPrivate();
String aesKeyString = Base64.getEncoder().encodeToString(aesKey.getEncoded());
System.out.println("AES密钥: " + aesKeyString);
// 初始化IV(通常需要确保IV的安全传输) 16字节的IV向量
IvParameterSpec iv = new IvParameterSpec(new byte[16]);
// 客户端用服务端的RSA公钥加密AES密钥
String encryptedAESKey = RSAUtil.encryptRSA(aesKeyString, rsaPublicKey);
System.out.println("加密后的AES密钥: " + encryptedAESKey);
// 模拟服务端解密AES密钥
String decryptedAESKey = RSAUtil.decryptRSA(encryptedAESKey, rsaPrivateKey);
SecretKey originalAESKey = new javax.crypto.spec.SecretKeySpec(Base64.getDecoder().decode(decryptedAESKey), "AES");
System.out.println("解密后的AES密钥: " + Base64.getEncoder().encodeToString(originalAESKey.getEncoded()));
// 使用AES加密和解密数据
String originalData = "我是需要加密的数据artisan GO GO GO !!!";
String encryptedData = AESUtil.encryptAES(originalData, aesKey, iv);
System.out.println("加密的数据: " + encryptedData);
String decryptedData = AESUtil.decryptAES(encryptedData, aesKey, iv);
System.out.println("解密的数据: " + decryptedData);
}
}
输出
AES密钥: n5PbFsDPACXiDsuBhjHwvg==
加密后的AES密钥: cuNuyggZpGhVthHpUPEEt7l7Nh9ySl4S4zLBVLpxbx3ft9JwKNfTi0ggtAX1p27lpFsru/riYVv/6HuI/AO2PV/WzmE9ySUa7+cdkvlTqdbsQaFF67R2DqEtMbsJyfiGVI6Y9acObMWw9nGeggtsQAlfNqjV8LC8i1T4OJcstMcmdgCEg85vBizwdFEOJPZO1SDEd///CY2jT7tY7Zz4kvq9f+WkNnHy+s11cUOzr6Griv83JlFNPvJ3DifVhkmxsR5Cg9HaRtjSRvx9VPfwza/SrQWue7rzsLSirXsj+kIOBfOopSFj0xSBCG32NnQEuWspSGdgJTHAmD/X7RJzoQ==
解密后的AES密钥: n5PbFsDPACXiDsuBhjHwvg==
加密的数据: a1gn+70y0nkd9VGg3hg3Y/b0PxUd1dqAuzKHDedGMdleu2UVWkBtInZ0Ox4iNOFM
解密的数据: 我是需要加密的数据artisan GO GO GO !!!
总结
这个流程的核心在于:
- 使用RSA来安全地交换AES密钥。
- AES用来加密实际的数据,确保数据传输的安全性和效率
- 请注意保护好自己的私钥,不可泄露
通过这种双向加密的方式,客户端和服务端能够安全地互相传递敏感信息,同时确保即使通信内容被截获,也无法被解读。