import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Sha1WithRsaUtil {
static String reqParam = "{'aa':11,'cc':33,'ee':'','bb':22,'signType':'SHA1WithRSA','signData':'aa'}";
static String reqParam2 = "{\"aa\":11,\"cc\":33,\"ee\":\"\",\"bb\":22,\"signType\":\"SHA1WithRSA\",\"signData\":\"aa\"}";
/**
* 加密算法RSA
*/
public static final String RSA_ALGORITHM = "RSA";
/**
* 签名算法
* SHA1WithRSA MD5withRSA
*/
public static final String SIGNATURE_ALGORITHM = "SHA1WithRSA";
/**
* 据说1024 加密不安全,默认 走2048加密
*/
public static final int keySize = 2048;
/**
* 字符串编码
*/
public static final String CHARSET = "UTF-8";
/**
* 忽略不参与签名的参数
*/
private static String signTypeKey = "signType";
private static String signDataKey = "signData";
/**
* 请求参数按照ASCII 码升序排序,并用&连接字符串
*
* @Param reqJson: 请求的json 串
* {'aa':11,'cc':33,'ee':'','bb':22,'signType':'SHA1WithRSA','signData':'aa'}
* @Return: aa=11&bb=22&cc=3
*/
public static String preSignDataProcess(String reqJson) {
if (StringUtils.isEmpty(reqJson)) {
return null;
}
HashMap map = JSON.parseObject(reqJson, new TypeReference>() {
});
List keyList = map.keySet().stream().sorted().collect(Collectors.toList());
StringBuffer sb = new StringBuffer();
keyList.stream().forEach(k -> {
Object v = map.get(k);
if (v != null && !"".equals(v) && !signTypeKey.equals(k) && !signDataKey.equals(k)) {
sb.append(k.trim()).append("=").append(v).append("&");
}
});
if (sb.toString().endsWith("&")) {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
/**
* 创建RSA 原始的公钥私钥
*
* @return
*/
public static Map createKeys() {
return createKeys(keySize);
}
/**
* 获取初始的公钥和私钥
* 1024 2048
*/
private static Map createKeys(int keySize) {
// 为RSA算法创建一个KeyPairGenerator对象
KeyPairGenerator kpg;
try {
kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
}
// 初始化KeyPairGenerator对象,密钥长度
kpg.initialize(keySize);
// 生成密匙对
KeyPair keyPair = kpg.generateKeyPair();
// 得到公钥
Key publicKey = keyPair.getPublic();
String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
// 得到私钥
Key privateKey = keyPair.getPrivate();
String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
Map keyPairMap = new HashMap<>();
keyPairMap.put("publicKey", publicKeyStr);
keyPairMap.put("privateKey", privateKeyStr);
return keyPairMap;
}
/**
* 根据RSA初始公钥 转化为 X509公钥
*
* @param publicKey 密钥字符串(经过base64编码)
* @throws Exception
*/
public static RSAPublicKey getPublicKeyX509(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
// 通过X509编码的Key指令获得公钥对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
return key;
}
/**
* 根据RSA初始私钥 转化为 PKCS8私钥
*
* @param privateKey 密钥字符串(经过base64编码)
* @throws Exception
*/
public static RSAPrivateKey getPrivateKeyPkcs8(String privateKey)
throws NoSuchAlgorithmException, InvalidKeySpecException {
// 通过PKCS#8编码的Key指令获得私钥对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
return key;
}
/**
* 加密操作
* X509 公钥加密(对应 PKCS8 私钥进行解密) 或者 PKCS8 私钥加密(对应X509公钥解密)
*/
private static String encrypt(String data, Key key) {
BigInteger modulus = keyModulus(key);
try {
Cipher cipher = cipherInstance(Cipher.ENCRYPT_MODE, key);
byte[] bytes = rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET),
modulus.bitLength());
return Base64.encodeBase64URLSafeString(bytes);
} catch (Exception e) {
throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
}
}
/**
* 解密操作
* PKCS8 私钥解密(对应 X509 公钥加密)或者 X509 公钥解密(对应 PKCS8 私钥进行加密)
*/
private static String decrypt(String data, Key key) {
BigInteger modulus = keyModulus(key);
Cipher cipher = cipherInstance(Cipher.DECRYPT_MODE, key);
byte[] bytes = rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data),
modulus.bitLength());
try {
return new String(bytes, CHARSET);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("RSA解密失败:", e);
}
}
/**
* RSA签名
*
* @param content 待签名数据
* @param privateKey 商户私钥
* @return 签名值
*/
public static String sign(String content, String privateKey) {
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
KeyFactory keyf = KeyFactory.getInstance(RSA_ALGORITHM);
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(priKey);
signature.update(content.getBytes(CHARSET));
byte[] signed = signature.sign();
return Base64.encodeBase64URLSafeString(signed);
} catch (Exception e) {
throw new RuntimeException("签名发生异常", e);
}
}
/**
* RSA 验签
*
* @param content 待签名数据
* @param sign 签名值
* @param publicKey 分配给开发商公钥
* @return 布尔值
*/
public static boolean verify(String content, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
byte[] encodedKey = Base64.decodeBase64(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(pubKey);
signature.update(content.getBytes(CHARSET));
boolean bverify = signature.verify(Base64.decodeBase64(sign));
return bverify;
} catch (Exception e) {
throw new RuntimeException("RSA 验签失败", e);
}
}
/**
* 分段处理
*
* @param cipher
* @param opmode
* @param datas
* @param keySize
* @return
*/
private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {
int maxBlock = 0;
if (opmode == Cipher.DECRYPT_MODE) {
maxBlock = keySize / 8;
} else {
maxBlock = keySize / 8 - 11;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] buff;
byte[] resultDatas;
Exception e1;
int i = 0;
try {
while (datas.length > offSet) {
if (datas.length - offSet > maxBlock) {
buff = cipher.doFinal(datas, offSet, maxBlock);
} else {
buff = cipher.doFinal(datas, offSet, datas.length - offSet);
}
out.write(buff, 0, buff.length);
i++;
offSet = i * maxBlock;
}
resultDatas = out.toByteArray();
} catch (Exception e) {
throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e);
} finally {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时,关闭流发生异常", e);
}
}
return resultDatas;
}
/**
* 获取加密key的 实例
*/
private static Cipher cipherInstance(int mode, java.security.Key key) {
Cipher cipher = null;
try {
cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(mode, key);
} catch (Exception e) {
throw new RuntimeException("获取Cipher 实例异常:", e);
}
return cipher;
}
private static BigInteger keyModulus(Key key) {
BigInteger modulus = null;
if (key instanceof RSAPublicKey) {
modulus = ((RSAPublicKey) key).getModulus();
} else if (key instanceof RSAPrivateKey) {
modulus = ((RSAPrivateKey) key).getModulus();
}
return modulus;
}
public static void main(String[] args) throws Exception {
Map keyMap = createKeys();
String publicKey = keyMap.get("publicKey");
String privateKey = keyMap.get("privateKey");
System.out.println("原始公钥:\n" + publicKey);
System.out.println("原始私钥:\n" + privateKey);
String content = preSignDataProcess(reqParam);
String sign = sign(content, privateKey);
System.out.println("签名:\n" + sign);
boolean verify = verify(content, sign, publicKey);
System.out.println("验签:" + verify);
String privateEncrypt = encrypt(content, getPrivateKeyPkcs8(privateKey));
System.out.println("PKCS8 私钥加密:\n" + privateEncrypt);
String publicDecrypt = decrypt(privateEncrypt, getPublicKeyX509(publicKey));
System.out.println("X509 公钥解密:\n" + publicDecrypt);
String publicEncrypt = encrypt(content, getPublicKeyX509(publicKey));
System.out.println("X509 公钥加密:\n" + publicEncrypt);
String privateDecrypt = decrypt(publicEncrypt, getPrivateKeyPkcs8(privateKey));
System.out.println("PKCS8 私钥解密:\n" + privateDecrypt);
}
}