性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法

news2024/11/27 14:40:30

文章目录

    • 一、前言
    • 二、加密接口
      • 1、什么是SM2
      • 2、被测接口加密逻辑
    • 三、准备工作
    • 四、JMeter 扩展实现
      • 步骤1:准备开发环境
      • 步骤2:了解实现方法
      • 步骤3:runTest 方法
      • 步骤4:getDefaultParameters 方法
      • 步骤5:setupTest 方法
    • 五、编译、部署
    • 六、使用
    • 七、总结

一、前言

国密即国家密码局认定的国产密码算法。通过自主可控的国产密码算法保护重要数据的安全,是有效提升信息安全保障水平的重要举措。目前,我国在金融、教育、交通、通信、国防工业、能源等各类重要领域的信息系统均已开始进行国产密码算法的升级改造。

现如今对使用国密算法加密的接口进行性能测试也逐渐成为是常见的测试场景。使用 JMeter 希望实现更灵活的国密加密测试方式,可以通过对 JMeter 自定义 Java Sampler进行扩展开发来实现。

二、加密接口

1、什么是SM2

为了保障在金融、医疗、能源等领域保障信息传输安全,国家商用密码管理办公室制定了一系列密码标准,包括 SM1(SCB2)、SM2、SM3、SM4、SM7、SM9、祖冲之密码算法(ZUC)等。其中 SM1、SM4、SM7 是对称算法,SM2、SM9 是非对称算法,SM3 是哈希算法。

国密 SM2 算法是一种先进安全的公钥密码算法,在我们国家商用密码体系中被用来替换 RSA 算法。SM2 算法就是 ECC 椭圆曲线密码机制,但在签名、密钥交换方面不同于 ECDSA、ECDH 等国际标准,而是采取了更为安全的机制。另外,SM2 推荐了一条 256 位的曲线作为标准曲线。

关于非对称算法还要注意几点:

  1. 公钥是通过私钥产生的。
  2. 公钥加密,私钥解密是加密的过程。
  3. 私钥加密,公钥解密是签名的过程。

2、被测接口加密逻辑

  1. 客户端接口请求数据交互时,需要提前交换加密所需的公钥;
  2. 在发起请求时,客户端使用提供的公钥对请求参数进行加密;
  3. 服务端收到后,使用对称私钥进行解密后做业务处理;
  4. 服务端在数据返回前对返回数据使用客户端提供的公钥加密
  5. 客户端再接收到数据后使用对称私钥进行解密。
  6. 加密算法使用国密SM2算法。

数据请求与响应过程的数据加密,需要将原始数据体加密为密文内容,并组装为以下格式:

{“pt”:”密文”}

三、准备工作

扩展实现 JMeter Java Sampler 之前,先考虑清楚哪些选项需要暴露出来。在使用SM2加密数据发送请求的时候,需要配置一些基本参数。

  • 加密文本:客户端请求的 Payload
  • 公钥:服务端提供的公钥

下图是本文最终完成的 JMeter自定义 Java Sampler 插件的截图,使用该插件进行测试前,需要输入上面所列的信息。

在这里插入图片描述

四、JMeter 扩展实现

步骤1:准备开发环境

本例中将使用 Maven 来管理依赖并进行打包。针对本文的任务, 项目中需要使用到的依赖包括 ApacheJMeter_core 和 ApacheJMeter_java,以及国密SM2相关类库。

 <dependencies>
        <dependency>
 			<!-- 本地类库,根据实际项目定制 -->
            <groupId>sm-sdk</groupId>
            <artifactId>sm-sdk-0.0.9-snapshot.jar</artifactId>
            <version>0.0.9-snapshot</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/libs/sm-sdk-0.0.9-snapshot.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15to18</artifactId>
            <version>1.69</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_core</artifactId>
            <version>5.6.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_java</artifactId>
            <version>5.6.2</version>
        </dependency>

    </dependencies>

