銀聯支付sdk亂塞全局加解密算法,導致的支付寶加解密類亂碼的問題

原文及更多文章請見個人博客:http://heartlifes.com

背景:

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?這麼修改全局參數,直接會導致工程中其它加解密類全部趴窩

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章