| package cc.mrbird.febs.pay.util; | 
|   | 
|   | 
|   | 
| import org.apache.commons.codec.binary.Base64; | 
| import org.bouncycastle.jce.provider.BouncyCastleProvider; | 
|   | 
| import javax.crypto.Cipher; | 
| import java.io.ByteArrayOutputStream; | 
| import java.nio.charset.StandardCharsets; | 
| import java.security.*; | 
| import java.security.spec.PKCS8EncodedKeySpec; | 
| import java.security.spec.X509EncodedKeySpec; | 
| import java.util.HashMap; | 
| import java.util.Map; | 
|   | 
| /** | 
|  * RSA加解密的工具类 | 
|  */ | 
| public class RSAUtil { | 
| //    private static final Logger logger = LoggerFactory.getLogger(RSAUtil.class); | 
|     public static final String SIGNATURE_ALGORITHM_SHA1 = "SHA1withRSA"; | 
|     public static final String SIGNATURE_ALGORITHM_MD5 = "MD5withRSA"; | 
|     public static final String RSA = "RSA"; | 
|   | 
|     public static final String ANDROID_ENCRYPT_ALGORITHM = "RSA/ECB/NoPadding"; | 
|     public static final String DEFAULT_ENCRYPT_ALGORITHM = "RSA/ECB/PKCS1Padding"; | 
|   | 
|     public static final String PUBLIC_KEY = "publicKey"; | 
|     public static final String PRIVATE_KEY = "privateKey"; | 
|   | 
|     /** */ | 
|     /** | 
|      * RSA最大加密明文大小 | 
|      */ | 
|     private static final int MAX_ENCRYPT_BLOCK = 116; | 
|   | 
|     /** */ | 
|     /** | 
|      * RSA最大解密密文大小 | 
|      */ | 
|     private static final int MAX_DECRYPT_BLOCK = 128; | 
|   | 
|     /** | 
|      * 初始化BC提供者,RSA算法必须要先初始化BC才能进行加密解密和签名验签 | 
|      */ | 
|     private static void initProvider() { | 
|         if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { | 
|             Security.addProvider(new BouncyCastleProvider()); | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 生成RSA签名串 | 
|      * | 
|      * @param data       需要生成签名串的数据 | 
|      * @param privateKey 私钥 | 
|      * @return | 
|      * @throws BizException | 
|      */ | 
|     public static String sign(String data, String privateKey, boolean isSha) throws Exception { | 
|         try { | 
|             initProvider(); | 
|             byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8); | 
|             byte[] keyBytes = CodeUtil.base64Decode(privateKey); | 
|             String algorithm = isSha ? SIGNATURE_ALGORITHM_SHA1 : SIGNATURE_ALGORITHM_MD5; | 
|   | 
|             PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); | 
|             PrivateKey priKey = KeyFactory.getInstance(RSA).generatePrivate(pkcs8KeySpec); | 
|             Signature signature = Signature.getInstance(algorithm); | 
|             signature.initSign(priKey); | 
|             signature.update(dataBytes); | 
|             return CodeUtil.base64Encode(signature.sign()); | 
|         }catch (Throwable e){ | 
| //            logger.error("==>sign err:", e); | 
|             throw new Exception("生成RSA签名失败", e); | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 验证RSA签名串 | 
|      * | 
|      * @param data      需要验签的数据 | 
|      * @param publicKey 公钥 | 
|      * @param sign      用户传过来的签名串 | 
|      * @return | 
|      * @throws BizException | 
|      */ | 
|     public static boolean verify(String data, String publicKey, String sign, boolean isSha) throws Exception { | 
|         try { | 
|             initProvider(); | 
|             byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8); | 
|             byte[] signBytes = CodeUtil.base64Decode(sign); | 
|             String algorithm = isSha ? SIGNATURE_ALGORITHM_SHA1 : SIGNATURE_ALGORITHM_MD5; | 
|             PublicKey publicK = getPublicKey(publicKey); | 
|   | 
|             Signature signature = Signature.getInstance(algorithm); | 
|             signature.initVerify(publicK); | 
|             signature.update(dataBytes); | 
|             return signature.verify(signBytes); | 
|         } catch (Throwable e) { | 
| //            logger.error("==>verify err:", e); | 
|             throw new Exception("RSA验签失败", e); | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 对称密钥公钥加密 | 
|      * | 
|      * @param publicKeyStr 公钥Str | 
|      * @param content      密钥原文 | 
|      * @return 加密密文 | 
|      */ | 
|     public static String encryptByPublicKey(String publicKeyStr, String content) throws Exception { | 
|         | 
|             byte[] dataBytes = content.getBytes(StandardCharsets.UTF_8); | 
|             dataBytes = doCipher(dataBytes, publicKeyStr, true, false); | 
|             return CodeUtil.base64Encode(dataBytes); | 
|         | 
|     } | 
|   | 
|     /** | 
|      * 对称密钥密文解密 | 
|      * | 
|      * @param privateKeyStr 私钥字符串 | 
|      * @param content       对称密钥密文 | 
|      * @return 对称密钥明文 | 
|      * @throws Exception | 
|      */ | 
|     public static String decryptByPrivateKey(String privateKeyStr, String content) throws Exception{ | 
|             byte[] dataBytes = CodeUtil.base64Decode(content); | 
|             dataBytes = doCipher(dataBytes, privateKeyStr, false, false); | 
|             return new String(dataBytes, StandardCharsets.UTF_8); | 
|         | 
|     } | 
|   | 
|     private static byte[] doCipher(byte[] dataBytes, String keyStr, boolean isEncrypt, boolean isAndroid) throws Exception { | 
|   | 
|         initProvider(); | 
|   | 
|         Key key; | 
|         Cipher cipher; | 
|         int maxBlock; | 
|   | 
|         if (isEncrypt) { | 
|             maxBlock = MAX_ENCRYPT_BLOCK; | 
|             key = getPublicKey(keyStr); | 
|             if (isAndroid) { | 
|                 cipher = Cipher.getInstance(ANDROID_ENCRYPT_ALGORITHM);// 如果是安卓机 | 
|             } else { | 
|                 cipher = Cipher.getInstance(DEFAULT_ENCRYPT_ALGORITHM); | 
|             } | 
|             cipher.init(Cipher.ENCRYPT_MODE, key); | 
|         } else { | 
|             maxBlock = MAX_DECRYPT_BLOCK; | 
|             byte[] keyBytes = Base64.decodeBase64(keyStr); | 
|             PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); | 
|             KeyFactory keyFactory = KeyFactory.getInstance(RSA); | 
|             Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); | 
|             cipher = Cipher.getInstance(keyFactory.getAlgorithm()); | 
|             cipher.init(Cipher.DECRYPT_MODE, privateK); | 
|         } | 
|   | 
|         int offSet = 0, i = 0, inputLen = dataBytes.length; | 
|         byte[] cache; | 
|         ByteArrayOutputStream out = new ByteArrayOutputStream(); | 
|   | 
|         try { | 
|             // 对数据分段加密/解密 | 
|             while (inputLen - offSet > 0) { | 
|                 if (inputLen - offSet > maxBlock) { | 
|                     cache = cipher.doFinal(dataBytes, offSet, maxBlock); | 
|                 } else { | 
|                     cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet); | 
|                 } | 
|                 out.write(cache, 0, cache.length); | 
|                 i++; | 
|                 offSet = i * maxBlock; | 
|             } | 
|             return out.toByteArray(); | 
|         } finally { | 
|             out.close(); | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 生成公私密钥对 | 
|      * @return | 
|      */ | 
|     public static Map<String, String> genKeyPair() throws Exception { | 
|         try { | 
|             KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA); | 
|             keyPairGen.initialize(1024); | 
|             KeyPair keyPair = keyPairGen.generateKeyPair(); | 
|   | 
|             Map<String, String> keyMap = new HashMap<>(2); | 
|             keyMap.put(PUBLIC_KEY, CodeUtil.base64Encode(keyPair.getPublic().getEncoded())); | 
|             keyMap.put(PRIVATE_KEY, CodeUtil.base64Encode(keyPair.getPrivate().getEncoded())); | 
|             return keyMap; | 
|         }catch (Throwable e){ | 
|             throw new Exception("生成RSA密钥对出现异常", e); | 
|         } | 
|     } | 
|   | 
|     private static PublicKey getPublicKey(String publicKey) throws Exception { | 
|         byte[] keyBytes = CodeUtil.base64Decode(publicKey); | 
|         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); | 
|         KeyFactory keyFactory = KeyFactory.getInstance(RSA); | 
|         return keyFactory.generatePublic(x509KeySpec); | 
|     } | 
| } |