Java 使用 SpringBoot 生成 RSA 密鑰文件對及校驗
1. 新建 SpringBoot 項目
2. 編寫代碼
2.1 編寫 application.yml 文件
SystemConfig:
rsa-keypair:
# 加密方式
algorithm: RSA
# 初始化大小
key-size: 1024
# 公鑰文件
public-key-file: D://publicKey
# 私鑰文件
private-key-file: D://priavteKey
2.2 編寫配置類用於讀取 YAML 配置文件屬性
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @Author: Arther Lee
* @Description: 生成密鑰對的配置文件
* @Date: create in 2022-01-29 15:11
*/
@Component
public class GenerateKeyPairConfig {
@Value("${SystemConfig.rsa-keypair.algorithm}")
private String algorithm;
@Value("${SystemConfig.rsa-keypair.key-size}")
private Integer keySize;
@Value("${SystemConfig.rsa-keypair.public-key-file}")
private String publicKeyFile;
@Value("${SystemConfig.rsa-keypair.private-key-file}")
private String privateKeyFile;
/**
* 獲取指定加密算法
* @return 讀取YAML文件的 SystemConfig.rsa-keypair.algorithm 屬性
*/
public String getAlgorithm() {
return algorithm;
}
/**
* 獲取密鑰長度,用來初始化
* @return 讀取YAML文件的 SystemConfig.rsa-keypair.key-size 屬性
*/
public Integer getKeySize() {
return keySize;
}
/**
* 獲取公鑰存放文件
* @return 讀取YAML文件的 SystemConfig.rsa-keypair.public-key-file 屬性
*/
public String getPublicKeyFile() {
return publicKeyFile;
}
/**
* 獲取私鑰存放文件
* @return 讀取YAML文件的 SystemConfig.rsa-keypair.private-key-file 屬性
*/
public String getPrivateKeyFile() {
return privateKeyFile;
}
}
2.3 編寫 RSA 工具類
import com.example.demo.common.GenerateKeyPairConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Arther Lee
* @Description: 密鑰對文件工具類
* @Date: create in 2022-01-28 17:08
*/
@Component
public class GenerateKeyPairUtil {
@Autowired
private GenerateKeyPairConfig KeyPairConfig;
// region 私有方法
/**
* 生成密鑰對
* @return 返回map集合,其中包含publicKey與privateKey
* @throws NoSuchAlgorithmException
*/
private Map<String, Key> generateKeyPair() throws NoSuchAlgorithmException {
/**
* RSA算法要求有一個可信任的隨機數源
*/
SecureRandom secureRandom = new SecureRandom();
/**
* 為RSA算法創建一個KeyPairGenerator對象
*/
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyPairConfig.getAlgorithm());
/**
* 利用上面的隨機數據源初始化這個KeyPairGenerator對象
*/
keyPairGenerator.initialize(KeyPairConfig.getKeySize(), secureRandom);
/**
* 生成密匙對
*/
KeyPair keyPair = keyPairGenerator.generateKeyPair();
/**
* 得到公鑰
*/
Key publicKey = keyPair.getPublic();
/**
* 得到私鑰
*/
Key privateKey = keyPair.getPrivate();
Map<String, Key> keyPairMap = new HashMap<>();
keyPairMap.put("publicKey", publicKey);
keyPairMap.put("privateKey", privateKey);
return keyPairMap;
}
/**
* 獲取文件中獲取密鑰對象
* @param fileName 文件名
* @return 密鑰對象
*/
private Key getKeyFromFile(String fileName) {
Key key = null;
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(fileName));
key = (Key) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return key;
}
/**
* 將密鑰對生成到文件中
*/
private void generateKeyPairToFiles() {
ObjectOutputStream oosPublicKey = null;
ObjectOutputStream oosPrivateKey = null;
try {
Map<String, Key> keyPairMap = generateKeyPair();
Key publicKey = keyPairMap.get("publicKey");
Key privateKey = keyPairMap.get("privateKey");
oosPublicKey = new ObjectOutputStream(new FileOutputStream(KeyPairConfig.getPublicKeyFile()));
oosPrivateKey = new ObjectOutputStream(new FileOutputStream(KeyPairConfig.getPrivateKeyFile()));
oosPublicKey.writeObject(publicKey);
oosPrivateKey.writeObject(privateKey);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
/**
* 清空緩存,關閉文件輸出流
*/
oosPublicKey.close();
oosPrivateKey.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// endregion 私有方法
// region 公有方法
/**
* 初始化密鑰對文件
* @return 返回密鑰對信息【publicKey(公鑰字符串)、、privateKey(私鑰字符串)】
*/
public Map<String, String> initKeyPair() {
Map<String, String> keyPairMap = new HashMap<>();
File publicFile = new File(KeyPairConfig.getPublicKeyFile());
File privateFile = new File(KeyPairConfig.getPrivateKeyFile());
/**
* 判斷是否存在公鑰和私鑰文件
*/
if (!publicFile.exists() || !privateFile.exists()) {
generateKeyPairToFiles();
}
ObjectInputStream oisPublic = null;
ObjectInputStream oisPrivate = null;
Key publicKey = null;
Key privateKey = null;
try {
oisPublic = new ObjectInputStream(new FileInputStream(KeyPairConfig.getPublicKeyFile()));
oisPrivate = new ObjectInputStream(new FileInputStream(KeyPairConfig.getPrivateKeyFile()));
publicKey = (Key) oisPublic.readObject();
privateKey = (Key) oisPrivate.readObject();
byte[] publicKeyBytes = publicKey.getEncoded();
byte[] privateKeyBytes = privateKey.getEncoded();
String publicKeyBase64 = new BASE64Encoder().encode(publicKeyBytes);
String privateKeyBase64 = new BASE64Encoder().encode(privateKeyBytes);
/**
* 公鑰字符串
*/
keyPairMap.put("publicKey", publicKeyBase64);
/**
* 私鑰字符串
*/
keyPairMap.put("privateKey", privateKeyBase64);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
oisPrivate.close();
oisPublic.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return keyPairMap;
}
/**
* 加密方法
* @param source 源數據
* @return 加密后的字符串
*/
public String encrypt(String source) {
Key publicKey = getKeyFromFile(KeyPairConfig.getPublicKeyFile());
BASE64Encoder encoder = new BASE64Encoder();
String encryptSource = null;
try {
/**
* 得到Cipher對象來實現對源數據的RSA加密
*/
Cipher cipher = Cipher.getInstance(KeyPairConfig.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] bytes = source.getBytes();
/**
* 執行加密操作
*/
encryptSource = encoder.encode(cipher.doFinal(bytes));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return encryptSource;
}
/**
* 解密方法
* @param source 密文
* @return 解密后的字符串
*/
public String decrypt(String source) {
Key privateKey = getKeyFromFile(KeyPairConfig.getPrivateKeyFile());
BASE64Decoder decoder = new BASE64Decoder();
String decryptSource = null;
try {
/**
* 得到Cipher對象對已用公鑰加密的數據進行RSA解密
*/
Cipher cipher = Cipher.getInstance(KeyPairConfig.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
/**
* 執行解密操作
*/
byte[] bytes = decoder.decodeBuffer(source);
decryptSource = new String(cipher.doFinal(bytes), "UTF-8");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return decryptSource;
}
// endregion 公有方法
}
3. 項目測試
3.1 測試代碼
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Map;
@SpringBootTest
class DemoApplicationTests {
@Autowired
GenerateKeyPairUtil keyPairUtil;
@Test
void contextLoads() {
Map<String, String> keyPairMap = keyPairUtil.initKeyPair();
String publicKey = keyPairMap.get("publicKey");
String privateKey = keyPairMap.get("privateKey");
System.out.println("公鑰:");
System.out.println(publicKey);
System.out.println();
System.out.println("私鑰:");
System.out.println(privateKey);
System.out.println();
String source = "Hello World";
System.out.println("待加密字符串:" + source);
System.out.println();
String strEncrypt = keyPairUtil.encrypt(source);
System.out.println("加密后的字符串:");
System.out.println(strEncrypt);
System.out.println();
String strDecrypt = keyPairUtil.decrypt(strEncrypt);
System.out.println("解密后的字符串:");
System.out.println(strDecrypt);
}
}
3.2 測試結果
公鑰:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCURAtxRGI7Of19MOb2XoTXFjBG52kr7b11DRJ4
UnyThIuKUjzNSQnW+a1T3fHMfF0w22NiyE2lRpYZ+W6z7MsOhr/EOrXHcFhRd3+bc+j+56aLo8Mp
rYnxBmcc49J5uN8ztg4XSLf4DyEx3CmSh8/mzJxOtoEYDKGL1RapQu2l/QIDAQAB
私鑰:
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJREC3FEYjs5/X0w5vZehNcWMEbn
aSvtvXUNEnhSfJOEi4pSPM1JCdb5rVPd8cx8XTDbY2LITaVGlhn5brPsyw6Gv8Q6tcdwWFF3f5tz
6P7npoujwymtifEGZxzj0nm43zO2DhdIt/gPITHcKZKHz+bMnE62gRgMoYvVFqlC7aX9AgMBAAEC
gYEAjl0H36qZ5+S20g6ytr3rL9vOX0a0ZcnRsSLsKTyLAdqzYg209Ci9mf4DwBPMqVyA3vjJZYCP
jbNJTYeEFJ+6GKyIXZeYYXlEzPytrScB+vfro3JUGNnDu4RtFjFPsf3iew872/Vllkq/rNnrXnze
vA7Ea0JxfUEtumdX9CgE8AECQQDo86ocAYcQO+JbX8G9RGcn8SvCieaG9dM7U3fUlrB7XrcJqDo+
ypRqEYZGcdX4iv841bFAqPPFRkhWS+TAMmm9AkEAou9npIFhC0Xe/ncICeWcIn0XHfy/e1cKTE+d
YqfB5RdUcM/qPzrdO2U7p9guscc+e6AbHyhE4MtuoSZu2hxRQQJBAKFzBunEEUSqDFaBxjeTqd7f
4hFBG9lblFtgnQNksMnAOiFiS4PrSPM+VA6MpNxOEVblm6SRs+l8rXPJw6+FAQ0CQEIR0DYt3Hsk
vxLyk4jn2ZNGpCwdxEuwdNWS5yANJJvQBQal2LgBF5qxJyqdh/nA8H5S4wyUWLHK7DZejk7VcsEC
QAn83cKhqcxArrF+jNizom3at44Ag5fdlUahb+ybSNnqeJ6qq5Tagrix6KqVImRAsW1AUQC0r+IN
4FyTzh5WQAw=
待加密字符串:Hello World
加密后的字符串:
IerO2h4VHRN9cD3PoyD8oBlW9yHXu6ZJa9XO1zIi3JhQFIOMye18nx7pR2gI7dr9h41Q5mRiNjz7
3PDu5tLF7nyoIF0IcUHk3Dv4JMfQnfwGEEScatSjai1doIFnpBhUoDJEUY2/qBAUbt14/J1nhKn6
BgeHz0lYrvTVB2TAmus=
解密后的字符串:
Hello World