zoukankan      html  css  js  c++  java
  • 银联支付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?这么修改全局参数,直接会导致工程中其它加解密类全部趴窝

  • 相关阅读:
    jQuery插件jTemplates(模板)
    js常用正则
    SQLServer笔记 //20111027
    神经网络感知器matlab实现
    求全排列(无重复字母)
    python 学习笔记(1、数据类型)
    WampServer 不能打开phpmyadmin 的解决办法
    求一个整形数组里子序列和最大的算法
    堆排序算法的实习(C++)
    归并排序
  • 原文地址:https://www.cnblogs.com/heartlifes/p/6970981.html
Copyright © 2011-2022 走看看