银联支付sdk乱塞全局加解密算法,导致的支付宝加解密类乱码的问题

背景:

1.现在版本的支付宝wap支付需要到支付宝后台获取一个token,该字段是加密返回的,需要调用RSA类进行解密 2.银联APP支付是直接给sdk包,然后调用sdk包做tn获取的,内部调用是个黑盒,开发是看不到的

现象:

1.在不调用银联APP SDK进行初始化的情况下,支付宝WAP支付整体流程都是正确的,token能拿到,也能正常解密 2.在进行一次银联支付后,即银联SDK初始化后,支付宝WAP支付开始一直报错,现象为token加密字符串能获取,但是解密一直是乱码

原因:

查看银联SDK后,发现在其CertUtil中有个init()静态方法,其调用方法中,有以下两行坑爹代码:

Security.insertProviderAt(new BouncyCastleProvider(), 1); 
Security.addProvider(new BouncyCastleProvider());

这两行代码是什么意思呢? 在Security全局上下文环境,将BouncyCastleProvider这个算法类,直接变成默认算法类 导致了什么结果呢? 当你调用支付宝提供的RSA类的时候,默认的算法类从JDK自带的SUN RSA,变成了这个BouncyCastleProvider提供的RSA算法,直接导致和支付宝的加密算法不匹配,于是报错乱码。

解决:

修改RSA类如下,手动指定算法的provider类

package com.wonders.test;

public class RSA {
    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";


    /**
     * RSA验签名检查
     *
     * @param content        待签名数据
     * @param sign           签名值
     * @param ali_public_key 支付宝公钥
     * @param input_charset  编码格式
     * @return 布尔值
     */

    public static boolean verify(String content, String sign, String ali_public_key, String input_charset) {
        try {
            Provider provider = Security.getProvider("SunRsaSign");
            KeyFactory keyFactory = KeyFactory.getInstance("RSA", provider);
            byte[] encodedKey = Base64.decode(ali_public_key);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS, provider);
            signature.initVerify(pubKey);
            signature.update(content.getBytes(input_charset));
            boolean bverify = signature.verify(Base64.decode(sign));
            return bverify;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 解密
     *
     * @param content       密文
     * @param private_key   商户私钥
     * @param input_charset 编码格式
     * @return 解密后的字符串
     */

    public static String decrypt(String content, String private_key, String input_charset) throws Exception {
        System.out.println("alipay decrypt content..." + content);
        System.out.println("alipay decrypt key..." + private_key);
        PrivateKey prikey = getPrivateKey(private_key);
        Provider provider = Security.getProvider("SunJCE");
        Cipher cipher = Cipher.getInstance("RSA", provider);
        cipher.init(Cipher.DECRYPT_MODE, prikey);
        InputStream ins = new ByteArrayInputStream(Base64.decode(content));
        ByteArrayOutputStream writer = new ByteArrayOutputStream(); // rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密
        byte[] buf = new byte[128];
        int bufl;
        while ((bufl = ins.read(buf)) != -1) {
            byte[] block = null;
            if (buf.length == bufl) {
                block = buf;
            } else {
                block = new byte[bufl];
                for (int i = 0; i < bufl; i++) {
                    block[i] = buf[i];
                }
            }
            writer.write(cipher.doFinal(block));
        }
        return new String(writer.toByteArray(), input_charset);
    }

    /**
     * 得到私钥 * * @param key * 密钥字符串(经过base64编码) * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = Base64.decode(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        Provider provider = Security.getProvider("SunRsaSign");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA", provider);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }
}

最后吐槽一下银联的SDK,拜托大哥你以后代码写的不要那么暴力,稍微低调点OK?这么修改全局参数,直接会导致工程中其它加解密类全部趴窝