AESUtil
import com.xxx.common.BssException;
import com.xxx.common.constants.CommonConstants; import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException; /**
* AES 加密工具,密钥长度为128bit
*
* @author yangyongjie
* @date 2019/10/23
* @desc
*/ public class AESUtil {
private AESUtil() {
} private static final String AES_ALG = "AES"; /**
* AES算法
*/
private static final String AES_CBC_PCK_ALG = "AES/CBC/PKCS5Padding"; private static final byte[] AES_IV = initIv(AES_CBC_PCK_ALG); /**
* 加密
*
* @param content
* @param encryptType
* @param encryptKey
* @param charset
* @return
* @throws BssException
*/
public static String encryptContent(String content, String encryptType, String encryptKey,
String charset) throws BssException { if (AES_ALG.equals(encryptType)) { return aesEncrypt(content, encryptKey, charset); } else { throw new BssException("当前不支持该算法类型:encrypeType=" + encryptType);
} } /**
* 解密
*
* @param content
* @param encryptType
* @param encryptKey
* @param charset
* @return
* @throws BssException
*/
public static String decryptContent(String content, String encryptType, String encryptKey,
String charset) throws BssException { if (AES_ALG.equals(encryptType)) { return aesDecrypt(content, encryptKey, charset); } else { throw new BssException("当前不支持该算法类型:encrypeType=" + encryptType);
} } /**
* AES加密,编码默认为UTF-8
*
* @param content
* @param aesKey
* @return
* @throws BssException
*/
public static String aesEncrypt(String content, String aesKey) throws BssException {
return aesEncrypt(content, aesKey, CommonConstants.CHARSET_UTF8);
} /**
* AES加密
*
* @param content
* @param aesKey
* @param charset
* @return
* @throws BssException
*/
private static String aesEncrypt(String content, String aesKey, String charset)
throws BssException { try {
Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG); IvParameterSpec iv = new IvParameterSpec(AES_IV);
cipher.init(Cipher.ENCRYPT_MODE,
new SecretKeySpec(Base64.decodeBase64(aesKey.getBytes()), AES_ALG), iv); byte[] encryptBytes = cipher.doFinal(content.getBytes(charset));
return new String(Base64.encodeBase64(encryptBytes));
} catch (Exception e) {
throw new BssException("AES加密失败:Aescontent = " + content + "; charset = "
+ charset, e);
} } /**
* AES解密,编码默认为UTF-8
*
* @param content
* @param key
* @return
* @throws BssException
*/
public static String aesDecrypt(String content, String key) throws BssException {
return aesDecrypt(content, key, CommonConstants.CHARSET_UTF8);
} /**
* AES解密
*
* @param content
* @param key
* @param charset
* @return
* @throws BssException
*/
private static String aesDecrypt(String content, String key, String charset)
throws BssException {
try {
Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG);
IvParameterSpec iv = new IvParameterSpec(initIv(AES_CBC_PCK_ALG));
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(key.getBytes()),
AES_ALG), iv); byte[] cleanBytes = cipher.doFinal(Base64.decodeBase64(content.getBytes()));
return new String(cleanBytes, charset);
} catch (Exception e) {
throw new BssException("AES解密失败:Aescontent = " + content + "; charset = "
+ charset, e);
}
} /**
* 初始向量的方法, 全部为0. 这里的写法适合于其它算法,针对AES算法的话,IV值一定是128位的(16字节).
*
* @param fullAlg
* @return
* @throws GeneralSecurityException
*/
private static byte[] initIv(String fullAlg) { try {
Cipher cipher = Cipher.getInstance(fullAlg);
int blockSize = cipher.getBlockSize();
byte[] iv = new byte[blockSize];
for (int i = 0; i < blockSize; ++i) {
iv[i] = 0;
}
return iv;
} catch (Exception e) { int blockSize = 16;
byte[] iv = new byte[blockSize];
for (int i = 0; i < blockSize; ++i) {
iv[i] = 0;
}
return iv;
}
} /**
* 生成AES密钥
* AES分组长度固定为128bit,密钥长度只有128、192和256bit三种
*
* @param length 密钥的长度
* @return
* @throws Exception
*/
public static String generateDesKey(int length) throws Exception {
//实例化
KeyGenerator kgen;
kgen = KeyGenerator.getInstance("AES");
//设置密钥长度
kgen.init(length);
//生成密钥
SecretKey skey = kgen.generateKey();
//返回密钥的二进制编码
byte[] bytes = skey.getEncoded();
// 字节数组转字符串用二进制转16进制的方式
// return byteToHexString(bytes);
// 使用base64转成字符串
return new String(Base64.encodeBase64(bytes));
} /**
* byte数组转化为16进制字符串
*
* @param bytes
* @return
*/
public static String byteToHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
String strHex = Integer.toHexString(bytes[i]);
if (strHex.length() > 3) {
sb.append(strHex.substring(6));
} else {
if (strHex.length() < 2) {
sb.append("0" + strHex);
} else {
sb.append(strHex);
}
}
}
return sb.toString();
} public static void main(String[] args) throws Exception {
String key = generateDesKey(128);
String cipher = aesEncrypt("xiaominiubi", key);
String plain = aesDecrypt(cipher, key); } }
BssException:
/**
* 自定义异常类
*
* @author yangyongjie
* @date 2019/10/23
* @desc
*/
public class BssException extends Exception { private static final long serialVersionUID = -238091758285157331L; private String errCode;
private String errMsg; public BssException() {
super();
} public BssException(String message, Throwable cause) {
super(message, cause);
} public BssException(String message) {
super(message);
} public BssException(Throwable cause) {
super(cause);
} public BssException(String errCode, String errMsg) {
super(errCode + ":" + errMsg);
this.errCode = errCode;
this.errMsg = errMsg;
} public String getErrCode() {
return this.errCode;
} public String getErrMsg() {
return this.errMsg;
}
}
RSA:
密钥长度为1024位的话,最大加密明文大小为117,最大解密密文大小为128
密钥长度为2048位的话,最大加密明文大小为245,最大解密密文大小为256
示例中的密钥长度为1024位,推荐使用2048位
生成2048位的RSA公私钥对:
/**
* 生成2048位的公私钥对
*
* @return
* @throws BssException
*/
public static Map<String, String> genRSAKeyPairs() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
// keySize
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
String priKey = Base64.encodeBase64String(privateKey.getEncoded());
String pubKey = Base64.encodeBase64String(publicKey.getEncoded());
Map<String, String> keyMap = new HashMap<>(4);
keyMap.put("publicKey", pubKey);
keyMap.put("privateKey", priKey);
return keyMap;
}
RSAUtil:
import com.xxx.common.BssException;
import com.xxx.common.SignSourceData;
import com.xxx.common.constants.CommonConstants;
import org.apache.commons.lang3.StringUtils; import javax.crypto.Cipher;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*; /**
* @author yangyongjie
* @date 2019/10/23
* @desc
*/
public class RSAUtil {
private RSAUtil(){}
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117; /**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128; /**
* 公钥加密
*
* @param content 待加密内容
* @param publicKey 公钥
* @param charset 字符集,如UTF-8, GBK, GB2312
* @return 密文内容
* @throws BssException
*/
public static String rsaEncrypt(String content, String publicKey,
String charset) throws BssException {
try {
PublicKey pubKey = getPublicKeyFromX509(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(publicKey.getBytes()));
Cipher cipher = Cipher.getInstance(CommonConstants.SIGN_TYPE_RSA);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] data = StringUtils.isEmpty(charset) ? content.getBytes()
: content.getBytes(charset);
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 = Base64.encodeBase64(out.toByteArray());
out.close(); return StringUtils.isEmpty(charset) ? new String(encryptedData)
: new String(encryptedData, charset);
} catch (Exception e) {
throw new BssException("EncryptContent = " + content + ",charset = " + charset,
e);
}
} /**
* 私钥解密
*
* @param content 待解密内容
* @param privateKey 私钥
* @param charset 字符集,如UTF-8, GBK, GB2312
* @return 明文内容
* @throws BssException
*/
public static String rsaDecrypt(String content, String privateKey,
String charset) throws BssException {
try {
PrivateKey priKey = getPrivateKeyFromPKCS8(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(privateKey.getBytes()));
Cipher cipher = Cipher.getInstance(CommonConstants.SIGN_TYPE_RSA);
cipher.init(Cipher.DECRYPT_MODE, priKey);
byte[] encryptedData = StringUtils.isEmpty(charset)
? Base64.decodeBase64(content.getBytes())
: Base64.decodeBase64(content.getBytes(charset));
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 StringUtils.isEmpty(charset) ? new String(decryptedData)
: new String(decryptedData, charset);
} catch (Exception e) {
throw new BssException("EncodeContent = " + content + ",charset = " + charset, e);
}
} /**
* rsa内容签名
*
* @param content
* @param privateKey
* @param charset
* @return
* @throws BssException
*/
public static String rsaSign(String content, String privateKey, String charset,
String signType) throws BssException { if (CommonConstants.SIGN_TYPE_RSA.equals(signType)) { return rsaSign(content, privateKey, charset);
} else if (CommonConstants.SIGN_TYPE_RSA2.equals(signType)) { return rsa256Sign(content, privateKey, charset);
} else { throw new BssException("Sign Type is Not Support : signType=" + signType);
} } /**
* sha256WithRsa 加签
*
* @param content
* @param privateKey
* @param charset
* @return
* @throws BssException
*/
public static String rsa256Sign(String content, String privateKey,
String charset) throws BssException { try {
PrivateKey priKey = getPrivateKeyFromPKCS8(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(privateKey.getBytes())); Signature signature = Signature
.getInstance(CommonConstants.SIGN_SHA256RSA_ALGORITHMS); signature.initSign(priKey); if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
} byte[] signed = signature.sign(); return new String(Base64.encodeBase64(signed));
} catch (Exception e) {
throw new BssException("RSAcontent = " + content + "; charset = " + charset, e);
} } /**
* sha1WithRsa 加签
*
* @param content
* @param privateKey
* @param charset
* @return
* @throws BssException
*/
public static String rsaSign(String content, String privateKey,
String charset) throws BssException {
try {
PrivateKey priKey = getPrivateKeyFromPKCS8(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(privateKey.getBytes())); Signature signature = Signature
.getInstance(CommonConstants.SIGN_ALGORITHMS); signature.initSign(priKey); if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
} byte[] signed = signature.sign(); return new String(Base64.encodeBase64(signed));
} catch (InvalidKeySpecException ie) {
throw new BssException("RSA私钥格式不正确,请检查是否正确配置了PKCS8格式的私钥", ie);
} catch (Exception e) {
throw new BssException("RSAcontent = " + content + "; charset = " + charset, e);
}
} /**
* @param sortedParams
* @return
*/
public static String getSignContent(Map<String, String> sortedParams) {
StringBuilder content = new StringBuilder();
List<String> keys = new ArrayList<String>(sortedParams.keySet());
Collections.sort(keys);
int index = 0;
for (String key : keys) {
String value = sortedParams.get(key);
if (StringUtil.areNotEmpty(key, value)) {
content.append(index == 0 ? "" : "&").append(key).append("=").append(value);
index++;
}
}
return content.toString();
} public static SignSourceData extractSignContent(String str, int begin) {
if (str == null) {
return null;
} int beginIndex = extractBeginPosition(str, begin);
if (beginIndex >= str.length()) {
return null;
} int endIndex = extractEndPosition(str, beginIndex);
return new SignSourceData(str.substring(beginIndex, endIndex), beginIndex, endIndex);
} private static int extractBeginPosition(String responseString, int begin) {
int beginPosition = begin;
//找到第一个左大括号(对应响应的是JSON对象的情况:普通调用OpenAPI响应明文)
//或者双引号(对应响应的是JSON字符串的情况:加密调用OpenAPI响应Base64串),作为待验签内容的起点
while (beginPosition < responseString.length()
&& responseString.charAt(beginPosition) != '{'
&& responseString.charAt(beginPosition) != '"') {
++beginPosition;
}
return beginPosition;
} private static int extractEndPosition(String responseString, int beginPosition) {
//提取明文验签内容终点
if (responseString.charAt(beginPosition) == '{') {
return extractJsonObjectEndPosition(responseString, beginPosition);
}
//提取密文验签内容终点
else {
return extractJsonBase64ValueEndPosition(responseString, beginPosition);
}
} private static int extractJsonBase64ValueEndPosition(String responseString, int beginPosition) {
for (int index = beginPosition; index < responseString.length(); ++index) {
//找到第2个双引号作为终点,由于中间全部是Base64编码的密文,所以不会有干扰的特殊字符
if (responseString.charAt(index) == '"' && index != beginPosition) {
return index + 1;
}
}
//如果没有找到第2个双引号,说明验签内容片段提取失败,直接尝试选取剩余整个响应字符串进行验签
return responseString.length();
} private static int extractJsonObjectEndPosition(String responseString, int beginPosition) {
//记录当前尚未发现配对闭合的大括号
LinkedList<String> braces = new LinkedList<String>();
//记录当前字符是否在双引号中
boolean inQuotes = false;
//记录当前字符前面连续的转义字符个数
int consecutiveEscapeCount = 0;
//从待验签字符的起点开始遍历后续字符串,找出待验签字符串的终止点,终点即是与起点{配对的}
for (int index = beginPosition; index < responseString.length(); ++index) {
//提取当前字符
char currentChar = responseString.charAt(index); //如果当前字符是"且前面有偶数个转义标记(0也是偶数)
if (currentChar == '"' && consecutiveEscapeCount % 2 == 0) {
//是否在引号中的状态取反
inQuotes = !inQuotes;
}
//如果当前字符是{且不在引号中
else if (currentChar == '{' && !inQuotes) {
//将该{加入未闭合括号中
braces.push("{");
}
//如果当前字符是}且不在引号中
else if (currentChar == '}' && !inQuotes) {
//弹出一个未闭合括号
braces.pop();
//如果弹出后,未闭合括号为空,说明已经找到终点
if (braces.isEmpty()) {
return index + 1;
}
} //如果当前字符是转义字符
if (currentChar == '\\') {
//连续转义字符个数+1
++consecutiveEscapeCount;
} else {
//连续转义字符个数置0
consecutiveEscapeCount = 0;
}
} //如果没有找到配对的闭合括号,说明验签内容片段提取失败,直接尝试选取剩余整个响应字符串进行验签
return responseString.length();
} public static String rsaSign(Map<String, String> params, String privateKey,
String charset) throws BssException {
String signContent = getSignContent(params); return rsaSign(signContent, privateKey, charset); } public static PrivateKey getPrivateKeyFromPKCS8(String algorithm,
InputStream ins) throws Exception {
if (ins == null || StringUtils.isEmpty(algorithm)) {
return null;
} KeyFactory keyFactory = KeyFactory.getInstance(algorithm); byte[] encodedKey = StreamUtil.readText(ins).getBytes(); encodedKey = Base64.decodeBase64(encodedKey); return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
} public static String getSignCheckContentV1(Map<String, String> params) {
if (params == null) {
return null;
} params.remove("sign");
params.remove("sign_type"); StringBuilder content = new StringBuilder();
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys); for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
content.append((i == 0 ? "" : "&") + key + "=" + value);
} return content.toString();
} public static String getSignCheckContentV2(Map<String, String> params) {
if (params == null) {
return null;
} params.remove("sign"); StringBuilder content = new StringBuilder();
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys); for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
content.append(i == 0 ? "" : "&").append(key).append("=").append(value);
} return content.toString();
} /**
* 如果是RSA签名,请调用此方法进行验签
*
* @param params 待验签的从bss接收到的参数Map
* @param publicKey bss公钥
* @param charset 参数内容编码集
* @return true:验签通过;false:验签不通过
* @throws BssException
*/
public static boolean rsaCheckV1(Map<String, String> params, String publicKey,
String charset) throws BssException {
String sign = params.get("sign");
String content = getSignCheckContentV1(params); return rsaCheckContent(content, sign, publicKey, charset);
} public static boolean rsaCertCheckV1(Map<String, String> params, String bssPublicCertPath,
String charset) throws BssException {
String publicKey = getAlipayPublicKey(bssPublicCertPath);
return rsaCheckV1(params, publicKey, charset);
} /**
* 如果是RSA或RSA2签名,请调用此方法进行验签
*
* @param params 待验签的从bss接收到的参数Map
* @param publicKey bss公钥
* @param charset 参数内容编码集
* @param signType 指定采用的签名方式,RSA或RSA2
* @return true:验签通过;false:验签不通过
* @throws BssException
*/
public static boolean rsaCheckV1(Map<String, String> params, String publicKey,
String charset, String signType) throws BssException {
String sign = params.get("sign");
String content = getSignCheckContentV1(params); return rsaCheck(content, sign, publicKey, charset, signType);
} public static boolean rsaCertCheckV1(Map<String, String> params, String alipayPublicCertPath,
String charset, String signType) throws BssException {
String publicKey = getAlipayPublicKey(alipayPublicCertPath);
return rsaCheckV1(params, publicKey, charset, signType);
} public static boolean rsaCheckV2(Map<String, String> params, String publicKey,
String charset) throws BssException {
String sign = params.get("sign");
String content = getSignCheckContentV2(params); return rsaCheckContent(content, sign, publicKey, charset);
} public static boolean rsaCertCheckV2(Map<String, String> params, String alipayPublicCertPath,
String charset) throws BssException {
String publicKey = getAlipayPublicKey(alipayPublicCertPath);
return rsaCheckV2(params, publicKey, charset);
} public static boolean rsaCheckV2(Map<String, String> params, String publicKey,
String charset, String signType) throws BssException {
String sign = params.get("sign");
String content = getSignCheckContentV2(params); return rsaCheck(content, sign, publicKey, charset, signType);
} public static boolean rsaCertCheckV2(Map<String, String> params, String alipayPublicCertPath,
String charset, String signType) throws BssException {
String publicKey = getAlipayPublicKey(alipayPublicCertPath); return rsaCheckV2(params, publicKey, charset, signType);
} public static boolean rsaCheck(String content, String sign, String publicKey, String charset,
String signType) throws BssException { if (CommonConstants.SIGN_TYPE_RSA.equals(signType)) { return rsaCheckContent(content, sign, publicKey, charset); } else if (CommonConstants.SIGN_TYPE_RSA2.equals(signType)) { return rsa256CheckContent(content, sign, publicKey, charset); } else { throw new BssException("Sign Type is Not Support : signType=" + signType);
} } public static boolean rsaCertCheck(String content, String sign, String alipayPublicCertPath, String charset,
String signType) throws BssException {
String publicKey = getAlipayPublicKey(alipayPublicCertPath);
return rsaCheck(content, sign, publicKey, charset, signType);
} public static boolean rsa256CheckContent(String content, String sign, String publicKey,
String charset) throws BssException {
try {
PublicKey pubKey = getPublicKeyFromX509("RSA",
new ByteArrayInputStream(publicKey.getBytes())); Signature signature = Signature
.getInstance(CommonConstants.SIGN_SHA256RSA_ALGORITHMS); signature.initVerify(pubKey); if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
} return signature.verify(Base64.decodeBase64(sign.getBytes()));
} catch (Exception e) {
throw new BssException(
"RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
}
} public static boolean rsaCheckContent(String content, String sign, String publicKey,
String charset) throws BssException {
try {
PublicKey pubKey = getPublicKeyFromX509("RSA",
new ByteArrayInputStream(publicKey.getBytes())); Signature signature = Signature
.getInstance(CommonConstants.SIGN_ALGORITHMS); signature.initVerify(pubKey); if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
} return signature.verify(Base64.decodeBase64(sign.getBytes()));
} catch (Exception e) {
throw new BssException(
"RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
}
} public static PublicKey getPublicKeyFromX509(String algorithm,
InputStream ins) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance(algorithm); StringWriter writer = new StringWriter();
StreamUtil.io(new InputStreamReader(ins), writer); byte[] encodedKey = writer.toString().getBytes(); encodedKey = Base64.decodeBase64(encodedKey); return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
} /**
* 验签并解密
* <p>
* <b>目前适用于公众号</b><br>
* params参数示例:
* <br>{
* <br>biz_content=M0qGiGz+8kIpxe8aF4geWJdBn0aBTuJRQItLHo9R7o5JGhpic/MIUjvXo2BLB++BbkSq2OsJCEQFDZ0zK5AJYwvBgeRX30gvEj6eXqXRt16
* /IkB9HzAccEqKmRHrZJ7PjQWE0KfvDAHsJqFIeMvEYk1Zei2QkwSQPlso7K0oheo/iT+HYE8aTATnkqD
* /ByD9iNDtGg38pCa2xnnns63abKsKoV8h0DfHWgPH62urGY7Pye3r9FCOXA2Ykm8X4/Bl1bWFN/PFCEJHWe/HXj8KJKjWMO6ttsoV0xRGfeyUO8agu6t587Dl5ux5zD
* /s8Lbg5QXygaOwo3Fz1G8EqmGhi4+soEIQb8DBYanQOS3X+m46tVqBGMw8Oe+hsyIMpsjwF4HaPKMr37zpW3fe7xOMuimbZ0wq53YP
* /jhQv6XWodjT3mL0H5ACqcsSn727B5ztquzCPiwrqyjUHjJQQefFTzOse8snaWNQTUsQS7aLsHq0FveGpSBYORyA90qPdiTjXIkVP7mAiYiAIWW9pCEC7F3XtViKTZ8FRMM9ySicfuAlf3jtap6v2KPMtQv70X+hlmzO/IXB6W0Ep8DovkF5rB4r/BJYJLw/6AS0LZM9w5JfnAZhfGM2rKzpfNsgpOgEZS1WleG4I2hoQC0nxg9IcP0Hs+nWIPkEUcYNaiXqeBc=,
* <br>sign=rlqgA8O+RzHBVYLyHmrbODVSANWPXf3pSrr82OCO/bm3upZiXSYrX5fZr6UBmG6BZRAydEyTIguEW6VRuAKjnaO/sOiR9BsSrOdXbD5Rhos/Xt7
* /mGUWbTOt/F+3W0/XLuDNmuYg1yIC/6hzkg44kgtdSTsQbOC9gWM7ayB4J4c=, sign_type=RSA,
* <br>charset=UTF-8
* <br>}
* </p>
*
* @param params
* @param bssPublicKey bss公钥
* @param cusPrivateKey 合作方私钥
* @param isCheckSign 是否验签
* @param isDecrypt 是否解密
* @return 解密后明文,验签失败则异常抛出
* @throws BssException
*/
public static String checkSignAndDecrypt(Map<String, String> params, String bssPublicKey,
String cusPrivateKey, boolean isCheckSign,
boolean isDecrypt) throws BssException {
String charset = params.get("charset");
String bizContent = params.get("biz_content");
if (isCheckSign) {
if (!rsaCheckV2(params, bssPublicKey, charset)) {
throw new BssException("rsaCheck failure:rsaParams=" + params);
}
} if (isDecrypt) {
return rsaDecrypt(bizContent, cusPrivateKey, charset);
} return bizContent;
} /**
* 验签并解密
* <p>
* <b>目前适用于公众号</b><br>
* params参数示例:
* <br>{
* <br>biz_content=M0qGiGz+8kIpxe8aF4geWJdBn0aBTuJRQItLHo9R7o5JGhpic/MIUjvXo2BLB++BbkSq2OsJCEQFDZ0zK5AJYwvBgeRX30gvEj6eXqXRt16
* /IkB9HzAccEqKmRHrZJ7PjQWE0KfvDAHsJqFIeMvEYk1Zei2QkwSQPlso7K0oheo/iT+HYE8aTATnkqD
* /ByD9iNDtGg38pCa2xnnns63abKsKoV8h0DfHWgPH62urGY7Pye3r9FCOXA2Ykm8X4/Bl1bWFN/PFCEJHWe/HXj8KJKjWMO6ttsoV0xRGfeyUO8agu6t587Dl5ux5zD
* /s8Lbg5QXygaOwo3Fz1G8EqmGhi4+soEIQb8DBYanQOS3X+m46tVqBGMw8Oe+hsyIMpsjwF4HaPKMr37zpW3fe7xOMuimbZ0wq53YP
* /jhQv6XWodjT3mL0H5ACqcsSn727B5ztquzCPiwrqyjUHjJQQefFTzOse8snaWNQTUsQS7aLsHq0FveGpSBYORyA90qPdiTjXIkVP7mAiYiAIWW9pCEC7F3XtViKTZ8FRMM9ySicfuAlf3jtap6v2KPMtQv70X+hlmzO/IXB6W0Ep8DovkF5rB4r/BJYJLw/6AS0LZM9w5JfnAZhfGM2rKzpfNsgpOgEZS1WleG4I2hoQC0nxg9IcP0Hs+nWIPkEUcYNaiXqeBc=,
* <br>sign=rlqgA8O+RzHBVYLyHmrbODVSANWPXf3pSrr82OCO/bm3upZiXSYrX5fZr6UBmG6BZRAydEyTIguEW6VRuAKjnaO/sOiR9BsSrOdXbD5Rhos/Xt7
* /mGUWbTOt/F+3W0/XLuDNmuYg1yIC/6hzkg44kgtdSTsQbOC9gWM7ayB4J4c=, sign_type=RSA,
* <br>charset=UTF-8
* <br>}
* </p>
*
* @param params
* @param bssPublicKey bss公钥
* @param cusPrivateKey 合作方私钥
* @param isCheckSign 是否验签
* @param isDecrypt 是否解密
* @return 解密后明文,验签失败则异常抛出
* @throws BssException
*/
public static String checkSignAndDecrypt(Map<String, String> params, String bssPublicKey,
String cusPrivateKey, boolean isCheckSign,
boolean isDecrypt, String signType) throws BssException {
String charset = params.get("charset");
String bizContent = params.get("biz_content");
if (isCheckSign) {
if (!rsaCheckV2(params, bssPublicKey, charset, signType)) {
throw new BssException("rsaCheck failure:rsaParams=" + params);
}
} if (isDecrypt) {
return rsaDecrypt(bizContent, cusPrivateKey, charset);
} return bizContent;
} /**
* 从公钥证书中提取公钥序列号
*
* @param certPath 公钥证书存放路径,例如:/home/admin/cert.crt
* @return 公钥证书序列号
* @throws BssException
*/
public static String getCertSN(String certPath) throws BssException {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(certPath);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
MessageDigest md = MessageDigest.getInstance("MD5");
md.update((cert.getIssuerX500Principal().getName() + cert.getSerialNumber()).getBytes());
String certSN = new BigInteger(1, md.digest()).toString(16);
//BigInteger会把0省略掉,需补全至32位
certSN = fillMD5(certSN);
return certSN; } catch (NoSuchAlgorithmException e) {
throw new BssException(e);
} catch (IOException e) {
throw new BssException(e);
} catch (CertificateException e) {
throw new BssException(e);
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
throw new BssException(e);
}
}
} private static String fillMD5(String md5) {
return md5.length() == 32 ? md5 : fillMD5("0" + md5);
} /**
* 从公钥证书中提取公钥
*
* @param alipayPublicCertPath 公钥证书存放路径,例如:/home/admin/cert.crt
* @return 公钥
* @throws BssException
*/
public static String getAlipayPublicKey(String alipayPublicCertPath) throws BssException {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(alipayPublicCertPath);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
PublicKey publicKey = cert.getPublicKey();
return Base64.encodeBase64String(publicKey.getEncoded());
} catch (IOException e) {
throw new BssException(e);
} catch (CertificateException e) {
throw new BssException(e);
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
throw new BssException(e);
}
}
} // public static String getSignatureContent(RequestParametersHolder requestHolder) {
// return getSignContent(getSortedMap(requestHolder));
// }
//
// public static Map<String, String> getSortedMap(RequestParametersHolder requestHolder) {
// Map<String, String> sortedParams = new TreeMap<String, String>();
// AlipayHashMap appParams = requestHolder.getApplicationParams();
// if (appParams != null && appParams.size() > 0) {
// sortedParams.putAll(appParams);
// }
// AlipayHashMap protocalMustParams = requestHolder.getProtocalMustParams();
// if (protocalMustParams != null && protocalMustParams.size() > 0) {
// sortedParams.putAll(protocalMustParams);
// }
// AlipayHashMap protocalOptParams = requestHolder.getProtocalOptParams();
// if (protocalOptParams != null && protocalOptParams.size() > 0) {
// sortedParams.putAll(protocalOptParams);
// }
//
// return sortedParams;
// }
}
RSAUtil简洁版:
import com.xxx.common.BssException;
import com.xxx.common.constants.CommonConstants;
import org.apache.commons.lang3.StringUtils; import javax.crypto.Cipher;
import java.io.*;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map; /**
* RSA 加解密签名工具类
* 密钥长度为1024位的话,最大加密明文大小为117,最大解密密文大小为128
* 密钥长度为2048位的话,最大加密明文大小为245,最大解密密文大小为256
*
* @author yangyongjie
* @date 2019/10/23
* @desc
*/
public class RSAUtil { private RSAUtil() {
} /**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 245; /**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 256; /**
* 公钥加密,默认字符集 UTF-8
*
* @param content 待加密内容
* @param publicKey 公钥
* @return 密文内容
* @throws BssException
*/
public static String rsaEncrypt(String content, String publicKey) throws BssException {
return rsaEncrypt(content, publicKey, CommonConstants.CHARSET_UTF8);
} /**
* 公钥加密
*
* @param content 待加密内容
* @param publicKey 公钥
* @param charset 字符集,如UTF-8, GBK, GB2312
* @return 密文内容
* @throws BssException
*/
public static String rsaEncrypt(String content, String publicKey, String charset) throws BssException {
try {
PublicKey pubKey = getPublicKeyFromX509(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(publicKey.getBytes()));
Cipher cipher = Cipher.getInstance(CommonConstants.SIGN_TYPE_RSA);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] data = StringUtils.isEmpty(charset) ? content.getBytes()
: content.getBytes(charset);
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 = Base64.encodeBase64(out.toByteArray());
out.close(); return StringUtils.isEmpty(charset) ? new String(encryptedData) : new String(encryptedData, charset);
} catch (Exception e) {
throw new BssException("EncryptContent = " + content + ",charset = " + charset, e);
}
} /**
* 私钥解密,默认字符集 UTF-8
*
* @param content 待解密内容
* @param privateKey 私钥
* @return 明文内容
* @throws BssException
*/
public static String rsaDecrypt(String content, String privateKey) throws BssException {
return rsaDecrypt(content, privateKey, CommonConstants.CHARSET_UTF8);
} /**
* 私钥解密
*
* @param content 待解密内容
* @param privateKey 私钥
* @param charset 字符集,如UTF-8, GBK, GB2312
* @return 明文内容
* @throws BssException
*/
public static String rsaDecrypt(String content, String privateKey, String charset) throws BssException {
try {
PrivateKey priKey = getPrivateKeyFromPKCS8(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(privateKey.getBytes()));
Cipher cipher = Cipher.getInstance(CommonConstants.SIGN_TYPE_RSA);
cipher.init(Cipher.DECRYPT_MODE, priKey);
byte[] encryptedData = StringUtils.isEmpty(charset)
? Base64.decodeBase64(content.getBytes())
: Base64.decodeBase64(content.getBytes(charset));
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 StringUtils.isEmpty(charset) ? new String(decryptedData) : new String(decryptedData, charset);
} catch (Exception e) {
throw new BssException("EncodeContent = " + content + ",charset = " + charset, e);
}
} /**
* rsa内容签名,默认字符集为UTF-8
*
* @param content
* @param privateKey
* @return
* @throws BssException
*/
public static String rsaSign(String content, String privateKey, String signType) throws BssException {
return rsaSign(content, privateKey, CommonConstants.CHARSET_UTF8, signType);
} /**
* rsa内容签名
*
* @param content
* @param privateKey
* @param charset
* @return
* @throws BssException
*/
public static String rsaSign(String content, String privateKey, String charset, String signType) throws BssException {
if (CommonConstants.SIGN_TYPE_RSA.equals(signType)) {
return rsaSign(content, privateKey, charset);
} else if (CommonConstants.SIGN_TYPE_RSA2.equals(signType)) {
return rsa256Sign(content, privateKey, charset);
} else {
throw new BssException("Sign Type is Not Support : signType=" + signType);
} } /**
* sha256WithRsa 加签,默认字符集为UTF-8
*
* @param content
* @param privateKey
* @return
* @throws BssException
*/
public static String rsa256Sign(String content, String privateKey) throws BssException {
return rsa256Sign(content, privateKey, CommonConstants.CHARSET_UTF8);
} /**
* sha256WithRsa 加签
*
* @param content
* @param privateKey
* @param charset
* @return
* @throws BssException
*/
public static String rsa256Sign(String content, String privateKey, String charset) throws BssException { try {
PrivateKey priKey = getPrivateKeyFromPKCS8(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(privateKey.getBytes())); Signature signature = Signature
.getInstance(CommonConstants.SIGN_SHA256RSA_ALGORITHMS); signature.initSign(priKey); if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
} byte[] signed = signature.sign(); return new String(Base64.encodeBase64(signed));
} catch (Exception e) {
throw new BssException("RSAcontent = " + content + "; charset = " + charset, e);
} } /**
* sha1WithRsa 加签
*
* @param content
* @param privateKey
* @param charset
* @return
* @throws BssException
*/
public static String rsa160Sign(String content, String privateKey, String charset) throws BssException {
try {
PrivateKey priKey = getPrivateKeyFromPKCS8(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(privateKey.getBytes())); Signature signature = Signature.getInstance(CommonConstants.SIGN_ALGORITHMS); signature.initSign(priKey); if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
} byte[] signed = signature.sign(); return new String(Base64.encodeBase64(signed));
} catch (InvalidKeySpecException ie) {
throw new BssException("RSA私钥格式不正确,请检查是否正确配置了PKCS8格式的私钥", ie);
} catch (Exception e) {
throw new BssException("RSAcontent = " + content + "; charset = " + charset, e);
}
} /**
* @param sortedParams
* @return
*/
public static String getSignContent(Map<String, String> sortedParams) {
StringBuilder content = new StringBuilder();
List<String> keys = new ArrayList<String>(sortedParams.keySet());
Collections.sort(keys);
int index = 0;
for (String key : keys) {
String value = sortedParams.get(key);
if (StringUtil.areNotEmpty(key, value)) {
content.append(index == 0 ? "" : "&").append(key).append("=").append(value);
index++;
}
}
return content.toString();
} public static String rsaSign(Map<String, String> params, String privateKey, String charset) throws BssException {
String signContent = getSignContent(params); return rsaSign(signContent, privateKey, charset); } public static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {
if (ins == null || StringUtils.isEmpty(algorithm)) {
return null;
} KeyFactory keyFactory = KeyFactory.getInstance(algorithm); byte[] encodedKey = StreamUtil.readText(ins).getBytes(); encodedKey = Base64.decodeBase64(encodedKey); return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
} public static String getSignCheckContentV1(Map<String, String> params) {
if (params == null) {
return null;
} params.remove("sign");
params.remove("sign_type"); StringBuilder content = new StringBuilder();
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys); for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
content.append((i == 0 ? "" : "&") + key + "=" + value);
} return content.toString();
} public static String getSignCheckContentV2(Map<String, String> params) {
if (params == null) {
return null;
} params.remove("sign"); StringBuilder content = new StringBuilder();
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys); for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
content.append(i == 0 ? "" : "&").append(key).append("=").append(value);
} return content.toString();
} /**
* 如果是RSA签名,请调用此方法进行验签
*
* @param params 待验签的从bss接收到的参数Map
* @param publicKey bss公钥
* @param charset 参数内容编码集
* @return true:验签通过;false:验签不通过
* @throws BssException
*/
public static boolean rsaCheckV1(Map<String, String> params, String publicKey, String charset) throws BssException {
String sign = params.get("sign");
String content = getSignCheckContentV1(params); return rsaCheckContent(content, sign, publicKey, charset);
} /**
* 如果是RSA或RSA2签名,请调用此方法进行验签
*
* @param params 待验签的从bss接收到的参数Map
* @param publicKey bss公钥
* @param charset 参数内容编码集
* @param signType 指定采用的签名方式,RSA或RSA2
* @return true:验签通过;false:验签不通过
* @throws BssException
*/
public static boolean rsaCheckV1(Map<String, String> params, String publicKey, String charset, String signType) throws BssException {
String sign = params.get("sign");
String content = getSignCheckContentV1(params); return rsaCheck(content, sign, publicKey, charset, signType);
} public static boolean rsaCheckV2(Map<String, String> params, String publicKey, String charset) throws BssException {
String sign = params.get("sign");
String content = getSignCheckContentV2(params); return rsaCheckContent(content, sign, publicKey, charset);
} public static boolean rsaCheckV2(Map<String, String> params, String publicKey, String charset, String signType) throws BssException {
String sign = params.get("sign");
String content = getSignCheckContentV2(params); return rsaCheck(content, sign, publicKey, charset, signType);
} public static boolean rsaCheck(String content, String sign, String publicKey, String charset, String signType) throws BssException { if (CommonConstants.SIGN_TYPE_RSA.equals(signType)) { return rsaCheckContent(content, sign, publicKey, charset); } else if (CommonConstants.SIGN_TYPE_RSA2.equals(signType)) { return rsa256CheckContent(content, sign, publicKey, charset); } else { throw new BssException("Sign Type is Not Support : signType=" + signType);
} } /**
* RSA2签名方式验签,默认字符集为UTF-8
*
* @param content
* @param sign
* @param publicKey
* @return
* @throws BssException
*/
public static boolean rsa256CheckContent(String content, String sign, String publicKey) throws BssException {
return rsa256CheckContent(content, sign, publicKey, CommonConstants.CHARSET_UTF8);
} /**
* RSA2签名方式验签
*
* @param content
* @param sign
* @param publicKey
* @param charset
* @return
* @throws BssException
*/
public static boolean rsa256CheckContent(String content, String sign, String publicKey, String charset) throws BssException {
try {
PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes())); Signature signature = Signature.getInstance(CommonConstants.SIGN_SHA256RSA_ALGORITHMS); signature.initVerify(pubKey); if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
} return signature.verify(Base64.decodeBase64(sign.getBytes()));
} catch (Exception e) {
throw new BssException(
"RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
}
} public static boolean rsaCheckContent(String content, String sign, String publicKey, String charset) throws BssException {
try {
PublicKey pubKey = getPublicKeyFromX509("RSA",
new ByteArrayInputStream(publicKey.getBytes())); Signature signature = Signature
.getInstance(CommonConstants.SIGN_ALGORITHMS); signature.initVerify(pubKey); if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
} return signature.verify(Base64.decodeBase64(sign.getBytes()));
} catch (Exception e) {
throw new BssException(
"RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
}
} public static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance(algorithm); StringWriter writer = new StringWriter();
StreamUtil.io(new InputStreamReader(ins), writer); byte[] encodedKey = writer.toString().getBytes(); encodedKey = Base64.decodeBase64(encodedKey); return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
} /**
* 验签并解密
* <p>
* <b>目前适用于公众号</b><br>
* params参数示例:
* <br>{
* <br>biz_content=xxx
* <br>sign=xxx, sign_type=RSA,
* <br>charset=UTF-8
* <br>}
* </p>
*
* @param params
* @param bssPublicKey bss公钥
* @param cusPrivateKey 合作方私钥
* @param isCheckSign 是否验签
* @param isDecrypt 是否解密
* @return 解密后明文,验签失败则异常抛出
* @throws BssException
*/
public static String checkSignAndDecrypt(Map<String, String> params, String bssPublicKey, String cusPrivateKey, boolean isCheckSign,
boolean isDecrypt) throws BssException {
String charset = params.get("charset");
String bizContent = params.get("biz_content");
if (isCheckSign) {
if (!rsaCheckV2(params, bssPublicKey, charset)) {
throw new BssException("rsaCheck failure:rsaParams=" + params);
}
} if (isDecrypt) {
return rsaDecrypt(bizContent, cusPrivateKey, charset);
} return bizContent;
} /**
* 验签并解密
* <p>
* <b>目前适用于公众号</b><br>
* params参数示例:
* <br>{
* <br>biz_content=xxx
* <br>sign=xxx, sign_type=RSA,
* <br>charset=UTF-8
* <br>}
* </p>
*
* @param params
* @param bssPublicKey bss公钥
* @param cusPrivateKey 合作方私钥
* @param isCheckSign 是否验签
* @param isDecrypt 是否解密
* @return 解密后明文,验签失败则异常抛出
* @throws BssException
*/
public static String checkSignAndDecrypt(Map<String, String> params, String bssPublicKey, String cusPrivateKey, boolean isCheckSign,
boolean isDecrypt, String signType) throws BssException {
String charset = params.get("charset");
String bizContent = params.get("biz_content");
if (isCheckSign) {
if (!rsaCheckV2(params, bssPublicKey, charset, signType)) {
throw new BssException("rsaCheck failure:rsaParams=" + params);
}
} if (isDecrypt) {
return rsaDecrypt(bizContent, cusPrivateKey, charset);
} return bizContent;
} /**
* 从公钥证书中提取公钥
*
* @param publicCertPath 公钥证书存放路径,例如:/home/admin/cert.crt
* @return 公钥
* @throws BssException
*/
public static String getCertPublicKey(String publicCertPath) throws BssException {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(publicCertPath);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
PublicKey publicKey = cert.getPublicKey();
return Base64.encodeBase64String(publicKey.getEncoded());
} catch (IOException e) {
throw new BssException(e);
} catch (CertificateException e) {
throw new BssException(e);
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
throw new BssException(e);
}
}
}
}
私钥加密,公钥解密(用的不多):
/**
* 私钥加密,最大加密明文大小117,密钥长度为1024
* 有的时候会使用私钥进行加密,公钥解密
* 用私钥加密,相比私钥签名的好处是:既保证不被篡改性,又能缩短字符串长度
*
* @param content 待加密内容
* @param privateKey 私钥
* @return 密文内容
* @throws BssException
*/
public static String rsaEncryptByPriKey1024(String content, String privateKey) throws BssException {
try {
PrivateKey priKey = getPrivateKeyFromPKCS8(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(privateKey.getBytes()));
Cipher cipher = Cipher.getInstance(CommonConstants.SIGN_TYPE_RSA);
cipher.init(Cipher.ENCRYPT_MODE, priKey);
byte[] data = content.getBytes(CommonConstants.CHARSET_UTF8);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > 117) {
cache = cipher.doFinal(data, offSet, 117);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * 117;
}
byte[] encryptedData = Base64.encodeBase64(out.toByteArray());
out.close(); return new String(encryptedData, CommonConstants.CHARSET_UTF8);
} catch (Exception e) {
throw new BssException("EncryptContent = " + content + ",charset = " + CommonConstants.CHARSET_UTF8, e);
}
} /**
* 公钥解密,最大解密密文大小为128,密钥长度为1024
*
* @param content
* @param publicKey
* @return
*/
public static String rsaDecryptByPubKey1024(String content, String publicKey) throws BssException {
String charset = CommonConstants.CHARSET_UTF8;
try {
PublicKey pubKey = getPublicKeyFromX509(CommonConstants.RSA_ALGORITHM,
new ByteArrayInputStream(publicKey.getBytes()));
Cipher cipher = Cipher.getInstance(CommonConstants.SIGN_TYPE_RSA);
cipher.init(Cipher.DECRYPT_MODE, pubKey);
byte[] encryptedData = StringUtils.isEmpty(charset)
? Base64.decodeBase64(content.getBytes())
: Base64.decodeBase64(content.getBytes(charset));
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > 128) {
cache = cipher.doFinal(encryptedData, offSet, 128);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * 128;
}
byte[] decryptedData = out.toByteArray();
out.close(); return StringUtils.isEmpty(charset) ? new String(decryptedData) : new String(decryptedData, charset);
} catch (Exception e) {
throw new BssException("EncodeContent = " + content + ",charset = " + charset, e);
}
}
BASE64:JDK1.8可以使用自带的Base64
import org.apache.commons.codec.BinaryDecoder;
import org.apache.commons.codec.BinaryEncoder;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.EncoderException; import java.io.UnsupportedEncodingException; /**
* Provides Base64 encoding and decoding as defined by RFC 2045
* @author yangyongjie
* @date 2019/10/23
* @desc
*/
public class Base64 implements BinaryEncoder, BinaryDecoder { /**
* Chunk size per RFC 2045 section 6.8.
*
* <p>The {@value} character limit does not count the trailing CRLF, but counts
* all other characters, including any equal signs.</p>
*
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
*/
static final int CHUNK_SIZE = 76; /**
* Chunk separator per RFC 2045 section 2.1.
*
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
*/
static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes(); /**
* The base length.
*/
static final int BASELENGTH = 255; /**
* Lookup length.
*/
static final int LOOKUPLENGTH = 64; /**
* Used to calculate the number of bits in a byte.
*/
static final int EIGHTBIT = 8; /**
* Used when encoding something which has fewer than 24 bits.
*/
static final int SIXTEENBIT = 16; /**
* Used to determine how many bits data contains.
*/
static final int TWENTYFOURBITGROUP = 24; /**
* Used to get the number of Quadruples.
*/
static final int FOURBYTE = 4; /**
* Used to test the sign of a byte.
*/
static final int SIGN = -128; /**
* Byte used to pad output.
*/
static final byte PAD = (byte) '='; // Create arrays to hold the base64 characters and a
// lookup for base64 chars
private static byte[] base64Alphabet = new byte[BASELENGTH];
private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; // Populating the lookup and character arrays
static {
for (int i = 0; i < BASELENGTH; i++) {
base64Alphabet[i] = (byte) -1;
}
for (int i = 'Z'; i >= 'A'; i--) {
base64Alphabet[i] = (byte) (i - 'A');
}
for (int i = 'z'; i >= 'a'; i--) {
base64Alphabet[i] = (byte) (i - 'a' + 26);
}
for (int i = '9'; i >= '0'; i--) {
base64Alphabet[i] = (byte) (i - '0' + 52);
} base64Alphabet['+'] = 62;
base64Alphabet['/'] = 63; for (int i = 0; i <= 25; i++) {
lookUpBase64Alphabet[i] = (byte) ('A' + i);
} for (int i = 26, j = 0; i <= 51; i++, j++) {
lookUpBase64Alphabet[i] = (byte) ('a' + j);
} for (int i = 52, j = 0; i <= 61; i++, j++) {
lookUpBase64Alphabet[i] = (byte) ('0' + j);
} lookUpBase64Alphabet[62] = (byte) '+';
lookUpBase64Alphabet[63] = (byte) '/';
} private static boolean isBase64(byte octect) {
if (octect == PAD) {
return true;
} else if (base64Alphabet[octect] == -1) {
return false;
} else {
return true;
}
} /**
* Tests a given byte array to see if it contains only valid characters within the Base64 alphabet.
*
* @param arrayOctect byte array to test
* @return true if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; false, otherwise
*/
public static boolean isArrayByteBase64(byte[] arrayOctect) { arrayOctect = discardWhitespace(arrayOctect); int length = arrayOctect.length;
if (length == 0) {
// shouldn't a 0 length array be valid base64 data?
// return false;
return true;
}
for (int i = 0; i < length; i++) {
if (!isBase64(arrayOctect[i])) {
return false;
}
}
return true;
} /**
* Encodes binary data using the base64 algorithm but does not chunk the output.
*
* @param binaryData binary data to encode
* @return Base64 characters
*/
public static byte[] encodeBase64(byte[] binaryData) {
return encodeBase64(binaryData, false);
} /**
* Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
*
* @param binaryData binary data to encode
* @return Base64 characters chunked in 76 character blocks
*/
public static byte[] encodeBase64Chunked(byte[] binaryData) {
return encodeBase64(binaryData, true);
} /**
* Decodes an Object using the base64 algorithm. This method is provided in order to satisfy the requirements of the Decoder interface,
* and will throw a DecoderException if the supplied object is not of type byte[].
*
* @param pObject Object to decode
* @return An object (of type byte[]) containing the binary data which corresponds to the byte[] supplied.
* @throws DecoderException if the parameter supplied is not of type byte[]
*/
public Object decode(Object pObject) throws DecoderException {
if (!(pObject instanceof byte[])) {
throw new DecoderException("Parameter supplied to Base64 decode is not a byte[]");
}
return decode((byte[]) pObject);
} /**
* Decodes a byte[] containing containing characters in the Base64 alphabet.
*
* @param pArray A byte array containing Base64 character data
* @return a byte array containing binary data
*/
public byte[] decode(byte[] pArray) {
return decodeBase64(pArray);
} /**
* Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
*
* @param binaryData Array containing binary data to encode.
* @param isChunked if isChunked is true this encoder will chunk the base64 output into 76 character blocks
* @return Base64-encoded data.
*/
public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
int lengthDataBits = binaryData.length * EIGHTBIT;
int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
byte encodedData[] = null;
int encodedDataLength = 0;
int nbrChunks = 0; if (fewerThan24bits != 0) {
//data not divisible by 24 bit
encodedDataLength = (numberTriplets + 1) * 4;
} else {
// 16 or 8 bit
encodedDataLength = numberTriplets * 4;
} // If the output is to be "chunked" into 76 character sections,
// for compliance with RFC 2045 MIME, then it is important to
// allow for extra length to account for the separator(s)
if (isChunked) { nbrChunks =
(CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE));
encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
} encodedData = new byte[encodedDataLength]; byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; int encodedIndex = 0;
int dataIndex = 0;
int i = 0;
int nextSeparatorIndex = CHUNK_SIZE;
int chunksSoFar = 0; //log.debug("number of triplets = " + numberTriplets);
for (i = 0; i < numberTriplets; i++) {
dataIndex = i * 3;
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
b3 = binaryData[dataIndex + 2]; //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3); l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03); byte val1 =
((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 =
((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
byte val3 =
((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
//log.debug( "val2 = " + val2 );
//log.debug( "k4 = " + (k<<4) );
//log.debug( "vak = " + (val2 | (k<<4)) );
encodedData[encodedIndex + 1] =
lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex + 2] =
lookUpBase64Alphabet[(l << 2) | val3];
encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f]; encodedIndex += 4; // If we are chunking, let's put a chunk separator down.
if (isChunked) {
// this assumes that CHUNK_SIZE % 4 == 0
if (encodedIndex == nextSeparatorIndex) {
System.arraycopy(
CHUNK_SEPARATOR,
0,
encodedData,
encodedIndex,
CHUNK_SEPARATOR.length);
chunksSoFar++;
nextSeparatorIndex =
(CHUNK_SIZE * (chunksSoFar + 1)) +
(chunksSoFar * CHUNK_SEPARATOR.length);
encodedIndex += CHUNK_SEPARATOR.length;
}
}
} // form integral number of 6-bit groups
dataIndex = i * 3; if (fewerThan24bits == EIGHTBIT) {
b1 = binaryData[dataIndex];
k = (byte) (b1 & 0x03);
//log.debug("b1=" + b1);
//log.debug("b1<<2 = " + (b1>>2) );
byte val1 =
((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
encodedData[encodedIndex + 2] = PAD;
encodedData[encodedIndex + 3] = PAD;
} else if (fewerThan24bits == SIXTEENBIT) { b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03); byte val1 =
((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 =
((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex + 1] =
lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
encodedData[encodedIndex + 3] = PAD;
} if (isChunked) {
// we also add a separator to the end of the final chunk.
if (chunksSoFar < nbrChunks) {
System.arraycopy(
CHUNK_SEPARATOR,
0,
encodedData,
encodedDataLength - CHUNK_SEPARATOR.length,
CHUNK_SEPARATOR.length);
}
} return encodedData;
} /**
* Decodes Base64 data into octects
*
* @param base64Data Byte array containing Base64 data
* @return Array containing decoded data.
*/
public static byte[] decodeBase64(byte[] base64Data) {
// RFC 2045 requires that we discard ALL non-Base64 characters
base64Data = discardNonBase64(base64Data); // handle the edge case, so we don't have to worry about it later
if (base64Data.length == 0) {
return new byte[0];
} int numberQuadruple = base64Data.length / FOURBYTE;
byte decodedData[] = null;
byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; // Throw away anything not in base64Data int encodedIndex = 0;
int dataIndex = 0;
{
// this sizes the output array properly - rlw
int lastData = base64Data.length;
// ignore the '=' padding
while (base64Data[lastData - 1] == PAD) {
if (--lastData == 0) {
return new byte[0];
}
}
decodedData = new byte[lastData - numberQuadruple];
} for (int i = 0; i < numberQuadruple; i++) {
dataIndex = i * 4;
marker0 = base64Data[dataIndex + 2];
marker1 = base64Data[dataIndex + 3]; b1 = base64Alphabet[base64Data[dataIndex]];
b2 = base64Alphabet[base64Data[dataIndex + 1]]; if (marker0 != PAD && marker1 != PAD) {
//No PAD e.g 3cQl
b3 = base64Alphabet[marker0];
b4 = base64Alphabet[marker1]; decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex + 1] =
(byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
} else if (marker0 == PAD) {
//Two PAD e.g. 3c[Pad][Pad]
decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
} else if (marker1 == PAD) {
//One PAD e.g. 3cQ[Pad]
b3 = base64Alphabet[marker0]; decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex + 1] =
(byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
}
encodedIndex += 3;
}
return decodedData;
} /**
* Discards any whitespace from a base-64 encoded block.
*
* @param data The base-64 encoded data to discard the whitespace from.
* @return The data, less whitespace (see RFC 2045).
*/
static byte[] discardWhitespace(byte[] data) {
byte groomedData[] = new byte[data.length];
int bytesCopied = 0; for (int i = 0; i < data.length; i++) {
switch (data[i]) {
case (byte) ' ':
case (byte) '\n':
case (byte) '\r':
case (byte) '\t':
break;
default:
groomedData[bytesCopied++] = data[i];
}
} byte packedData[] = new byte[bytesCopied]; System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); return packedData;
} /**
* Discards any characters outside of the base64 alphabet, per the requirements on page 25 of RFC 2045 - "Any characters outside of the
* base64 alphabet are to be ignored in base64 encoded data."
*
* @param data The base-64 encoded data to groom
* @return The data, less non-base64 characters (see RFC 2045).
*/
static byte[] discardNonBase64(byte[] data) {
byte groomedData[] = new byte[data.length];
int bytesCopied = 0; for (int i = 0; i < data.length; i++) {
if (isBase64(data[i])) {
groomedData[bytesCopied++] = data[i];
}
} byte packedData[] = new byte[bytesCopied]; System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); return packedData;
} // Implementation of the Encoder Interface /**
* Encodes an Object using the base64 algorithm. This method is provided in order to satisfy the requirements of the Encoder interface,
* and will throw an EncoderException if the supplied object is not of type byte[].
*
* @param pObject Object to encode
* @return An object (of type byte[]) containing the base64 encoded data which corresponds to the byte[] supplied.
* @throws EncoderException if the parameter supplied is not of type byte[]
*/
public Object encode(Object pObject) throws EncoderException {
if (!(pObject instanceof byte[])) {
throw new EncoderException(
"Parameter supplied to Base64 encode is not a byte[]");
}
return encode((byte[]) pObject);
} /**
* Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 alphabet.
*
* @param pArray a byte array containing binary data
* @return A byte array containing only Base64 character data
*/
public byte[] encode(byte[] pArray) {
return encodeBase64(pArray, false);
} public static String encodeBase64String(byte[] input) {
try {
return new String(encodeBase64(input), "utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage(), e);
}
} public static byte[] decodeBase64String(String base64String) {
try {
return Base64.decodeBase64(base64String.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
StreamUtil:
import java.io.*; /**
* @author yangyongjie
* @date 2019/10/23
* @desc
*/
public class StreamUtil {
private static final int DEFAULT_BUFFER_SIZE = 8192; public static void io(InputStream in, OutputStream out) throws IOException {
io(in, out, -1);
} public static void io(InputStream in, OutputStream out, int bufferSize) throws IOException {
if (bufferSize == -1) {
bufferSize = DEFAULT_BUFFER_SIZE;
} byte[] buffer = new byte[bufferSize];
int amount; while ((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
} public static void io(Reader in, Writer out) throws IOException {
io(in, out, -1);
} public static void io(Reader in, Writer out, int bufferSize) throws IOException {
if (bufferSize == -1) {
bufferSize = DEFAULT_BUFFER_SIZE >> 1;
} char[] buffer = new char[bufferSize];
int amount; while ((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
} public static OutputStream synchronizedOutputStream(OutputStream out) {
return new SynchronizedOutputStream(out);
} public static OutputStream synchronizedOutputStream(OutputStream out, Object lock) {
return new SynchronizedOutputStream(out, lock);
} public static String readText(InputStream in) throws IOException {
return readText(in, null, -1);
} public static String readText(InputStream in, String encoding) throws IOException {
return readText(in, encoding, -1);
} public static String readText(InputStream in, String encoding, int bufferSize)
throws IOException {
Reader reader = (encoding == null) ? new InputStreamReader(in) : new InputStreamReader(in,
encoding); return readText(reader, bufferSize);
} public static String readText(Reader reader) throws IOException {
return readText(reader, -1);
} public static String readText(Reader reader, int bufferSize) throws IOException {
StringWriter writer = new StringWriter(); io(reader, writer, bufferSize);
return writer.toString();
} private static class SynchronizedOutputStream extends OutputStream {
private OutputStream out;
private Object lock; SynchronizedOutputStream(OutputStream out) {
this(out, out);
} SynchronizedOutputStream(OutputStream out, Object lock) {
this.out = out;
this.lock = lock;
} public void write(int datum) throws IOException {
synchronized (lock) {
out.write(datum);
}
} public void write(byte[] data) throws IOException {
synchronized (lock) {
out.write(data);
}
} public void write(byte[] data, int offset, int length) throws IOException {
synchronized (lock) {
out.write(data, offset, length);
}
} public void flush() throws IOException {
synchronized (lock) {
out.flush();
}
} public void close() throws IOException {
synchronized (lock) {
out.close();
}
}
}
}
StringUtil:
import java.util.UUID; /**
* 自定义字符串工具类
*
* @author yangyongjie
* @date 2019/9/24
* @desc
*/
public class StringUtil {
private StringUtil() {
} /**
* 返回UUID
*
* @return
*/
public static String getUUID() {
return UUID.randomUUID().toString().replaceAll("-", "");
} /**
* 检查指定的字符串列表是否不为空。
*/
public static boolean areNotEmpty(String... values) {
boolean result = true;
if (values == null || values.length == 0) {
result = false;
} else {
for (String value : values) {
result &= !isEmpty(value);
}
}
return result;
} /**
* 检查指定的字符串是否为空。
* <ul>
* <li>SysUtils.isEmpty(null) = true</li>
* <li>SysUtils.isEmpty("") = true</li>
* <li>SysUtils.isEmpty(" ") = true</li>
* <li>SysUtils.isEmpty("abc") = false</li>
* </ul>
*
* @param value 待检查的字符串
* @return true/false
*/
public static boolean isEmpty(String value) {
int strLen;
if (value == null || (strLen = value.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(value.charAt(i)) == false)) {
return false;
}
}
return true;
}
}
CommonConstants:
/**
* 公共常量类
*
* @author yangyongjie
* @date 2019/9/24
* @desc
*/
public class CommonConstants {
private CommonConstants() {
} public static final String STR_ONE = "1";
public static final String STR_TWO = "2";
public static final String STR_THREE = "3";
public static final String STR_FOUR = "4"; public static final int ONE = 1;
public static final int TWO = 2;
public static final int THREE = 3;
public static final int FOUR = 4; public static final String SIGN_TYPE = "sign_type"; /**
* 签名类型
*/
public static final String SIGN_TYPE_RSA = "RSA"; public static final String SIGN_TYPE_RSA2 = "RSA2";
/**
* 签名算法
*/ public static final String SIGN_ALGORITHMS = "SHA1WithRSA"; public static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA"; /**
* 加密算法
*/
public static final String RSA_ALGORITHM = "RSA"; public static final String ENCRYPT_TYPE_AES = "AES"; public static final String APP_ID = "app_id"; public static final String CHARSET = "charset"; /**
* UTF-8字符集
**/
public static final String CHARSET_UTF8 = "UTF-8"; /**
* GBK字符集
**/
public static final String CHARSET_GBK = "GBK"; }
补充:
HMAC-SHA1 加密算法工具类:
package xxx.common.utils; import xxx.common.constants.CommonConstants;
import org.apache.commons.lang3.StringUtils; import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; /**
* HMAC-SHA1 加密算法工具类
*
* @author yangyongjie
* @date 2019/11/6
* @desc
*/
public class HMACSHA1Util { private static final String HMAC_SHA_1 = "HmacSHA1"; private static final String KEY = "iU5GSex1N81mzccVtns/3w=="; /**
* 生成签名
*
* @param message
* @return
* @throws Exception
*/
public static String signature(String message) throws Exception {
return signature(message, KEY);
} /**
* 签名
*
* @param message 签名的字符串
* @param key 密钥
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static String signature(String message, String key) throws Exception {
byte[] byteMsg = message.getBytes(CommonConstants.CHARSET_UTF8);
byte[] byteKey = key.getBytes(CommonConstants.CHARSET_UTF8);
SecretKeySpec signKey = new SecretKeySpec(byteKey, HMAC_SHA_1);
Mac mac = Mac.getInstance(HMAC_SHA_1);
mac.init(signKey);
byte[] encodeArray = mac.doFinal(byteMsg);
return byte2HexString(encodeArray);
} /**
* 二进制转十六进制
*
* @param b
* @return
*/
public static String byte2HexString(byte[] b) {
String r = "";
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
r = r + hex;
}
return r;
} /**
* 验签
*
* @param message
* @param sign
* @return
*/
public static boolean checkSign(String message, String sign) throws Exception {
String signature = signature(message, KEY);
return StringUtils.equals(signature, sign);
} public static void main(String[] args) {
try {
String msg = "partnerId=5514c2f0aa4a40759f9e326e3d662595&openId=xiaomifengxing&token=201911061839039096405ef79bbe444ca8efeb598c1d81f2d&code=liehuo";
String sign = signature(msg);
boolean pass = checkSign(msg, sign);
System.out.println(pass);
} catch (Exception e) {
e.printStackTrace();
}
} }