Implementing Api interface encrypted communication with java

Interface encryption communication idea:

1) Agree on the secret key for communication between both parties, such as appKey = wenzhou

2) Communication security verification passed sign ature

 1. Generate timestamp, random number or random string, etc., such as timestamp: time=677899002

  2. The communication secret key, time stamp and parameters transmitted by the interface are spliced together through the splicing method agreed by both parties, such as:

Example 1: key1 = value1 & key2 = Value2 & Key3 = & key4 = value4 & appkey = Wenzhou & time = 677899002 &

Example 2: key1value1key2value2key3value3key4value4appKeywenzhoutime677899002

In addition, there are many, which can be agreed by users themselves

  3. Agree on the complex rules of signature, such as replacing the specified characters of spliced string, character exchange before and after string, character left or right shift, etc

For example, do string exchange for example 1 of the convention method: & 200998776 = emit & uohznew = yekppa & 4eulav = 4yek & = 3yek & 2eulav = 2yek & 1eulav = 1yek

For example 2, replace the y character in the string with *: Ke * 1value1ke * 2value2ke * 3value3ke * 4value4appke * wenzhioutime677899002

There are many ways. You can make an agreement by yourself, or you can skip this step

  4. Both parties agree to use the same encryption method to encrypt the final string and generate a signature (you can also capitalize all the generated signatures)

MD5, Base64, RSA # and other encryption algorithms, or write their own encryption algorithms

3) The caller passes the signature generated by the above method to the receiver together with the parameters of the interface parameters involved in generating the signature

4) The receiver generates signatures in the same way and compares whether the signatures are consistent

5) The receiver checks whether the appkeys are consistent

6) The receiver verifies the time stamp time plus the specified time length. For example, the time stamp plus 5 seconds (the effective time of the time stamp is 5 seconds). If the current time is greater than the time after the time stamp plus 5 seconds, the signature expires and access is denied

Agree on the secret key for communication between both parties (the interface provider needs to configure the appKey)

Here, I configure it in application Properties. Small partners can decide the configuration mode according to their own needs

MD5 encryption tool class (generate signature using MD5 encryption)

Here, the spliced string is encrypted to generate a signature. There are many encryption methods, such as RSA, MD5 and Base64

package com.gwssi.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.MessageDigest;

public class MD5Util {
    final static Logger log = LoggerFactory.getLogger(MD5Util.class);
    /**
     * Hexadecimal number to character mapping array
     */
    private final static String[] HEX_DIGITS = {"0", "1", "2", "3", "4",
            "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * md5 encryption algorithm 
     * @param  originString String to be encrypted
     * @return Encrypted string
     */
    public static String encodeByMD5(String originString){
        if (originString != null){
            try{
                //Creates an information summary with the specified algorithm name
                MessageDigest md = MessageDigest.getInstance("MD5");
                //Use the specified byte array to make the final update to the summary, and then complete the summary calculation
                byte[] results = md.digest(originString.getBytes());
                //Turn the resulting byte array into a string and return
                String resultString = byteArrayToHexString(results);
                return resultString.toUpperCase();
            } catch(Exception ex){
                log.error("md5 Encryption algorithm failed", ex);
            }
        }
        return null;
    }

    /**
     * Convert byte array to hexadecimal string
     * @param
     * @return    Hexadecimal string
     */
    private static String byteArrayToHexString(byte[] b){
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++){
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }

    /** Converts a byte into a hexadecimal string     */
    private static String byteToHexString(byte b){
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return HEX_DIGITS[d1] + HEX_DIGITS[d2];
    }
}


 

api interface provider demonstration interface signature verification

package com.gwssi.device.component;
import com.gwssi.common.entity.Constant;
import com.gwssi.common.entity.ResponseCode;
import com.gwssi.common.entity.Result;
import com.gwssi.common.utils.BgUtils;
import com.gwssi.common.utils.MD5Util;
import com.gwssi.common.utils.ThreadCache;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

@Component
public class WenZhouComponent {

    Logger log = LoggerFactory.getLogger(WenZhouComponent.class);

    @Value("${wenzhou.appKey}")
    String localAppKey;

    @SuppressWarnings("unchecked")
    public Map<String,Object> wenzhouApis(){
        //Get request parameters
        JSONObject js = JSONObject.fromObject(ThreadCache.getData(Constant.HTTP_PARAM));
        Map<String,Object> map = (Map<String,Object>) js;
    
        //map data is all parameters passed by the caller_ sign the signature generated by the caller through the agreed rules, the timestamp generated by the time caller, the secret key agreed by both parties, and the type is a common mandatory parameter
        //Required parameter verification
        if(!BgUtils.cheakParamIsNull(map, Arrays.asList("_sign","time","type","appKey"))){
            Result.putValue(ResponseCode.CodeEnum.REQUIRED_PARAM_NULL);
            return null;
        }
        //Signature verification
        if(!checkSign(map.get("_sign").toString(),map.get("appKey").toString(),Long.parseLong(map.get("time").toString()),map)){
            return null;
        }
        int type = Integer.parseInt(map.get("type").toString());
        //Perform interface body operation
        return null;
    }