项目创建完毕后,开始编写代码来实现插件。

步骤2:了解实现方法

实现 Java Sampler 自定义请求的两种方式

  • 继承 AbstractJavaSamplerClient 抽象类;
  • 实现 JavaSamplerClient 接口。

通过阅读源码可以发现 AbstractJavaSamplerClient 抽象类是 JavaSamplerClient 接口的子类,所以,我们可以新建一个 JavaClass,并继承 AbstractJavaSamplerClient。

AbstractJavaSamplerClient中 默认实现了四个可以覆盖的方法,分别是 getDefaultParameters(), setupTest(), runTest()和 teardownTest()方法。

  • 方法1:
SampleResult runTest(JavaSamplerContext context)

性能测试时的线程运行体,实现功能逻辑的主方法,每个线程会循环执行这个方法。runTest 方法定义在接口 JavaSamplerClient 中,扩展协议的主体逻辑就是在这个方法中进行编码实现,是必须要实现的方法。

  • 方法2:
public Arguments getDefaultParameters()

主要用于设置传入界面的参数,这个方法由 JMeter 在进行添加 JavaRequest 时第一个运行,它决定了你要在 GUI 中默认显示哪些属性。当每次在 GUI 里点击建立 java requst sampler 的时候会调用该方法。该方法设置了 parameters 的初始值,也可以在 sampler 的 GUI 界面做进一步的修改;

  • 方法3、4:
void setupTest(JavaSamplerContext context)
void teardownTest(JavaSamplerContext context)

setupTest 和 teardownTest 顾名思义,就是在 Java 请求开始时候进行的初始化工作,以及结束时候进行的扫尾工作。这两个方法也不是必须要实现的。

步骤3:runTest 方法

先实现 runTest 方法。 runTest 方法的返回结果为 SampleResult,也就是每次“取样“的结果。方法实现的代码结构如下:

 /**
     * 性能测试线程运行体
     * @return
     */

    @Override
    public SampleResult runTest(JavaSamplerContext context) {

        SampleResult result = new SampleResult();
        // 设置请求名称
        result.setSampleLabel("Jmeter SM2 Java Request");

        //开始统计响应时间标记
        result.sampleStart();

        try {
            long begin = System.currentTimeMillis();

            log.info("-----------------开始执行加密请求-----------------!");

            //调用加密
            ciphertext = SMEncry.sm2Encrypt(text,publicKey);

            long cost = (System.currentTimeMillis() - begin);

            //打印时间戳差值。Java请求响应时间
            System.out.println(ciphertext+" 总计花费:["+cost+"ms]");

            if (ciphertext == null){
                //设置测试结果为fasle
                result.setSuccessful(false);
                return result;
            }
            if (ciphertext.length() != 0){
                //设置测试结果为true
                result.setSuccessful(true);
            }else{
                //设置测试结果为fasle
                result.setSuccessful(false);
                result.setResponseMessage("ERROR");
            }
        }catch (Exception e){
            result.setSuccessful(false);
            result.setResponseMessage("ERROR");
            e.printStackTrace();
        }finally {
            //结束统计响应时间标记
            result.sampleEnd();
            log.info("-----------------结束执行加密请求-----------------!");
        }
        //将请求结果放进result中
        result.setResponseData(ciphertext,"UTF-8");
        //设置响应结果类型
        result.setDataType(SampleResult.TEXT);
        //改变查看结果树中显示的名称
        result.setSampleLabel("自定义SM2加密请求");
        return result;
    }

如上所示,代码逻辑主要是:

  • 接收入参调用SM2算法加密数据。
  • 返回的加密数据结果,给 SampleResult 设置正确的方法、结束时间等,这样 JMeter 引擎可获知测试成功与否,进一步地可以正确显示到 JMeter 的报告结果中。

步骤4:getDefaultParameters 方法

