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); 
 | 
    } 
 | 
} 
 |