RSA非对称加密:原理、应用与实践
https://cloud.baidu.com/article/3155891
项目中使用到的常量
private static final Log log = LogFactory.get();
// 定义RSA密钥的长度为2048位
private static final int RSA_KEY_SIZE = 2048;
// 指定RSA算法的名称
private static final String RSA_ALGORITHM = "RSA";
生成RSA密钥对,并分别保存公钥和私钥
public static void createKey(String publicKeyPath, String privateKeyPath, String charset) {
// 检查输入参数是否合法,如果存在null或空字符串,则抛出异常
if (publicKeyPath == null || publicKeyPath.isEmpty() ||
privateKeyPath == null || privateKeyPath.isEmpty() ||
charset == null || charset.isEmpty()) {
throw new IllegalArgumentException("Parameters cannot be null or empty.");
}
// 根据输入的字符集名称获取Charset对象
Charset cs;
try {
cs = Charset.forName(charset);
} catch (IllegalArgumentException e) {
// 如果字符集无效,抛出异常
throw new IllegalArgumentException("Invalid charset: " + charset, e);
}
try {
// 实例化密钥生成器
KeyPairGenerator rsa = KeyPairGenerator.getInstance(RSA_ALGORITHM);
// 初始化密钥生成器为2048位
rsa.initialize(RSA_KEY_SIZE);
// 生成密钥对
KeyPair keyPair = rsa.generateKeyPair();
// 将公钥编码为Base64格式字符串并写入文件
FileUtils.writeFileContent(publicKeyPath, new String(Base64.getEncoder().encode(keyPair.getPublic().getEncoded()), cs), charset);
// 将私钥编码为Base64格式字符串并写入文件
FileUtils.writeFileContent(privateKeyPath, new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded()), cs), charset);
} catch (NoSuchAlgorithmException e) {
// 如果RSA算法不可用,记录错误日志
log.error("Failed to generate RSA key pair: Algorithm not available.", e);
throw new RuntimeException("Failed to generate RSA key pair: Algorithm not available.", e);
}
}
根据公钥文件路径获取PublicKey对象
public static PublicKey getPublicKey(String publicKeyPath, String charset) {
try {
// 读取公钥文件内容
String publicKeyStr = FileUtils.getFileContent(publicKeyPath, charset);
// 对读取的公钥内容进行Base64解码
byte[] decodedKey = Base64.getDecoder().decode(publicKeyStr);
// 获取RSA算法的KeyFactory实例
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
// 根据解码后的公钥字节数组生成PublicKey对象
return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
// RSA算法相关异常处理
log.error("Failed to generate public key from the specified key specification.", e);
throw new RuntimeException(e);
}
}
根据私钥路径获取私钥对象
public static PrivateKey getPrivateKey(String privateKeyPath, String charset) {
try {
// 读取私钥文件内容
String privateKey = FileUtils.getFileContent(privateKeyPath, charset);
// 对读取的内容进行Base64解码
byte[] decode = Base64.getDecoder().decode(privateKey);
// 创建RSA密钥工厂
KeyFactory rsa = KeyFactory.getInstance(RSA_ALGORITHM);
// 使用解码后的密钥材料生成私钥对象
return rsa.generatePrivate(new PKCS8EncodedKeySpec(decode));
} catch (Exception e) {
// RSA算法相关异常处理
log.error("Failed to generate private key from the specified key specification.", e);
throw new RuntimeException(e);
}
}
使用RSA公钥加密明文
public static String encrypt(String plainText, PublicKey publicKey, String charset) {
try {
// 使用RSA算法的Cipher对象进行加密操作
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
// 初始化Cipher对象为加密模式
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 对明文进行加密
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(Charset.forName(charset)));
// 将加密后的字节数组转换为Base64编码的字符串
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
log.error("Encryption failed {}", e.getMessage(), e);
throw new RuntimeException("Failed to encrypt the plaintext", e);
}
}
使用RSA算法和私钥对已加密的文本进行解密
public static String decrypt(String encryptedText, PrivateKey privateKey, String charset) {
try {
// 创建Cipher实例,指定使用RSA算法
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// 初始化Cipher为解密模式,并使用提供的私钥
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 使用Base64解码器将已加密的文本解码为字节数组
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
// 使用Cipher解密字节数组
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
// 使用指定的字符集解码解密后的字节数组,并返回字符串
return new String(decryptedBytes, Charset.forName(charset));
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
log.error("Error during decryption: " + e.getMessage(), e);
throw new RuntimeException("Error during decryption", e);
}
}
使用到的工具类 FileUtils
将字符串内容写入指定文件
public static void writeFileContent(String filePath, String content, String charset) {
// 根据文件路径创建File对象
File file = new File(filePath);
// 检查文件是否存在,如果不存在则尝试创建
if (!file.exists()) {
boolean created = false;
try {
created = file.createNewFile();
} catch (IOException e) {
log.error("Failed to create the file: " + filePath, e);
throw new RuntimeException("Failed to create the file: " + filePath);
}
if (!created) {
throw new RuntimeException("Failed to create the file: " + filePath);
}
}
// 使用指定字符集创建OutputStreamWriter,用于写入文件内容
try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), charset != null ? Charset.forName(charset) : StandardCharsets.UTF_8)) {
// 写入字符串内容到文件
writer.write(content);
} catch (IOException e) {
// 如果发生IO异常,记录错误信息并抛出运行时异常
log.error("Failed to write to file: {} ", filePath, e);
throw new RuntimeException("Failed to write to file: " + filePath, e);
}
}
读取文件内容
public static String getFileContent(String filePath, String charset) {
// 检查文件路径是否为空或null
if (filePath == null || filePath.isEmpty()) {
throw new IllegalArgumentException("File path cannot be null or empty.");
}
// 检查编码格式是否为空或null
if (charset == null || charset.isEmpty()) {
throw new IllegalArgumentException("Charset cannot be null or empty.");
}
try {
// 使用StringJoiner拼接文件内容,行之间使用系统特定的行分隔符分隔
StringJoiner joiner = new StringJoiner(System.lineSeparator());
// 使用Files工具类读取文件内容
Path path = Paths.get(filePath);
try (Stream<String> lines = Files.lines(path, Charset.forName(charset))) {
lines.forEach(joiner::add);
}
// 返回读取到的文件内容
return joiner.toString();
} catch (IOException e) {
// 如果发生IO异常,记录错误信息并抛出运行时异常
log.error("Failed to read file: {} ", filePath, e);
throw new RuntimeException("Failed to read file: " + filePath, e);
}
}
加密使用到的依赖
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
<!-- 引入Apache Log4j核心库,用于日志管理 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<!-- 引入Hutool日志工具库,简化日志操作 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-log</artifactId>
<version>5.8.28</version>
</dependency>