我们CTO是个二逼,在与第三方对接时,需要传输加密,调研了一天,发现rsa加密最符合我们的需求,便在网上搜索了Java如何实现RSA加密,二逼CTO看到后说不够洁癖,我就缝缝补补,最终版,拿走即用
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.Serial;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
/**
* RSA加密算法是一种非对称加密算法
*
* @author 老子
* @since 1.0.0
*/
public final class RsaCipherUtils {
private static final String ALGORITHM = "RSA";
private static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
private static final String SIGN_ALGORITHMS = "SHA1WithRSA";
/**
* RSA key长度
*/
public static final int KEY_SIZE = 1024;
private final String publicKey;
private final String privateKey;
public RsaCipherUtils() {
this(KEY_SIZE);
}
public RsaCipherUtils(int keySize) {
Cipher cipher = createKeys(keySize);
this.publicKey = cipher.getPublicKey();
this.privateKey = cipher.getPrivateKey();
}
public RsaCipherUtils(String publicKey, String privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public static RsaCipherUtils buildPublicKey(String publicKey) {
return new RsaCipherUtils(publicKey, null);
}
public static RsaCipherUtils buildPrivateKey(String privateKey) {
return new RsaCipherUtils(null, privateKey);
}
public static Cipher createKeys() {
return createKeys(KEY_SIZE);
}
public static Cipher createKeys(int keySize) {
// 为RSA算法创建一个KeyPairGenerator对象
KeyPairGenerator kpg;
try {
kpg = KeyPairGenerator.getInstance(ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new BusinessException("No such algorithm-->[" + ALGORITHM + "]");
}
// 初始化KeyPairGenerator对象,密钥长度
kpg.initialize(keySize);
// 生成密匙对
KeyPair keyPair = kpg.generateKeyPair();
// 得到公钥
Key publicKey = keyPair.getPublic();
// 得到私钥
Key privateKey = keyPair.getPrivate();
Base64.Encoder encoder = Base64.getEncoder();
return new Cipher(encoder.encodeToString(publicKey.getEncoded()),
encoder.encodeToString(privateKey.getEncoded()));
}
/**
* 使用公钥进行加密
*
* @param plaintext .
* @return {byte[]}
*/
private byte[] encrypt(byte[] plaintext) {
try {
// 使用默认RSA
RSAPublicKey publicKey = createPublicKey(this.publicKey);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(ALGORITHM);
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, publicKey);
int bitLengthOfPuk = publicKey.getModulus().bitLength() / 8;
int blockSize = bitLengthOfPuk - 11;
if (plaintext.length > blockSize) {
List<byte[]> blocks = block(plaintext, blockSize);
ByteBuffer buffer = ByteBuffer.allocate(blocks.size() * bitLengthOfPuk);
for (byte[] block : blocks) {
buffer.put(cipher.doFinal(block));
}
return buffer.array();
} else {
return cipher.doFinal(plaintext);
}
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException |
BadPaddingException | InvalidKeySpecException e) {
throw new BusinessException("加密失败", e);
}
}
/**
* 使用公钥进行加密
*
* @param plaintext .
* @return {byte[]}
*/
public String encrypt(String plaintext) {
return Base64.getEncoder().encodeToString(encrypt(plaintext.getBytes()));
}
/**
* 使用私钥进行解密
*
* @param ciphertext .
* @return {byte[]}
*/
private byte[] decrypt(byte[] ciphertext) {
try {
// 使用默认RSA
RSAPrivateKey privateKey = createPrivateKey(this.privateKey);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, privateKey);
int blockSize = privateKey.getModulus().bitLength() / 8;
if (ciphertext.length > blockSize) {
List<byte[]> blocks = block(ciphertext, blockSize);
ByteBuffer buffer = ByteBuffer.allocate(blocks.size() * blockSize);
for (byte[] block : blocks) {
buffer.put(cipher.doFinal(block));
}
buffer.flip();
byte[] result = new byte[buffer.limit()];
buffer.get(result);
return result;
} else {
return cipher.doFinal(ciphertext);
}
} catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException |
NoSuchPaddingException | InvalidKeySpecException e) {
throw new BusinessException("解密失败", e);
}
}
/**
* 使用私钥进行解密
*
* @param ciphertext .
* @return {byte[]}
*/
public String decrypt(String ciphertext) {
byte[] decode;
Base64.Decoder decoder = Base64.getDecoder();
try {
decode = decoder.decode(ciphertext);
} catch (Exception e) {
decode = decoder.decode(ciphertext.getBytes(StandardCharsets.UTF_8));
}
return new String(decrypt(decode));
}
private RSAPublicKey createPublicKey(String puk) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] buffer = Base64.getDecoder().decode(puk);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
KeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
private RSAPrivateKey createPrivateKey(String prk) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] buffer = Base64.getDecoder().decode(prk);
KeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
/**
* 签名
*
* @param data .
* @param nonce .
* @return {byte[]}
*/
public byte[] sign(byte[] data, byte[] nonce) {
try {
PrivateKey privateKey = createPrivateKey(this.privateKey);
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
signature.initSign(privateKey);
byte[] withSalt = concat(data, nonce);
signature.update(withSalt);
return signature.sign();
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | InvalidKeySpecException e) {
throw new BusinessException("签名失败", e);
}
}
/**
* 验签
*
* @param data .
* @param nonce .
* @param signature .
* @return {boolean}
*/
public boolean verify(byte[] data, byte[] nonce, byte[] signature) {
try {
PublicKey publicKey = createPublicKey(this.publicKey);
Signature instance = Signature.getInstance(SIGN_ALGORITHMS);
instance.initVerify(publicKey);
byte[] withSalt = concat(data, nonce);
instance.update(withSalt);
return instance.verify(signature);
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) {
throw new BusinessException("签名验证失败", e);
}
}
private byte[] concat(byte[] b1, byte[] b2) {
byte[] withSalt = new byte[b1.length + b2.length];
System.arraycopy(b1, 0, withSalt, 0, b1.length);
System.arraycopy(b2, 0, withSalt, b1.length, b2.length);
return withSalt;
}
private List<byte[]> block(byte[] src, int blockSize) {
int group;
if (src.length % blockSize == 0) {
group = src.length / blockSize;
} else {
group = src.length / blockSize + 1;
}
List<byte[]> blocks = new ArrayList<>();
for (int i = 0; i < group; i++) {
int from = i * blockSize;
int to = Math.min(src.length, (i + 1) * blockSize);
byte[] block = Arrays.copyOfRange(src, from, to);
blocks.add(block);
}
return blocks;
}
public String getPublicKey() {
return publicKey;
}
public String getPrivateKey() {
return privateKey;
}
public static class Cipher {
/**
* 公钥
*/
private String publicKey;
/**
* 私钥
*/
private String privateKey;
public Cipher(String publicKey, String privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public String getPublicKey() {
return publicKey;
}
public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}
public String getPrivateKey() {
return privateKey;
}
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
}
}
下面展示此工具类的使用方式
public static void main(String[] args) {
// 提供三种构造方式来获取 RsaCipherUtils 实例
// 方式一: keySize 默认 1024
RsaCipherUtils utils = new RsaCipherUtils();
// 方式二: 指定 keySize 大小
//utils = new RsaCipherUtils(2048);
// 方式三: 通过公钥和私钥构造
//utils = new RsaCipherUtils("", "");
// 获取公钥
String publicKey = utils.getPublicKey();
System.out.println("公钥:" + publicKey);
// 获取私钥
String privateKey = utils.getPrivateKey();
System.out.println("私钥:" + privateKey);
// 加密
String encrypt = utils.encrypt("abc");
System.out.println("加密后的结果:" + encrypt);
// 解密
String decrypt = utils.decrypt(encrypt);
System.out.println("结密后的结果:" + decrypt);
}
运行结果
公钥:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQ5isPrFOPkAk+5bqqye2noPXjH6FUzmwxXNJCTrp33/SQEVigcPAcMS75GL6vANiCoflscTIUza5EsxJ5UJvMcgepdZkFdiUFRZXYB0kcjrTD7FchyHJqKD4sPH/gbD0Ygd+rD3hbAdhnBPfUUqUsP4QW0cNrjZTln/8/5vNK/QIDAQAB
私钥:MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJDmKw+sU4+QCT7luqrJ7aeg9eMfoVTObDFc0kJOunff9JARWKBw8BwxLvkYvq8A2IKh+WxxMhTNrkSzEnlQm8xyB6l1mQV2JQVFldgHSRyOtMPsVyHIcmooPiw8f+BsPRiB36sPeFsB2GcE99RSpSw/hBbRw2uNlOWf/z/m80r9AgMBAAECgYBCq40TrJRUIY+Hf7eIftnZP8/zfanDNimE+vMJrGTS5FqIcVrIk75/EkhNOAwAxNBaJwH3WgwTk2HEXWq6JBNS6L37QmgEFbjwMhGar18pM51JevNHrhw9aQ88HqSPEIVMOiKFENm1OCLnLVMMl89tlRxKziy0SXxSFw5NrogOhwJBALz/02Es9wsZzJ5KqX3n7FCKaiFD627sWgLf2PRXmIFZVSrzi0bPVzzC+C/kzor+Y3WY5PC8DzAnFlK4n2XWfNcCQQDERCI6cdm+CKmRy6G3JOpzntCPmDjhauZ/ZTNMXMh99e2//fAaX+j7cidgqJj2E6ba/g4jVjeFzfvToQ9/ughLAkEAtISU3QgZndyyd65QXRWbvQG3hLZetL/C6WPs0NSpsUIl+rRLnwKDDGIcs4ITVObNEJFMejLlPtTWmYQFmztWWQJBAJNY26GpK+Hhuvy8NlK7IlFfYBEOJVYG3bmzDoo79kGqyq2jRglnDBEKqMmGih/krRYoOhEJf3GzLWa6uloYHnUCQQCyeL4YRDLw2paPNKwr30sSAw0rDx5plZYTL3y4ILHo0IKTg/Gv4MHhAoTlG0ce1Et4fpqMlZ06KFI6kl2T+84g
加密后的结果:b1QAAqa52JCSyah7qveSkHJ0X15AXhSs1g7Pk2j2SUG9G0u9iCZl9WTJbs1eOJ3FdNqoxelqOA78t2/MBo/TrgZu4YNaJVdgqoo7C75ihOxMWmxMNhWLOV9GEnPK3kuiHBlUGwZHyfruSsiOdO3kWoVyW82/y36zsjiKwdfXUlY=
解密后的结果:abc