Last active
September 12, 2023 07:51
-
-
Save guozi/3d3db4f6958889c8c0c124a14fea8ddf to your computer and use it in GitHub Desktop.
RSA加解密工具类
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.codec.binary.Base64; | |
import org.apache.commons.io.FileUtils; | |
import javax.crypto.Cipher; | |
import java.io.ByteArrayOutputStream; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.ObjectInputStream; | |
import java.io.ObjectOutputStream; | |
import java.nio.charset.StandardCharsets; | |
import java.nio.file.Files; | |
import java.nio.file.Paths; | |
import java.security.Key; | |
import java.security.KeyFactory; | |
import java.security.KeyPair; | |
import java.security.KeyPairGenerator; | |
import java.security.PrivateKey; | |
import java.security.PublicKey; | |
import java.security.SecureRandom; | |
import java.security.Signature; | |
import java.security.interfaces.RSAPrivateKey; | |
import java.security.interfaces.RSAPublicKey; | |
import java.security.spec.PKCS8EncodedKeySpec; | |
import java.security.spec.X509EncodedKeySpec; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* <p> | |
* RSA公钥/私钥/签名工具包 | |
* </p> | |
* <p> | |
* 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman) | |
* </p> | |
* <p> | |
* 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/> | |
* 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/> | |
* 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全 | |
* </p> | |
* | |
* @author monkey | |
* @date 2018-10-29 | |
*/ | |
public class RSAUtils { | |
/** | |
* 加密算法RSA | |
*/ | |
public static final String KEY_ALGORITHM = "RSA"; | |
/** | |
* 签名算法 | |
*/ | |
public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; | |
/** | |
* 获取公钥的key | |
*/ | |
private static final String PUBLIC_KEY = "RSAPublicKey"; | |
/** | |
* 获取私钥的key | |
*/ | |
private static final String PRIVATE_KEY = "RSAPrivateKey"; | |
/** | |
* RSA 密钥位数 | |
*/ | |
private static final int KEY_SIZE = 1024; | |
/** | |
* RSA最大解密密文大小 | |
*/ | |
private static final int MAX_DECRYPT_BLOCK = KEY_SIZE / 8; | |
/** | |
* RSA最大加密明文大小 | |
*/ | |
private static final int MAX_ENCRYPT_BLOCK = MAX_DECRYPT_BLOCK - 11; | |
/** | |
* <p> | |
* 生成密钥对(公钥和私钥) | |
* </p> | |
* | |
* @return | |
* @throws Exception | |
*/ | |
public static Map<String, Object> genKeyPair() throws Exception { | |
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); | |
keyPairGen.initialize(KEY_SIZE); | |
KeyPair keyPair = keyPairGen.generateKeyPair(); | |
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); | |
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); | |
Map<String, Object> keyMap = new HashMap<>(2); | |
keyMap.put(PUBLIC_KEY, publicKey); | |
keyMap.put(PRIVATE_KEY, privateKey); | |
return keyMap; | |
} | |
/** | |
* <p> | |
* 用私钥对信息生成数字签名 | |
* </p> | |
* | |
* @param data 已加密数据 | |
* @param privateKey 私钥(BASE64编码) | |
* @return | |
* @throws Exception | |
*/ | |
public static String sign(byte[] data, String privateKey) throws Exception { | |
byte[] keyBytes = Base64.decodeBase64(privateKey); | |
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); | |
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); | |
PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); | |
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); | |
signature.initSign(privateK); | |
signature.update(data); | |
return Base64.encodeBase64String(signature.sign()); | |
} | |
/** | |
* <p> | |
* 校验数字签名 | |
* </p> | |
* | |
* @param data 已加密数据 | |
* @param publicKey 公钥(BASE64编码) | |
* @param sign 数字签名 | |
* @return | |
* @throws Exception | |
*/ | |
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { | |
byte[] keyBytes = Base64.decodeBase64(publicKey); | |
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); | |
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); | |
PublicKey publicK = keyFactory.generatePublic(keySpec); | |
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); | |
signature.initVerify(publicK); | |
signature.update(data); | |
return signature.verify(Base64.decodeBase64(sign)); | |
} | |
/** | |
* <P> | |
* 私钥解密 | |
* </p> | |
* | |
* @param encryptedData 已加密数据 | |
* @param privateKey 私钥(BASE64编码) | |
* @return | |
* @throws Exception | |
*/ | |
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception { | |
byte[] keyBytes = Base64.decodeBase64(privateKey); | |
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); | |
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); | |
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); | |
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); | |
cipher.init(Cipher.DECRYPT_MODE, privateK); | |
int inputLen = encryptedData.length; | |
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |
int offSet = 0; | |
byte[] cache; | |
int i = 0; | |
// 对数据分段解密 | |
while (inputLen - offSet > 0) { | |
if (inputLen - offSet > MAX_DECRYPT_BLOCK) { | |
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); | |
} else { | |
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); | |
} | |
out.write(cache, 0, cache.length); | |
i++; | |
offSet = i * MAX_DECRYPT_BLOCK; | |
} | |
byte[] decryptedData = out.toByteArray(); | |
out.close(); | |
return decryptedData; | |
} | |
/** | |
* <p> | |
* 公钥解密 | |
* </p> | |
* | |
* @param encryptedData 已加密数据 | |
* @param publicKey 公钥(BASE64编码) | |
* @return | |
* @throws Exception | |
*/ | |
public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception { | |
byte[] keyBytes = Base64.decodeBase64(publicKey); | |
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); | |
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); | |
Key publicK = keyFactory.generatePublic(x509KeySpec); | |
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); | |
cipher.init(Cipher.DECRYPT_MODE, publicK); | |
int inputLen = encryptedData.length; | |
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |
int offSet = 0; | |
byte[] cache; | |
int i = 0; | |
// 对数据分段解密 | |
while (inputLen - offSet > 0) { | |
if (inputLen - offSet > MAX_DECRYPT_BLOCK) { | |
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); | |
} else { | |
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); | |
} | |
out.write(cache, 0, cache.length); | |
i++; | |
offSet = i * MAX_DECRYPT_BLOCK; | |
} | |
byte[] decryptedData = out.toByteArray(); | |
out.close(); | |
return decryptedData; | |
} | |
/** | |
* <p> | |
* 公钥加密 | |
* </p> | |
* | |
* @param data 源数据 | |
* @param publicKey 公钥(BASE64编码) | |
* @return | |
* @throws Exception | |
*/ | |
public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception { | |
byte[] keyBytes = Base64.decodeBase64(publicKey); | |
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); | |
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); | |
Key publicK = keyFactory.generatePublic(x509KeySpec); | |
// 对数据加密 | |
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); | |
cipher.init(Cipher.ENCRYPT_MODE, publicK); | |
int inputLen = data.length; | |
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |
int offSet = 0; | |
byte[] cache; | |
int i = 0; | |
// 对数据分段加密 | |
while (inputLen - offSet > 0) { | |
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { | |
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); | |
} else { | |
cache = cipher.doFinal(data, offSet, inputLen - offSet); | |
} | |
out.write(cache, 0, cache.length); | |
i++; | |
offSet = i * MAX_ENCRYPT_BLOCK; | |
} | |
byte[] encryptedData = out.toByteArray(); | |
out.close(); | |
return encryptedData; | |
} | |
/** | |
* <p> | |
* 私钥加密 | |
* </p> | |
* | |
* @param data 源数据 | |
* @param privateKey 私钥(BASE64编码) | |
* @return | |
* @throws Exception | |
*/ | |
public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception { | |
byte[] keyBytes = Base64.decodeBase64(privateKey); | |
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); | |
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); | |
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); | |
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); | |
cipher.init(Cipher.ENCRYPT_MODE, privateK); | |
int inputLen = data.length; | |
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |
int offSet = 0; | |
byte[] cache; | |
int i = 0; | |
// 对数据分段加密 | |
while (inputLen - offSet > 0) { | |
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { | |
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); | |
} else { | |
cache = cipher.doFinal(data, offSet, inputLen - offSet); | |
} | |
out.write(cache, 0, cache.length); | |
i++; | |
offSet = i * MAX_ENCRYPT_BLOCK; | |
} | |
byte[] encryptedData = out.toByteArray(); | |
out.close(); | |
return encryptedData; | |
} | |
/** | |
* <p> | |
* 获取私钥 | |
* </p> | |
* | |
* @param keyMap 密钥对 | |
* @return | |
* @throws Exception | |
*/ | |
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { | |
Key key = (Key) keyMap.get(PRIVATE_KEY); | |
return Base64.encodeBase64String(key.getEncoded()); | |
} | |
/** | |
* <p> | |
* 获取公钥 | |
* </p> | |
* | |
* @param keyMap 密钥对 | |
* @return | |
* @throws Exception | |
*/ | |
public static String getPublicKey(Map<String, Object> keyMap) throws Exception { | |
Key key = (Key) keyMap.get(PUBLIC_KEY); | |
return Base64.encodeBase64String(key.getEncoded()); | |
} | |
/** | |
* 生成公私钥文件 | |
* | |
* @param publicFilePath 存储公钥的路径和文件名,例如:D:/pub/public.key | |
* @param privateFilePath 存储私钥的路径和文件名,例如:D:/pri/private.key | |
* @throws Exception | |
*/ | |
public static void createKey(String publicFilePath, String privateFilePath, int keySize) throws Exception { | |
// 生成密钥对 | |
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); | |
keyGen.initialize(keySize, new SecureRandom()); | |
KeyPair pair = keyGen.generateKeyPair(); | |
// 将已编码的密钥(公钥和私钥)字节写到文件中 | |
write(publicFilePath, pair.getPublic()); | |
write(privateFilePath, pair.getPrivate()); | |
} | |
/** | |
* 功能描述: <br> | |
* 写入一个对象 | |
* | |
* @param path 路径 | |
* @param key 密钥对象 | |
* @throws Exception | |
*/ | |
private static void write(String path, Object key) throws Exception { | |
File file = new File(path); | |
if (!file.getParentFile().exists()) { | |
// 创建文件目录 | |
boolean create = file.getParentFile().mkdirs(); | |
if (!create) { | |
return; | |
} | |
} | |
try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get(path)))) { | |
oos.writeObject(key); | |
} catch (Exception e) { | |
throw new Exception("密钥写入异常", e); | |
} | |
} | |
/** | |
* 功能描述: <br> | |
* 根据公钥文件存放位置解析为公钥对象 | |
* | |
* @param path 存放位置,例如:D:/pub/public.key | |
* @return | |
* @throws Exception | |
*/ | |
public static PublicKey resolvePublicKey(String path) throws Exception { | |
try (FileInputStream fis = FileUtils.openInputStream(new File(path)); | |
ObjectInputStream ois = new ObjectInputStream(fis) | |
) { | |
return (PublicKey) ois.readObject(); | |
} | |
} | |
/** | |
* 根据私钥文件存放位置解析为私钥对象 | |
* | |
* @param path 存放位置,例如:D:/pri/private.key | |
* @return | |
* @throws Exception | |
*/ | |
public static PrivateKey resolvePrivateKey(String path) throws Exception { | |
try (FileInputStream fis = FileUtils.openInputStream(new File(path)); | |
ObjectInputStream ois = new ObjectInputStream(fis) | |
) { | |
return (PrivateKey) ois.readObject(); | |
} | |
} | |
/** | |
* 将传入的公钥对象转换为经过Base64编码后的公钥字符串 | |
* | |
* @param pubKey | |
* @return | |
*/ | |
public static String getBase64PublicKeyString(PublicKey pubKey) { | |
return Base64.encodeBase64String(pubKey.getEncoded()).trim(); | |
} | |
/** | |
* 将传入的私钥对象转换为经过Base64编码后的私钥字符串 | |
* | |
* @param priKey | |
* @return | |
*/ | |
public static String getBase64PrivateKeyString(PrivateKey priKey) { | |
return Base64.encodeBase64String(priKey.getEncoded()).trim(); | |
} | |
/** | |
* 将传入的公钥存储路径读取公钥后转换为经过Base64编码后的公钥字符串 | |
* | |
* @param path 存放位置,例如:D:/pub/public.key | |
* @return | |
* @throws Exception | |
*/ | |
public static String getBase64PublicKeyString(String path) throws Exception { | |
PublicKey pubKey = resolvePublicKey(path); | |
return getBase64PublicKeyString(pubKey); | |
} | |
/** | |
* 将传入的私钥存储路径读取私钥后转换为经过Base64编码后的私钥字符串 | |
* | |
* @param path 存放位置,例如:D:/pri/private.key | |
* @return | |
* @throws Exception | |
*/ | |
public static String getBase64PrivateKeyString(String path) throws Exception { | |
PrivateKey priKey = resolvePrivateKey(path); | |
return getBase64PrivateKeyString(priKey); | |
} | |
/** | |
* java端公钥加密 | |
*/ | |
public static String encryptedDataOnJava(String data, String publicKey) throws Exception { | |
return Base64.encodeBase64String(encryptByPublicKey(data.getBytes(), publicKey)); | |
} | |
/** | |
* java端私钥解密 | |
*/ | |
public static String decryptDataOnJava(String data, String privateKey) throws Exception { | |
byte[] rs = Base64.decodeBase64(data); | |
return new String(RSAUtil.decryptByPrivateKey(rs, privateKey), StandardCharsets.UTF_8); | |
} | |
public static void main(String[] args) throws Exception { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment