JMeter入门9---Tcp sampler AES加密

时间:2022-11-08 11:59:27

JMeter入门9---Tcp sampler AES加密

Max.Bai

2018-06


压测tcp请求的时候需要对数据进行处理才发送,比如AES数据加密。实现方法可以有两种,一种自己写java请求,不适用默认tcp sampler, 第二种用默认的Tcp sampler,beanshell实现AES加密。

记录下beanshell实现过程。

1. 添加TCP Sampler

    EOL 设置为10 表示回车符号

2. 在TCP sampler添加 Add->Pre Process -> BeanShell PreProcess

3. 在BeanShell PreProcess 脚本里面添加如下代码。

AES 加密

import org.apache.jmeter.protocol.tcp.sampler.*;			// tcp sample lib
import org.apache.jmeter.samplers.*;			// jmeter samplers lib
import org.apache.jmeter.config.*;   
import com.alibaba.fastjson.JSON;		//fastjson jar save in /lib/ext folder or load in testplan
import com.alibaba.fastjson.JSONObject;
source("./telutils/AESCryptUtils.java");  //path start with bin as default

String IV_PARAMETER = "941c2d70a830c950";
String key = "941c2d70a830c950";

String body = sampler.getRequestData();   	// get tcp sample request data
log.info("PreProcessor===========================================" + body);

timestamp = System.currentTimeMillis();		// timestamp
String seq_num ="201806071746210003";
String s = String.format("abc %s %s", new Object[]{timestamp, seq_num});		//format string
log.info("formate test --->" + s);
log.info("dev id------->" + vars.get("dev_num"));			// get vars, set vars.put("abc", "123");

//parse json string to object 
JSONObject parseObject = JSON.parseObject(body);
// get data
// data to string
String data = parseObject.getString("data");
// string aes encode
String aesbody = AESCryptUtils.encode(data, key, IV_PARAMETER);
// String aesbody = "MTIzNDU2Nzg5MDA5ODc2NTQzMjExMjM0NTY3ODkwMDk";
// set data
parseObject.put("data", aesbody);
parseObject.put("deviceID", "DEVDD" + vars.get("dev_num"));
// add header to request
String  postData = "CST(" + parseObject.toJSONString() + ")\r\n";		// object to json string
log.info("PreProcessor===========================================" + postData);
//postData = "{\"code\":1002,\"deviceId\":\"0000111122223333aaaabbbb\",\"data\":\"MTIzNDU2Nzg5MDA5ODc2NTQzMjExMjM0NTY3ODkwMDk=\"}";
sampler.setRequestData(postData);			// set tcp sampole request data

Post process AES 解密过程

String IV_PARAMETER = "941c2d70a830c950";
String key = "PINd6af6c3134308";
// CTS({"code":"1003","data":"0FZqNrjLsKFZhB7iqKT1ZqpAh49i371GDBCen6/nFrgo7m5lXF1h0P95ru5eQ7UHgvau20ZHOJ/s9DoSBpi+7Kpgj1RzNKOy+Nc5E7W+mQQHiAKiyM6BcX8h9TmTfWHV8mSYxqij1zMB3+59+gC/wPRdhi9WkCEdWkKhkevA8BI/oEtsHUZ6kys9kcqnvT/p7hXjnZvpYcrv5q3GilY7JYS3sQnmP2WfgKu3xnzfWRTCUK3NkjmS6IiCYJIrDlGTenC3sYWikgZOnCoxJS5v/A=="})
String strbody = prev.getResponseDataAsString();   // get tcp response string
int x = strbody.indexOf("{");
int y = strbody.indexOf("}");
String codebody = strbody.substring(x,y+1); 
log.info("codebody===========================================" + codebody);
JSONObject parseObject = JSON.parseObject(codebody);
String aesdata = parseObject.getString("data");
log.info("aesdata===========================================" + aesdata);
//String aesdata = "0FZqNrjLsKFZhB7iqKT1ZqpAh49i371GDBCen6/nFrgo7m5lXF1h0P95ru5eQ7UHgvau20ZHOJ/s9DoSBpi+7Kpgj1RzNKOy+Nc5E7W+mQQHiAKiyM6BcX8h9TmTfWHV8mSYxqij1zMB3+59+gC/wPRdhi9WkCEdWkKhkevA8BI/oEtsHUZ6kys9kcqnvT/p7hXjnZvpYcrv5q3GilY7JYS3sQnmP2WfgKu3xnzfWRTCUK3NkjmS6IiCYJIrDlGTenC3sYWikgZOnCoxJS5v/A==";
String body = AESCryptUtils.decode(aesdata, key, IV_PARAMETER); // decode string

log.info("decrypto===========================================" + body);


4. 代码中包含了fastjson, AES加密脚本,AES加密脚本内容如下:

fastjson 在testplan导入,或者直接放在jmeter lib/ext 目录先,source到如的文件开始目录默认是/bin

 
package com.maxbai.test.util;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