实现参数信息从 JavaSamplerContext 的参数中读取出来:

   /**
     * 设置传入界面的参数
     * @return
     */

    @Override
    public Arguments getDefaultParameters(){
        Arguments arguments = new Arguments();
        arguments.addArgument("text","输入报文");
        arguments.addArgument("publicKey","输入密钥");
        return arguments;
    }

参数具体值的输入由脚本编写人员在 JMeter 界面上编辑脚本时指定,或者在运行期间使用指定变量的值。而为了方便脚本编写人员了解并更改所需的参数,我们通过 getDefaultParameters 方法将这些参数在界面上暴露出来。

步骤5:setupTest 方法

实现启动获取参数的操作。

    private String text;
    private String publicKey;
    private String ciphertext;

    /**
     * 初始化方法
     * @return
     */

    @Override
    public void setupTest(JavaSamplerContext context){
        //获取Jmeter中设置的参数
         text = context.getParameter("text");
         publicKey = context.getParameter("publicKey");
         log.info("text is:"+text);
         log.info("publicKey is:"+publicKey);
    }

五、编译、部署

完成了代码的编写,需要将代码进行编译和部署。这里有两点需要注意:

  • 把该项目所依赖的资源打成一个jar,在 target 目录下会需要生成一个 jar 包,编译出来的 jar 包里包含了所需的第三方类库,避免 JMeter 运行时找不到第三方提供的类的问题。
  • 由于引入本地类库,需要把此类库也打进 jar 包。

在插件工程新建一个assembly.xml

<assembly>
    <id>jar-with-dependencies</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <!-- 默认的配置 -->
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>runtime</scope>
        </dependencySet>
        <!-- 增加scope类型为system的配置 -->
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>system</scope>
        </dependencySet>
    </dependencySets>
</assembly>

因为本地依赖包scope配置为system,而默认的配置为runtime,所以本地依赖包不会打进去,以上配置主要增加了scope类型为system的配置;这样在打包的时候,就会把本地jar也打包进去

本地类库和assembly.xml位置,如下图:
在这里插入图片描述

接下来配置 pom.xml

<build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.7d.zuozewei.jmeter.TestSM2ByJmeter</mainClass>
                        </manifest>
                        <manifestEntries>
                            <Class-Path>.</Class-Path>
                        </manifestEntries>
                    </archive>
                    <!-- 将这一段注释掉 -->
                    <!--<descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>-->
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <!-- 增加配置 -->
                        <configuration>
                            <!-- assembly.xml文件路径 -->
                            <descriptors>
                                <descriptor>src/assembly/assembly.xml</descriptor>
                            </descriptors>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

最后,打包的效果如下:
在这里插入图片描述

将编译好的 jar-with-dependencies 包拷贝到 $JMETER_HOME/lib/ext 目录下,重启 JMeter。启动完毕,添加一个 Java 请求,在类名称下拉列表框中应该就能看到新扩展的类了。如果不存在,请查看一下 lib/ext 目录下是否正确拷贝了 jar 包,也可以查一下 JMeter 的日志,确认没有报出异常。

六、使用

新建一个测试脚本,在测试计划中加入一个线程组,然后添加自定义 Java Sampler。

测试参数:
在这里插入图片描述
测试加密结果:
在这里插入图片描述
那么,如何在业务中使用?可以通过 JSR223 PostProcessor获取加密报文,通过变量然后传入正常的业务Sampler。

参考示例如下:

//获取响应信息
log.info("response is: "+prev.getResponseDataAsString());
String responsesmessage = prev.getResponseDataAsString();
vars.put("value",responsesmessage);

七、总结

如本文所示,我们可以通过比较灵活的方式来扩展 JMeter 对国密算法的测试支持,希望能给大家带来帮助。

相关代码:

  • https://github.com/zuozewei/blog-example/tree/master/Performance-testing/01-test-tool/jmeter/jmeter-sm2-javarequest

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1625531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MATLAB 向量