    //api connection security check
    private boolean checkSign(String getSign,String appKey,long time,Map<String,Object> map){
        //The receiver checks whether the appkeys are consistent
        //Whether the appKey configuration is consistent
            log.info("Configure local appkey:"+localAppKey+" transmit appkey:"+appKey);
        if(!appKey.equals(localAppKey)){
            Result.putValue(ResponseCode.CodeEnum.APP_KEY_ERROR);
            return false;
        }


        //The receiver generates signatures in the same way and compares whether the signatures are consistent
        //The signature rule here is to concatenate all the incoming parameters (except the sign signature parameters) in order, key = value & together, then perform MD5 encryption, and then capitalize all the encrypted results, which is the signature generation rule
        StringBuffer str = new StringBuffer("");
        map.keySet().stream().filter(c->!c.equals("_sign")).forEach(c->str.append(c).append("=").append(map.get(c).toString()).append("&"));
        String mySign = MD5Util.encodeByMD5(str.toString());
        //Whether the signature calculation rules are consistent
        log.info("Encrypted string:"+str.toString()+" Calculate signature:"+mySign+" Delivery signature:"+getSign);
        if(!getSign.equals(mySign.toUpperCase())){
            Result.putValue(ResponseCode.CodeEnum.PARAM_SIGN_INCORRECT);
            return false;
        }


        //The receiver verifies the time stamp time plus the specified time length. For example, the time stamp plus 5 seconds (the effective time of the time stamp is 5 seconds). If the current time is greater than the time after the time stamp plus 5 seconds, the signature expires and access is denied
        //Signature expiration judgment (the time stamp is valid for only 5 seconds)
        if(new Date(time+5000).compareTo(new Date()) < 0){
            log.info("Signed on"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(time+5000))+"Post expiration");
            Result.putValue(ResponseCode.CodeEnum.SIGN_EXPIRE);
            return false;
        }
        return true;
    }


}

api interface address demonstration

    @ApiOperation("Provided by Wenzhou api Interface address encapsulation")
    @RequestMapping("/device/wenzhouApis")
    public void wenzhouApis(){
        wenZhouComponent.wenzhouApis();
    }

Request demo

Simulated caller request:

Receiver:

2021-05-18 17:34:24.682 [ http-nio-9080-exec-2 ] - [ INFO  ] [ o.a.c.core.ContainerBase.[Tomcat].[localhost].[/] : 180 ] - Initializing Spring FrameworkServlet 'dispatcherServlet'
2021-05-18 17:34:24.683 [ http-nio-9080-exec-2 ] - [ INFO  ] [ org.springframework.web.servlet.DispatcherServlet : 494 ] - FrameworkServlet 'dispatcherServlet': initialization started
2021-05-18 17:34:24.761 [ http-nio-9080-exec-2 ] - [ INFO  ] [ org.springframework.web.servlet.DispatcherServlet : 509 ] - FrameworkServlet 'dispatcherServlet': initialization completed in 78 ms
2021-05-18 17:34:24.891 [ http-nio-9080-exec-2 ] - [ INFO  ] [ com.gwssi.filter.ParameterFilter : 79 ] - http-nio-9080-exec-2 --- Request Begin --- /device/wenzhouApis,body={
    "_sign":"EC7ED24DF32F306E8F4E822E263289A3",
    "time":"677899002",
    "type":"1",
    "appKey":"wenzhou"
}
2021-05-18 17:34:24.891 [ http-nio-9080-exec-2 ] - [ INFO  ] [ com.gwssi.filter.ParameterFilter : 83 ] - http-nio-9080-exec-2 --- Request Begin --- /device/wenzhouApis,sysuid=
2021-05-18 17:34:25.053 [ http-nio-9080-exec-2 ] - [ INFO  ] [ com.gwssi.device.component.WenZhouComponent : 58 ] - Configure local appkey:wenzhou transmit appkey:wenzhou
2021-05-18 17:34:25.057 [ http-nio-9080-exec-2 ] - [ INFO  ] [ com.gwssi.device.component.WenZhouComponent : 67 ] - Encrypted string:time=677899002&type=1&appKey=wenzhou& Calculate signature:EC7ED24DF32F306E8F4E822E263289A3 Delivery signature:EC7ED24DF32F306E8F4E822E263289A3
2021-05-18 17:34:25.058 [ http-nio-9080-exec-2 ] - [ INFO  ] [ com.gwssi.device.component.WenZhouComponent : 75 ] - Signed in 1970-01-09 04:18:24 Post expiration
2021-05-18 17:34:25.149 [ http-nio-9080-exec-2 ] - [ INFO  ] [ com.gwssi.interceptor.ParameterInterceptor : 33 ] - http-nio-9080-exec-2 --- /device/wenzhouApis --- Request End --- {"code":14,"data":null,"msg":"Signature expired"}
2021-05-18 17:34:25.150 [ http-nio-9080-exec-2 ] - [ INFO  ] [ com.gwssi.interceptor.ParameterInterceptor : 34 ] - http-nio-9080-exec-2 --- /device/wenzhouApis --- Request Time --- 2021-05-18 17:34:24.905 used 245ms

Online MD5 encryption display: it can be seen that the encryption result is consistent with that of MD5Util

Summary

1) the provider and the caller of the interface agree on a unified parameter encryption algorithm to obtain a sign ature

2) When retrieving parameters, the caller will pass the parameters for calculating the signature sign, the required parameters and the signature to the interface

3) The interface provider encrypts the parameters obtained according to the agreed parameter encryption algorithm to obtain a signature. Compare whether the two signatures are consistent. If they are inconsistent, the interface stops the remaining operations

4) After the signature verification is passed, if the user still has the setting of the effective duration of the signature, he can also ask the provider to pass the timestamp (the time of the receiver is required to be consistent with that of the provider or the redundant time difference during calculation). The timestamp + effective duration is compared with the current time. If it is less than the current duration and the timestamp expires, the interface will stop the remaining operations

5) In order to further ensure security, both parties can also agree to use the public key for encryption. This public key can generally be saved by itself and not passed as a parameter (in this case, it is passed as a parameter, which is generally not recommended)

6) Recommend using https protocol instead of http

 

Keywords: Java interface Encryption

Added by Paul Arnold on Wed, 09 Feb 2022 15:53:08 +0200