美文网首页
php对接java接口RSA签名及验签问题!

php对接java接口RSA签名及验签问题!

作者: DragonersLi | 来源:发表于2022-05-19 21:54 被阅读0次

    java文档demo,签名实现
    1、筛选并排序
    将明文业务数据进行JSON化,并按照字符的键值 ASCII 码递增排序(字母升序排序) 此时生成的字符串为待签名字符串。
    2、调用签名函数
    使用各自语言对应的 SHA256WITHRSA( RSA签名)签名函数利用提供的私钥对签名字符串进行签名,并进行 Base64 编码。把生成的签名 encode 后赋值给 sign 参数
    加密
    将明文业务数据进行JSON化,使用提供的 AES 密钥加密后, 得到密文,将密文用 Base64 编码后放置到 biz_data 字段中
    💡 测试环境和正式环境地址、clientId、RSA私钥、AES密钥请询问我方相关开发或运营人员。

    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    
    import java.net.URI;
    import java.nio.charset.Charset;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Main {
        public static void main(String[] args) throws Exception{
            JSONObject data = new JSONObject();
            data.put("startTime", "2022-05-01 10:03:00");
            data.put("endTime", "2022-05-11 10:03:00");
            //RSA私钥
            String signPrivateKey="MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCtzlJwMDoum4BayDGsN5SbDANdMbkHatOaJyo8kC7jMDYi1b4gHIms+enjtl+oF2FpI8vjS+uF0dVR8vfgACYqnvosqgWiEiJfnvHBBYq7Bwu7Y51QolzSdR0WhV1IRv8b3mDySrUiQDeVHlUfe66XZw/T+yJG3ZbXRV0OkZMjfwm4/m52hhMBi+DgyGq4fVmi180oWEEgj8pnWx8ut1td7v7hEfIqFPR7QGhVy0gBleaVMpTWfz2O6QCM1Y7Z4LFa8SW5igO5Wg15VpijcS0kll+XiC1+KARZst0lu3xho0vCMwvdJolkpAR5Atp27wvAzlc73ZJHvtA386lqugHrAgMBAAECggEAGUd0/hRFohnD5XBQqTe8SYDJzHg67TVAaZ9gqUZfS3Prq81ixdDgxWPj/Na9uvkLlfs64GhebSxD1pN8MfxTkMdmo7Bm+Veh4D6B8w0XTHSN5EdszhmPXpziCjCDjMumtyr09sie58hnTS0IPHgEwMigqLhSF/SKx+yyyDesKvFFpu9QyrMcKL7W1iMU8W5H9LSB08z1EDY8nJbn6COCRyYdfRLHBcHzwguB0RgA606X/tArjR7HPXSnQd6qzYwJHsR5/2sS+6kIKrDqSUj8IJqGqei6ethX9jeYXHIPvtooym/Dh1mpgRqrmKCN4IeXU30+wR+nUbDMKWMh54mzAQKBgQDlyvYObEjrJjCKWMDS4bPqO+SLaUvSyhZtfpa4b/gskVOll2Y+KQrHMSRWn3XCFtl2YJM40/1+ijnlfJ7p43M3hQGx/au4U2En1fRt1u2ERDblsMvyn3TR1n9m3qOMS16I+18aWPzC4146Li5AG3I6SzHLjZmG28GKD0aRJUMXIQKBgQDBoMQqfKblJfA+cP0XBQBmnszWT3bC2hd5aLn3sMwCXDocE2mh8R1CIWoQurCRUqG1IuR6sw4k9fgjKPpAgxTiSZeORXROcLbw7PE8CR9/y+P0P+qg1IalmytV8N8afxEZBmkACvPuZMyzUlir8kbJNlJAvXSyiwhlk5Xo0vUTiwKBgFr16kxvRLYAWfqJg1p2iVdQ+fjNZ3w7DoGtOFAt0lkh9bB4q7ozWNbcdvvrBxwbG12mgOBf2do7MQvMNsNyi2sQtUkVluHR74VrReQszbwrnGdzgme6Au4FME0yGB8yvmsOxeiSDQvAIM569UffFWpJ1Z4zoPAnEQdrYI2X6GTBAoGALPYZ1wvO7VLb8IPoIRpGN44UXodhOmnOHaEV3dAt7zZfP/m6A6KrepmruWrAaV5YsmkByQQe+rIrBm8TfTty9ADGsoCqOzStJlC+y4QKznAX5LWa0/HFulrHu1MNW2e6HqeAZkQk1GyPo+wxLuw5R6vXebUEjhj+wCd/HesugXUCgYAMVVr0ClRsD9cOxwS6V5e6TJf488KBNyiNyhe0MeecNv2RgaXxeJUmrWyCJCXWbjo/iajGjqk6WpMzNoa6gOUFh2wAgrke9Q810u/kwxHfrUCugYqdOwVE7VIF2bkGjzceTSjdA8uzTa0PRuXKEUROME2jYUAbN6fQk0pJhk/A5w==";
            //AES密钥
            String aesKey="HtcdQxPS8YD/GiD1";
            //String jsonStr = RSA.getSignContent(data);
            //根据字段ASCII值排序
            String jsonStr = JSON.toJSONString(data, SerializerFeature.MapSortField);
            //JSON序列化后 jsonStr : {"endTime":"2022-05-11 10:03:00","startTime":"2022-05-01 10:03:00"}
    
            //RSA加签
            String sign = RSA.sign(jsonStr, signPrivateKey);
            //rsa签名后 sign:R23pIZMSOq/UsX2s9upnpIiYudZ+aZTN/LoOGKKOCvzwPVxBP2L7ECowA5qHBQcAGM+Y8QPnL0t9UsV8BEeYvDHIoiSovc4WA9ezineII8vsiUF0wxKUC4zzeBrhqh3T5oitPp8azCLCP/VtWfzYYfS0TjEr2oCgeMXxe3pwsgg836kGp3dP9a86a2sfv/eURwUwZc3gdhpJSKZqg1trnszQfiMF6sZK3LduNMIt/oiAp++PjfiAwo9S2atpBJQsIcFjMI3Q1/pHEzhoHZ4vh8deH3PTM2PBBITgAyLsPp/eMA6ziOkHiyxDfl3Cm0a3mSsyEv59xKEHBN85+78prA==
    
            //AES 加密
            String encrypt = AES.encrypt(jsonStr, aesKey);
            //aes加密后 encrypt:Kne+m17nZ5RllkJ9RNQqzsQs51BRvPfFzc5EYGfJOd8YOVAgRj/vMWAWxs3UHL3mp16+MOEo1YkPexGd6/oNu11rVqQTvGMNztxqKdm4Y+OjN/46ApD0/wbieN5X9AzGav5tiBEqjfXWegtuSrBIbw==
    
            String clientId="aa5c7f29-d103-11ec-9544-00ff8a20f478";
            Map<String ,Object> params= new HashMap();
            params.put("sign",sign);
            params.put("bizData",encrypt);
            params.put("clientId",clientId);
    
            //发送post请求
            CloseableHttpClient httpclient = HttpClients.createDefault();
            URI url=new URI("https://tid.xxx g.cc/api/thirdparty/order/statistics");
            HttpPost httppost = new HttpPost(url);
            httppost.addHeader("Content-type", "application/json;");
            httppost.setHeader("Accept", "application/json");
            httppost.setEntity(new StringEntity(JSON.toJSONString(params), Charset.forName("UTF-8")));
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String resStr = EntityUtils.toString(entity);
                System.out.println(resStr);
                //{"resp_data":{"total":0,"trail":0,"trail_pengding":0,"trail_close":0,"trail_pass":0,"trail_pass_waiting_pay":0,"trail_pass_waiting_send":0,"trail_pass_waiting_delivery":0,"trail_pass_renting":0,"trail_pass_backing":0,"trail_pass_finish":0,"untrail":0},"resp_code":"10000","resp_msg":"成功"}
            }
        }
    }
    

    RSA

    
    import java.security.*;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.ArrayList;
    import java.util.Base64;
    import java.util.Collections;
    import java.util.List;
    
    /**
     * @author boan
     */
    public class RSA {
       private static final String SIGN_ALGORITHMS = "SHA256withRSA";
        private static final String CHAR_SET = "UTF-8";
    
        public static String sign(String content, String privateKey) {
            try {
                PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
                KeyFactory keyf = KeyFactory.getInstance("RSA");
                PrivateKey priKey = keyf.generatePrivate(priPKCS8);
                java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
                signature.initSign(priKey);
                signature.update(content.getBytes(CHAR_SET));
                byte[] signed = signature.sign();
                return Base64.getEncoder().encodeToString(signed);
            } catch (Exception ex) {
                throw new RuntimeException("RSA 加签异常",ex);
            }
        }
        /**
         * RSA验签名检查
         * @param content 待签名数据
         * @param sign 签名值
         * @param ali_public_key 公钥
         * @return 布尔值
         */
        public static boolean verify(String content, String sign, String ali_public_key){
            try {
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                byte[] encodedKey = Base64.getDecoder().decode(ali_public_key);
                PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
                Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
                signature.initVerify(pubKey);
                signature.update( content.getBytes(CHAR_SET) );
                boolean bverify = signature.verify( Base64.getDecoder().decode((sign) ));
                return bverify;
            }catch (Exception e) {
               throw new RuntimeException("验签异常",e);
            }
        }
    }
    

    AesUtils

    import javax.crypto.Cipher;
    import javax.crypto.spec.SecretKeySpec;
    /**
    * @author netkiller
    */
    public class AesUtils {
        
        public static String encrypt(String input, String key) {
            byte[] crypted = null;
            try {
                
                SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
                
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, skey);
                crypted = cipher.doFinal(input.getBytes());
            } catch (Exception e) {
                throw new RuntimeException("加密异常",e);
            }
            java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
            
            return new String(encoder.encodeToString(crypted));
        }
        
        public static String decrypt(String input, String key) {
            byte[] output = null;
            try {
                java.util.Base64.Decoder decoder = java.util.Base64.getDecoder();
                SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                cipher.init(Cipher.DECRYPT_MODE, skey);
                output = cipher.doFinal(decoder.decode(input));
            } catch (Exception e) {
                throw new RuntimeException("解密异常",e);
            }
            return new String(output);
        }
    }
    
    
    
        private static $url = 'https://xxxx.xxxx.cc/api/thirdparty/order/statistics';//测试地址
        private static $clientId = 'aa5c7f29-d103-11ec-xxxx-00ff8a20f478';//客户端ID
        private static $aesKey = "HtcdQxPS8YD/xxxx";//AES密钥
        private static $rsaKey = "MIIEvAIBADANB.../A5w==";
    
        /**
         * 99pig
         * @param array $options
         * @return Client
         */
        public static function index($options = []){ 
            //业务数据 注意,开始时间和结束时间差不能超过3个月,统计时间以下单时间为准。
            $post_data['startTime'] =  date('Y-m-d H:i:s',time()-24*3600*80);//开始时间 '2022-05-01 10:03:00';//
            $post_data['endTime'] = date('Y-m-d H:i:s');//结束时间 '2022-05-11 10:03:00';//
            ksort($post_data);
            $json_data = json_encode($post_data);
            $private_key = "-----BEGIN RSA PRIVATE KEY-----\n".chunk_split(self::$rsaKey, 64, "\n")."-----END RSA PRIVATE KEY-----\n";
     
            $data['sign'] = openssl_sign($json_data, $signture, openssl_pkey_get_private($private_key),OPENSSL_ALGO_SHA256) ? base64_encode($signture) : '';
            $data['bizData'] = base64_encode(openssl_encrypt($json_data, 'AES-128-ECB', self::$aesKey, OPENSSL_RAW_DATA));//加密后的业务数据
            $data['clientId'] = self::$clientId; 
            return openssl_decrypt(self::curlPost($data,self::$url)['resp_data'], 'AES-128-ECB',  self::$aesKey);
          
        }
    
    
        private static function curlPost($params, $url)
        {
            $data = json_encode($params);
            $ch = curl_init();
            curl_setopt($ch,CURLOPT_URL,$url);
            curl_setopt($ch,CURLOPT_POST,1);
            curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,60);
            curl_setopt($ch,CURLOPT_HTTPHEADER,['Content-Type: application/json','Content-Length:' . strlen($data)]);
            curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
            curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
            $output = curl_exec($ch);
            curl_close($ch);
    
            return json_decode($output, true);
        }
    
    
    接口提供方用java语言,java适合PKCS8方式,非java语言PKCS1方式,java改成PKCS8方式比较麻烦

    php的PKCS1方式;java要也要改成此种方式

    //$json_data:{"endTime":"2022-05-11 10:03:00","startTime":"2022-05-01 10:03:00"}
    //$signature:加密后的结果
    //$private_key:rsaKey私钥,带开始和结束标志
    //OPENSSL_ALGO_SHA1:#PKCS1方式
    //验签成功加密
    if (openssl_sign($json_data, $signature, $private_key, OPENSSL_ALGO_SHA1)) { 
             openssl_private_encrypt($json_data, $signture, $private_key);
     }
    

    php的PKCS8方式;java不用改

    openssl_sign($json_data, $signture, openssl_pkey_get_private($private_key),OPENSSL_ALGO_SHA256) 
    ? base64_encode($signture) 
    : ''
    

    加密验签在线:http://www.metools.info/
    签名算法选OPENSSL_ALGO_SHA256 私钥密码和密钥(带开始和结束标志)和验签字符串

    image.png

    接口返回数据

    ^ array:3 [▼
      "resp_data" => "wmFSjRRihrh9mYZV5tBGWCURmw6P2VxtOyRKChuD5hC2xFq0aYz3zzOOOvdH8LEDstknNSwu+aRSQN0lQLUM8H1DiMkFcRdmoeY1dKi8OTy1czmaRjXcYtOiS74IXPq6/cUO+2dFOtQ13t4wn26wbsu9+qrPCNYS ▶"
      "resp_code" => "10000"
      "resp_msg" => "成功"
    ] 
    

    相关文章

      网友评论

          本文标题:php对接java接口RSA签名及验签问题!

          本文链接:https://www.haomeiwen.com/subject/ibitprtx.html