MATLAB 向量 向量是一维数字数组。MATLAB允许创建两种类型的向量 行向量 列向量 行向量 行向量通过将元素集括在方括号中并使用空格或逗号定界元素来创建。 示例 r [7 8 9 10 11] MATLAB将执行上述语句并返回以下结果- r 7 8 9 10 11 列向量 列向量 通过将元素集括在方…

GPU深度学习环境搭建:Win10+CUDA 11.7+Pytorch1.13.1+Anaconda3+python3.10.9

1. 查看显卡驱动及对应cuda版本关系 1.1 显卡驱动和cuda版本信息查看方法 在命令行中输入【nvidia-smi】可以当前显卡驱动版本和cuda版本。 根据显示,显卡驱动版本为:Driver Version: 516.59,CUDA 的版本为:CUDA Version 11.7。 此处我们可以根据下面的表1 显卡驱动和c…

Android Studio实现内容丰富的安卓校园超市

获取源码请点击文章末尾QQ名片联系&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动 项目代号168 1.开发环境 后端用springboot框架&#xff0c;安卓的用android studio开发 android stuido3.6 jdk1.8 idea mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册…

# 从浅入深 学习 SpringCloud 微服务架构(六)Feign(2)

从浅入深 学习 SpringCloud 微服务架构&#xff08;六&#xff09;Feign&#xff08;2&#xff09; 一、feign 的配置&#xff1a; 1、从 Spring Cloud Edgware 开始&#xff0c;Feign 支持使用属性自定义 Feign。 对于一个指定名称的 FeignClient&#xff08;例如该 Feign …

迅雷不限速破解方法

背景&#xff1a;现在迅雷和百度云的下载速度真的太恶心了&#xff0c;所以总有大佬可以采用厉害的方法进行破解&#xff0c;在网上看了一圈&#xff0c;很多都是骗人或者是无效的&#xff0c;找了一个靠谱的方法&#xff0c;亲测速度能达到10M以上&#xff0c;非常给力。 以下…

linux部署nacos

1.预备环境准备 Nacos 依赖 Java 环境来运行。如果您是从代码开始构建并运行Nacos&#xff0c;还需要为此配置 Maven环境&#xff0c;请确保是在以下版本环境中安装使用: 64 bit OS&#xff0c;支持 Linux/Unix/Mac/Windows&#xff0c;推荐选用 Linux/Unix/Mac。64 bit JDK …

私有化部署 Llama3 大模型, 支持 API 访问

私有化部署 Llama3 大模型, 支持 API 访问 视频 https://www.bilibili.com/video/BV1wD421n75p/ 前言 原文 https://ducafecat.com/blog/llama3-model-api-local 通过 ollama 本地运行 Llama3 大模型其实对我们开发来说很有意义&#xff0c;你可以私有化放服务上了。 然后通…

五、yolov8 tensorRT c++部署及接口封装(保姆级教程附源码)

采用 CTensorRT来部署深度学习模型有以下几个优点&#xff1a; 高性能推理&#xff1a;TensorRT是一个高性能的深度学习推理&#xff08;Inference&#xff09;优化器&#xff0c;专门为NVIDIA GPU硬件平台设计&#xff0c;能够提供低延迟、高吞吐量的模型推理性能。这意味着在…

12 c++版本的坦克大战

前言 呵呵 这大概是 大学里面的 c 贪吃蛇了吧 有一些 面向对象的理解, 但是不多 这里 具体的实现 就不赘述, 仅仅是 发一下代码 以及 具体的使用 坦克大战 #include<iostream> #include<windows.h> #include<conio.h> #include<ctime> #include…

深度学习基础之《TensorFlow框架(13)—二进制数据》

一、CIFAR-10二进制数据集介绍 1、CIFAR-10数据集 CIFAR-10数据集由10个类别的60000个32x32彩色图像组成&#xff0c;每个类别有6000个图像。有50000个训练图像和10000个测试图像 2、数据集分为五个训练批次和一个测试批次&#xff0c;每个批次有10000个图像 3、data_batch_…

