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 genKeyPair() throws Exception { try { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); Map 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); } }