新增RSA加解密和签名校验工具
This commit is contained in:
parent
774d2d0533
commit
ab645264df
9
pom.xml
9
pom.xml
@ -8,6 +8,15 @@
|
|||||||
<artifactId>utils</artifactId>
|
<artifactId>utils</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<version>5.8.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
173
src/main/java/com/simaek/util/RSAUtil.java
Normal file
173
src/main/java/com/simaek/util/RSAUtil.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
50
src/test/java/com/simaek/util/RSAUtilTest.java
Normal file
50
src/test/java/com/simaek/util/RSAUtilTest.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user