强化SSH服务安全的最佳实践

SSH&#xff08;Secure Shell&#xff09;作为一种广泛应用于Linux和其他类Unix系统中的强大工具&#xff0c;为管理员提供了安全的远程登录和命令执行功能。在现今高度互联的网络环境中&#xff0c;确保SSH服务的安全性显得尤为重要。本文将详细阐述一系列SSH服务的最佳实践&a…

探索文本向量化的新高峰:合合信息acge_text_embedding 模型

前言 文本向量化是将文本数据转换为数值向量的过程。由于计算机只能处理数值数据&#xff0c;文本数据需要被转换成数值形式才能被算法和模型处理。这种向量化的过程使得文本数据能够被机器学习、深度学习等算法有效地处理。文本向量化的方法有多种&#xff0c;其中常见的有以…

输入influx但是无法进入influxdb

问题描述&#xff1a; 博主想通过DockerJmeterInfluxDBGrafana搭建性能测试可视化平台&#xff0c;但是按照别的教程输入influx却无法进入inluxdb&#xff0c;输入输出如下&#xff1a; NAME:influx - Influx ClientUSAGE:influx [command]HINT: If you are looking for the I…

多种方法论的融合,可以把FMEA做得更好——FMEA软件

免费试用FMEA软件-免费版-SunFMEA FMEA&#xff0c;即故障模式与影响分析&#xff0c;是一种预防性质量工具&#xff0c;用于识别产品或过程中潜在的故障模式&#xff0c;评估其对系统的影响&#xff0c;并优先处理那些可能导致严重后果的故障。在实际应用中&#xff0c;单一的…

HashMap常用的API

HashMap好用的API isEmpty()和clear() 例子 package com.example.springbootdemo;import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest;import java.util.HashMap;/*** Author yimeng* Date 2024/4/26 9:27* PackageName:com.…

2024年Q1季度平板电视行业线上市场销售数据分析

Q1季度平板电视线上市场表现不如预期。 根据鲸参谋数据显示&#xff0c;2024年1月至3月线上电商平台&#xff08;京东天猫淘宝&#xff09;平板电视累计销量约360万件&#xff0c;环比下降12%&#xff0c;同比下降30%&#xff1b;累计销售额约99亿元&#xff0c;环比下降28%&a…

Mockaroo - 在线生成测试用例利器

简介&#xff1a;Mockaroo 是一个无需安装的在线工具&#xff0c;用于生成大量的自定义测试数据。它支持多种数据格式&#xff0c;如JSON、CSV、SQL和Excel&#xff0c;并能模拟复杂的数据结构。 历史攻略&#xff1a; 测试用例&#xff1a;多条件下编写&#xff0c;懒人妙用…

《苍穹外卖》Day08部分知识点记录

一、useGeneratedKeys和keyProperty useGeneratedKeys和keyProperty是<insert>标签中的两个属性&#xff0c;用于处理自动生成的主键值。 1. useGeneratedKeys userGeneratedKeys"true"表示启用自动生成主键功能&#xff1b;当useGeneratedKeys设置为true时…

Yolov5 export.py实现onnx模型的导出

查了很多资料&#xff0c;很多用python代码写的&#xff0c;只需要这个库那个库的&#xff0c;最后都没成功。 不如直接使用Yolov5里面的 export.py实现模型的转换。 一&#xff1a;安装依赖 因为yolov5里面的requirments.txt是将这些转换模型的都注释掉了 所以需要解除注释…

Redis网络相关的结构体 和 reactor模式

目录 1. epoll的封装 结构体aeApiStae 创建epoll fd的封装 epoll_ctl的封装 epoll_wait的封装 2. 结构体aeFileEvent、aeFiredEvent、aeTimeEvent 结构体aeFileEvent 结构体aeFiredEvent 结构体aeTimeEvent 3. struct aeEventLoop aeEventLoop相关的函数 1. 创建eve…