package com.qytb.utils;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.Base64Utils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static com.qytb.utils.IDRSAUtils.getPrivateKey;
import static com.qytb.utils.IDRSAUtils.getPublicKey;
public class RSAUtil {
/**
* RSA密钥长度必须是64的倍数,在512~65536之间。默认是1024
*/
public static final int KEY_SIZE = 1024;
private static Map<Integer, String> keyMap = new HashMap<Integer, String>(); //用于封装随机产生的公钥与私钥
public static void main(String[] args) throws Exception {
// //生成公钥和私钥
// genKeyPair();
// //加密字符串
// String message = "df723820";
// System.out.println("随机生成的公钥为:" + keyMap.get(0));
// System.out.println("随机生成的私钥为:" + keyMap.get(1));
// String messageEn = encrypt(message, keyMap.get(0));
// System.out.println(message + "\t加密后的字符串为:" + messageEn);
// String messageDe = decrypt(messageEn, keyMap.get(1));
// System.out.println("还原后的字符串为:" + messageDe);
HashMap<Object, Object> map = new HashMap<>();
map.put("aa","dfasddfd");
String publicKey = readConfig.getConfig("publicKey");
String encrypt = encrypt(map.toString(), publicKey);
System.out.println("加密内容========================="+encrypt);
}
/**
* 随机生成密钥对
*
* @throws NoSuchAlgorithmException
*/
public static void genKeyPair() throws NoSuchAlgorithmException {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024, new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
// 将公钥和私钥保存到Map
keyMap.put(0, publicKeyString); //0表示公钥
keyMap.put(1, privateKeyString); //1表示私钥
}
/**
* RSA公钥加密
*
* @param str 加密字符串
* @param publicKey 公钥
* @return 密文
* @throws Exception 加密过程中的异常信息
*/
public static String encrypt(String str, String publicKey) throws Exception {
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
return encipher(str,pubKey , KEY_SIZE / 8 - 11);
}
public static String encryptone( String str, String publicKey ) throws Exception{
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
/**
* 分段加密
*
* @param ciphertext 密文
* @param key 加密秘钥
* @param segmentSize 分段大小,<=0 不分段
* @return
*/
public static String encipher(String ciphertext, java.security.Key key, int segmentSize) {
try {
// 用公钥加密
byte[] srcBytes = ciphertext.getBytes("UTF-8");
// Cipher负责完成加密或解密工作,基于RSA
Cipher cipher = Cipher.getInstance("RSA");
// 根据公钥,对Cipher对象进行初始化
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] resultBytes = null;
if (segmentSize > 0) {
resultBytes = cipherDoFinal(cipher, srcBytes, segmentSize);
}
else{
resultBytes = cipher.doFinal(srcBytes);}
//String decrytStr = new String(resultBytes);
//String decrytStr = new String(resultBytes,"UTF-8");
String decrytStr = Base64Utils.encodeToString(resultBytes);
return decrytStr;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 使用私钥解密
*
* @param contentBase64 待解密内容,base64 编码
* @param privateKeyBase64 私钥 base64 编码
* @return
* @segmentSize 分段大小
*/
public static String decrypt (String contentBase64, String privateKeyBase64){
return decipher(contentBase64, privateKeyBase64, KEY_SIZE / 8);
}
/**
* 使用私钥解密(分段解密)
*
* @param contentBase64 待加密内容,base64 编码
* @param privateKeyBase64 私钥 base64 编码
* @return
* @segmentSize 分段大小
*/
public static String decipher (String contentBase64, String privateKeyBase64,int segmentSize){
try {
PrivateKey privateKey = getPrivateKey(privateKeyBase64);
return decipher(contentBase64, privateKey, segmentSize);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 分段解密
*
* @param contentBase64 密文
* @param key 解密秘钥
* @param segmentSize 分段大小(小于等于0不分段)
* @return
*/
public static String decipher (String contentBase64, java.security.Key key,int segmentSize){
try {
// 用私钥解密
byte[] srcBytes = Base64Utils.decodeFromString(contentBase64);
int length = srcBytes.length;
// Cipher负责完成加密或解密工作,基于RSA
Cipher deCipher = Cipher.getInstance("RSA");
// 根据公钥,对Cipher对象进行初始化
deCipher.init(Cipher.DECRYPT_MODE, key);
byte[] decBytes = null;//deCipher.doFinal(srcBytes);
if (segmentSize > 0) {
decBytes = cipherDoFinal(deCipher, srcBytes, segmentSize); //分段
}
else{
decBytes = deCipher.doFinal(srcBytes);
}
String decrytStr = new String(decBytes,"UTF-8");
return decrytStr;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] cipherDoFinal (Cipher cipher,byte[] srcBytes, int segmentSize)
throws IllegalBlockSizeException, BadPaddingException, IOException {
if (segmentSize <= 0) {
throw new RuntimeException("分段大小必须大于0");
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
int inputLen = srcBytes.length;
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > segmentSize) {
int length = srcBytes.length;
cache = cipher.doFinal(srcBytes, offSet, segmentSize);
} else {
cache = cipher.doFinal(srcBytes, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * segmentSize;
}
byte[] data = out.toByteArray();
out.close();
return data;
}
}