diff --git a/pom.xml b/pom.xml
index 911682f..3a357eb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,6 +8,15 @@
utils
1.0-SNAPSHOT
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.8.2
+ test
+
+
+
8
8
diff --git a/src/main/java/com/simaek/util/RSAUtil.java b/src/main/java/com/simaek/util/RSAUtil.java
new file mode 100644
index 0000000..5190fa7
--- /dev/null
+++ b/src/main/java/com/simaek/util/RSAUtil.java
@@ -0,0 +1,173 @@
+package com.simaek.util;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.security.*;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+/**
+ * RSA加密解密工具类
+ *
+ * @author Yaser Hsueh
+ */
+public final class RSAUtil {
+ private RSAUtil() {
+ throw new AssertionError();
+ }
+
+ private static final int defaultBits = 1024;
+ /**
+ * 最大解密明文长度
+ */
+ private static final int MAX_DECRYPT_BLOCK = defaultBits >> 3;
+ /**
+ * 最大加密明文长度
+ */
+ private static final int MAX_ENCRYPT_BLOCK = (defaultBits >> 3) - 11;
+
+
+ /**
+ * 生成秘钥对(默认长度1024Bits)
+ */
+ public static KeyPair getKeyPair() throws Exception {
+ return getKeyPair(defaultBits);
+ }
+
+ /**
+ * 生成秘钥对
+ */
+ public static KeyPair getKeyPair(int keySize) throws Exception {
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(keySize);
+ return keyPairGenerator.generateKeyPair();
+ }
+
+ /**
+ * 获取公钥(Base64编码)
+ */
+ public static String getPublicKey(KeyPair keyPair) {
+ PublicKey publicKey = keyPair.getPublic();
+ byte[] bytes = publicKey.getEncoded();
+ return byte2Base64(bytes);
+ }
+
+ /**
+ * 获取私钥(Base64编码)
+ */
+ public static String getPrivateKey(KeyPair keyPair) {
+ PrivateKey privateKey = keyPair.getPrivate();
+ byte[] bytes = privateKey.getEncoded();
+ return byte2Base64(bytes);
+ }
+
+ /**
+ * 将Base64编码后的公钥转换成PublicKey对象
+ */
+ public static PublicKey string2PublicKey(String pubStr) throws Exception {
+ byte[] keyBytes = base642Byte(pubStr);
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePublic(keySpec);
+ }
+
+ /**
+ * 将Base64编码后的私钥转换成PrivateKey对象
+ */
+ public static PrivateKey string2PrivateKey(String priStr) throws Exception {
+ byte[] keyBytes = base642Byte(priStr);
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePrivate(keySpec);
+ }
+
+ /**
+ * 公钥加密
+ */
+ public static byte[] publicEncrypt(byte[] content, PublicKey publicKey) throws Exception {
+ Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+ return fragment(content, cipher, MAX_ENCRYPT_BLOCK);
+ }
+
+ /**
+ * 私钥解密
+ */
+ public static byte[] privateDecrypt(byte[] content, PrivateKey privateKey) throws Exception {
+ Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ cipher.init(Cipher.DECRYPT_MODE, privateKey);
+ return fragment(content, cipher, MAX_DECRYPT_BLOCK);
+ }
+
+ /**
+ * 私钥签名
+ */
+ public static String privateSign(byte[] content, String privateKey) throws Exception {
+ byte[] keyBytes = base642Byte(privateKey);
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+ Signature signature = Signature.getInstance("SHA256withRSA");
+ signature.initSign(privateK);
+ signature.update(content);
+ return byte2Base64(signature.sign());
+ }
+
+ /**
+ * 公钥验签
+ */
+ public static boolean publicVerify(byte[] content, String publicKey, String sign) throws Exception {
+ byte[] keyBytes = base642Byte(publicKey);
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PublicKey publicK = keyFactory.generatePublic(keySpec);
+ Signature signature = Signature.getInstance("SHA256withRSA");
+ signature.initVerify(publicK);
+ signature.update(content);
+ return signature.verify(base642Byte(sign));
+ }
+
+ /**
+ * 字节数组转Base64编码
+ */
+ public static String byte2Base64(byte[] bytes) {
+ Base64.Encoder encoder = Base64.getEncoder();
+ return encoder.encodeToString(bytes);
+ }
+
+ /**
+ * Base64编码转字节数组
+ */
+ public static byte[] base642Byte(String base64Key) {
+ Base64.Decoder decoder = Base64.getDecoder();
+ return decoder.decode(base64Key);
+ }
+
+ /**
+ * 分片处理长度超过RSA支持范文的明文数据
+ *
+ * @param content 加密/解密内容
+ * @param cipher 加密/解密算法
+ * @param slice 分片长度
+ * @return 分片加密/解密后整合的数据
+ */
+ private static byte[] fragment(byte[] content, Cipher cipher, int slice) throws Exception {
+ int inputLength = content.length;
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ byte[] cache;
+ int i = 0, offset = 0;
+ while (inputLength - offset > 0) {
+ if (inputLength - offset > slice) {
+ cache = cipher.doFinal(content, offset, slice);
+ } else {
+ cache = cipher.doFinal(content, offset, inputLength - offset);
+ }
+ byteArrayOutputStream.write(cache, 0, cache.length);
+ offset = slice * ++i;
+ }
+ byte[] resultBytes = byteArrayOutputStream.toByteArray();
+ byteArrayOutputStream.close();
+ return resultBytes;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/simaek/util/RSAUtilTest.java b/src/test/java/com/simaek/util/RSAUtilTest.java
new file mode 100644
index 0000000..7405d49
--- /dev/null
+++ b/src/test/java/com/simaek/util/RSAUtilTest.java
@@ -0,0 +1,50 @@
+package com.simaek.util;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.security.KeyPair;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 测试RSA加密工具类的加密和解密功能,签名和校验功能
+ *
+ * @author Yaser Hsueh
+ * @see com.simaek.util.RSAUtil
+ */
+class RSAUtilTest {
+ private static String publicKeyString;
+ private static String privateKeyString;
+
+ @BeforeAll
+ static void before() throws Exception {
+ final KeyPair keyPair = RSAUtil.getKeyPair();
+ publicKeyString = RSAUtil.getPublicKey(keyPair);
+ privateKeyString = RSAUtil.getPrivateKey(keyPair);
+ }
+
+ @Test
+ void encryptAndDecrypt() throws Exception {
+ final String origin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ final byte[] bytes = RSAUtil.publicEncrypt(origin.getBytes(), RSAUtil.string2PublicKey(publicKeyString));
+ final String base64 = RSAUtil.byte2Base64(bytes);
+ final byte[] decrypt = RSAUtil.privateDecrypt(RSAUtil.base642Byte(base64), RSAUtil.string2PrivateKey(privateKeyString));
+ final String result = new String(decrypt);
+ System.out.println("Original: " + origin);
+ System.out.println("Encrypted: " + base64);
+ System.out.println("Decrypted: " + result);
+ assertEquals(origin, result);
+ }
+
+ @Test
+ void signAndVerify() throws Exception {
+ final String origin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ final String sign = RSAUtil.privateSign(origin.getBytes(), privateKeyString);
+ final boolean verify = RSAUtil.publicVerify(origin.getBytes(), publicKeyString, sign);
+ System.out.println("Original: " + origin);
+ System.out.println("Signature: " + sign);
+ assertTrue(verify);
+ }
+}
\ No newline at end of file