/**  * @date 17/11/21 下午2:30  * AES对称加密工具类  */ public class AESCryptUtils {

    private static final String IV_PARAMETER = "176d3805f01deeab";
    //编码方式
    private static final String CHARSET_NAME = "UTF-8";

    private static final String KEY_ALGORITHM = "AES";

    private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";

    /**  * 加密  *  * @param data 加密内容  * @param key 原始密钥  * @param iv 16bytes初始向量  * @return  */  public static String encode(String data, String key, String iv) {
        return encrypt(data, key, iv);
    }

    public static String encode(String data, String key) {
        return encrypt(data, md5Hex16(key), IV_PARAMETER);
    }

    /**  * 加密  *  * @param data 加密内容  * @param key 原始密钥  * @param iv 16bytes初始向量  * @return  */  public static String decode(String data, String key, String iv) {
        return decrypt(data, key, iv);
    }

    public static String decode(String data, String key) {
        return decrypt(data, md5Hex16(key), IV_PARAMETER);
    }

    /**  * 16位md5加密  *  * @param key 原始密钥  * @return  */  public static String md5Hex16(String key) {
        return DigestUtils.md5Hex(key.getBytes()).substring(8, 24);
    }

    /**  * 加密  *  * @param data 加密内容  * @param md5Key 16位md5后的密钥  * @param iv 初始向量  * @return  */  private static String encrypt(String data, String md5Key, String iv) {
        try {
            IvParameterSpec zeroIv = new IvParameterSpec(iv.getBytes());
            //两个参数,第一个为私钥字节数组, 第二个为加密方式 AES或者DES
            SecretKeySpec key = new SecretKeySpec(md5Key.getBytes(), KEY_ALGORITHM);
            //实例化加密类,参数为加密方式,要写全
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            //初始化,此方法可以采用三种方式,按加密算法要求来添加。(1)无第三个参数(2)第三个参数为SecureRandom random = new SecureRandom();中random对象,随机数。(AES不可采用这种方法)(3)采用此代码中的IVParameterSpec
            cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
            //加密操作,返回加密后的字节数组,然后需要编码。主要编解码方式有Base64, HEX, UUE,7bit等等。此处看服务器需要什么编码方式
            byte[] encryptedData = cipher.doFinal(data.getBytes(CHARSET_NAME));
            return Base64.encodeBase64String(encryptedData);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**  * 解密  *  * @param data 解密内容  * @param strKey 16位密钥  * @param iv 初始向量  * @return  */  private static String decrypt(String data, String strKey, String iv) {
        try {
           byte[] byteMi = Base64.decodeBase64(data);
//            byte[] byteMi = new BASE64Decoder().decodeBuffer(data);
            IvParameterSpec zeroIv = new IvParameterSpec(iv.getBytes());
            SecretKeySpec key = new SecretKeySpec(strKey.getBytes(), KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            //与加密时不同MODE:Cipher.DECRYPT_MODE
            cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
            byte[] decryptedData = cipher.doFinal(byteMi);
            return new String(decryptedData, CHARSET_NAME);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**  * 测试  *  * @param args  * @throws Exception  */  public static void main(String[] args) throws Exception {
        //初始向量,AES为16bytes
        String IV_PARAMETER = "941c2d70a830c950";
        String content = "{\"deviceId\":\"MC93c9c2d8ac435db6019ba619d6a77d\",\"sequence\":\"167783\",\"time\":1515582588066,\"version\":\"XXX.YYY.ZZZ.MMM\"}";
        String key = "941c2d70a830c950";
        //md5密钥
        System.out.println("16位md5密钥:" + md5Hex16(key));
        //偏移量
        System.out.println("初始向量:" + IV_PARAMETER);
        // 加密
        System.out.println("加密前:" + content);
        String encryptResult = encode(content, key, IV_PARAMETER);

        System.out.println("加密后:" + new String(encryptResult));
        // 解密
        String decryptResult = decode(encryptResult, key, IV_PARAMETER);
        System.out.println("解密后:" + new String(decryptResult));
    }

}


5. timestamp 在benshell中的获得

timestamp = System.currentTimeMillis();		// timestamp

6. String.format() 在benshell中只有2个参数,一个是string,一个是Object[].

String s = String.format("abc %s %s", new Object[]{timestamp, seq_num});		//format string


JMeter入门9---Tcp sampler AES加密


附、Bean Shell常用内置变量

    JMeter在它的BeanShell中内置了变量,用户可以通过这些变量与JMeter进行交互,其中主要的变量及其使用方法如下:

  • log:写入信息到jmeber.log文件,使用方法:log.info(“This is log info!”);

  • ctx:该变量引用了当前线程的上下文,使用方法可参考:org.apache.jmeter.threads.JMeterContext

  • vars - (JMeterVariables):操作jmeter变量,这个变量实际引用了JMeter线程中的局部变量容器(本质上是Map),它是测试用例与BeanShell交互的桥梁,常用方法:

    a) vars.get(String key):从jmeter中获得变量值

    b) vars.put(String key,String value):数据存到jmeter变量中

    更多方法可参考:org.apache.jmeter.threads.JMeterVariables

  • props - (JMeterProperties - class java.util.Properties):操作jmeter属性,该变量引用了JMeter的配置信息,可以获取Jmeter的属性,它的使用方法与vars类似,但是只能put进去String类型的值,而不能是一个对象。对应于java.util.Properties。 

    a) props.get("START.HMS");  注:START.HMS为属性名,在文件jmeter.properties中定义 

    b) props.put("PROP1","1234"); 

  • prev - (SampleResult):获取前面的sample返回的信息,常用方法:

    a) getResponseDataAsString():获取响应信息

    b) getResponseCode() :获取响应code

    更多方法可参考:org.apache.jmeter.samplers.SampleResult

  • sampler - (Sampler):gives access to the current sampler



参考:

https://www.blazemeter.com/blog/queen-jmeters-built-componentshow-use-beanshell

https://www.cnblogs.com/clairejing/p/7890144.html

https://blog.csdn.net/doctor_who2004/article/details/53108623