美文网首页
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