package com.nova.sankuai.domain.api.jiniu; import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; import lombok.extern.slf4j.Slf4j; import sun.misc.BASE64Decoder; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.*; /** * BairongSignature * 签名加密工具类-简化版 * * @author zhenzhong.li * @date 18/1/4 */ @Slf4j public class BairongSignature { private static final String charset = "utf-8"; private static final String signTypeSHA1 = "SHA1withRSA"; private static final String signTypeSHA256 = "SHA256withRSA"; private static final String signTypeMD5 = "MD5withRSA"; //AES_256_cbc pkcs7 private static final String algorithm = "AES/CBC/PKCS5Padding"; /** * 加签 * * @param signParams * @param privateKey * @return */ public static String signMD5(Map signParams, String privateKey) { return initSign(signTypeMD5, signParams, privateKey); } public static String signSHA1(Map signParams, String privateKey) { return initSign(signTypeSHA1, signParams, privateKey); } public static String signSHA256(Map signParams, String privateKey) { return initSign(signTypeSHA256, signParams, privateKey); } /** * 根据类型生成签名 * * @param privateKey */ private static String initSign(String signType, Map signParams, String privateKey) { try { String content = getSignContent(signParams); PrivateKey priKey = getPrivateKeyFromPKCS8(privateKey); Signature signature = Signature.getInstance(signType); signature.initSign(priKey); if (isEmpty(charset)) { signature.update(content.getBytes()); } else { signature.update(content.getBytes(charset)); } byte[] signed = signature.sign(); return Base64.encode(signed); } catch (Exception e) { System.out.println("生成签名异常:" + e.getMessage()); e.printStackTrace(); } return null; } /** * 验证签名 * */ public static boolean checkSignMD5(Map signParams, String sign, String publicKey) { return rsa256CheckContent(signTypeMD5, signParams, sign, publicKey); } public static boolean checkSignSHA1(Map signParams, String sign, String publicKey) { return rsa256CheckContent(signTypeSHA1, signParams, sign, publicKey); } public static boolean checkSignSHA256(Map signParams, String sign, String publicKey) { return rsa256CheckContent(signTypeSHA256, signParams, sign, publicKey); } /** * 根据加签类型验证签名 * * @param signParams * @param sign * @param publicKey * @return */ private static boolean rsa256CheckContent(String signType, Map signParams, String sign, String publicKey) { try { String content = getSignContent(signParams); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); byte[] encodedKey = Base64.decode(publicKey); PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); Signature signature = Signature.getInstance(signType); signature.initVerify(pubKey); signature.update(content.getBytes(charset)); boolean bverify = signature.verify(Base64.decode(sign)); return bverify; } catch (Exception e) { e.printStackTrace(); } return false; } /** * RSA-公钥加密过程 * * @param params * @param pubKey * @return * @throws Exception */ public static String encryptRSA(Map params, String pubKey) throws Exception { if (isEmpty(pubKey)) { throw new Exception("加密公钥为空, 请设置"); } String context = getSignContent(params); PublicKey publicKey = getPublicKeyFromX509(pubKey); Cipher cipher; try { // 使用默认RSA cipher = Cipher.getInstance("RSA"); // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] output = cipher.doFinal(context.getBytes()); return Base64.encode(output); } catch (NoSuchAlgorithmException e) { throw new Exception("无此加密算法"); } catch (NoSuchPaddingException e) { e.printStackTrace(); return null; } catch (InvalidKeyException e) { throw new Exception("加密公钥非法,请检查"); } catch (IllegalBlockSizeException e) { throw new Exception("明文长度非法"); } catch (BadPaddingException e) { throw new Exception("明文数据已损坏"); } } /** * RSA-私钥解密过程 * * @param context * @param priKey * @return * @throws Exception */ public static String decryptRSA(String context, String priKey) throws Exception { if (isEmpty(priKey)) { throw new Exception("解密私钥为空, 请设置"); } PrivateKey privateKey = getPrivateKeyFromPKCS8(priKey); Cipher cipher; try { // 使用默认RSA cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] output = cipher.doFinal(Base64.decode(context)); return new String(output); } catch (NoSuchAlgorithmException e) { throw new Exception("无此解密算法"); } catch (NoSuchPaddingException e) { e.printStackTrace(); return null; } catch (InvalidKeyException e) { throw new Exception("解密私钥非法,请检查"); } catch (IllegalBlockSizeException e) { throw new Exception("密文长度非法"); } catch (BadPaddingException e) { throw new Exception("密文数据已损坏"); } } /** * 参数格式转换Map转String * * @param sortedParams * @return */ public static String getSignContent(Map sortedParams) { StringBuilder content = new StringBuilder(); List keys = new ArrayList<>(sortedParams.keySet()); Collections.sort(keys); int index = 0; for (String key : keys) { String value = sortedParams.get(key); if (isNotEmpty(key) && isNotEmpty(value)) { content.append(index == 0 ? "" : "&").append(key).append("=").append(value); index++; } } return content.toString(); } /** * 私钥对象生成 * */ private static PrivateKey getPrivateKeyFromPKCS8(String priKey) throws Exception { PKCS8EncodedKeySpec priPKCS8; PrivateKey privateKey = null; if (isEmpty(priKey)) { return privateKey; } try { priPKCS8 = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(priKey)); KeyFactory keyf = KeyFactory.getInstance("RSA"); privateKey = keyf.generatePrivate(priPKCS8); } catch (Exception e) { System.out.println("私钥解析错误:" + e.getMessage()); } return privateKey; } /** * 公钥对象生成 * * @param pubKey * @return * @throws Exception */ private static PublicKey getPublicKeyFromX509(String pubKey) throws Exception { PublicKey publicKey = null; if (isEmpty(pubKey)) { return publicKey; } try { X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec( new BASE64Decoder().decodeBuffer(pubKey)); KeyFactory keyFactory; keyFactory = KeyFactory.getInstance("RSA"); // 取公钥匙对象 publicKey = keyFactory.generatePublic(bobPubKeySpec); } catch (Exception e) { } return publicKey; } /** * AES加密 * * @param base64Key * @param text * @return * @throws Exception */ public static String encryptAES(String base64Key, String text) { try { byte[] key = parseHexStr2Byte(base64Key); SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, sKeySpec); byte[] encryptBytes = cipher.doFinal(text.getBytes(charset)); return parseByte2HexStr(encryptBytes); } catch (Exception e) { System.out.println("AES加密错误:" + e.getMessage()); } return null; } /** * AES解密 * * @param base64Key * @param text * @return * @throws Exception */ public static String decryptAES(String base64Key, String text) { try { byte[] key = parseHexStr2Byte(base64Key); SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, sKeySpec); byte[] decryptBytes = cipher.doFinal(parseHexStr2Byte(text)); return new String(decryptBytes, "UTF-8"); } catch (Exception e) { log.error("AES解密错误:" + e.getMessage()); } return null; } /** * 将16进制转换为二进制 * * @param hexStr * @return */ private static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) return null; byte[] result = new byte[hexStr.length() / 2]; for (int i = 0; i < hexStr.length() / 2; i++) { int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); result[i] = (byte) (high * 16 + low); } return result; } /** * 将二进制转换成16进制 * */ public static String parseByte2HexStr(byte[] buf) { StringBuilder sb = new StringBuilder(); for (byte b : buf) { String hex = Integer.toHexString(b & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); } private static boolean isEmpty(String str) { return ((str == null) || (str.length() == 0)); } private static boolean isNotEmpty(String str) { return ((str != null) && (str.length() > 0)); } }