赞
踩
国密即国家密码局认定的国产密码算法。通过自主可控的国产密码算法保护重要数据的安全,是有效提升信息安全保障水平的重要举措。目前,我国在金融、教育、交通、通信、国防工业、能源等各类重要领域的信息系统均已开始进行国产密码算法的升级改造。
现如今对使用国密算法加密的接口进行性能测试也逐渐成为是常见的测试场景。使用 JMeter 希望实现更灵活的国密加密测试方式,可以通过对 JMeter 自定义 Java Sampler进行扩展开发来实现。
为了保障在金融、医疗、能源等领域保障信息传输安全,国家商用密码管理办公室制定了一系列密码标准,包括 SM1(SCB2)、SM2、SM3、SM4、SM7、SM9、祖冲之密码算法(ZUC)等。其中 SM1、SM4、SM7 是对称算法,SM2、SM9 是非对称算法,SM3 是哈希算法。
国密 SM2 算法是一种先进安全的公钥密码算法,在我们国家商用密码体系中被用来替换 RSA 算法。SM2 算法就是 ECC 椭圆曲线密码机制,但在签名、密钥交换方面不同于 ECDSA、ECDH 等国际标准,而是采取了更为安全的机制。另外,SM2 推荐了一条 256 位的曲线作为标准曲线。
关于非对称算法还要注意几点:
数据请求与响应过程的数据加密,需要将原始数据体加密为密文内容,并组装为以下格式:
{“pt”:”密文”}
扩展实现 JMeter Java Sampler 之前,先考虑清楚哪些选项需要暴露出来。在使用SM2加密数据发送请求的时候,需要配置一些基本参数。
下图是本文最终完成的 JMeter自定义 Java Sampler 插件的截图,使用该插件进行测试前,需要输入上面所列的信息。
本例中将使用 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>
项目创建完毕后,开始编写代码来实现插件。
实现 Java Sampler 自定义请求的两种方式
通过阅读源码可以发现 AbstractJavaSamplerClient 抽象类是 JavaSamplerClient 接口的子类,所以,我们可以新建一个 JavaClass,并继承 AbstractJavaSamplerClient。
AbstractJavaSamplerClient中 默认实现了四个可以覆盖的方法,分别是 getDefaultParameters(), setupTest(), runTest()和 teardownTest()方法。
SampleResult runTest(JavaSamplerContext context)
性能测试时的线程运行体,实现功能逻辑的主方法,每个线程会循环执行这个方法。runTest 方法定义在接口 JavaSamplerClient 中,扩展协议的主体逻辑就是在这个方法中进行编码实现,是必须要实现的方法。
public Arguments getDefaultParameters()
主要用于设置传入界面的参数,这个方法由 JMeter 在进行添加 JavaRequest 时第一个运行,它决定了你要在 GUI 中默认显示哪些属性。当每次在 GUI 里点击建立 java requst sampler 的时候会调用该方法。该方法设置了 parameters 的初始值,也可以在 sampler 的 GUI 界面做进一步的修改;
void setupTest(JavaSamplerContext context)
void teardownTest(JavaSamplerContext context)
setupTest 和 teardownTest 顾名思义,就是在 Java 请求开始时候进行的初始化工作,以及结束时候进行的扫尾工作。这两个方法也不是必须要实现的。
先实现 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;
}
如上所示,代码逻辑主要是:
实现参数信息从 JavaSamplerContext 的参数中读取出来:
/**
* 设置传入界面的参数
* @return
*/
@Override
public Arguments getDefaultParameters(){
Arguments arguments = new Arguments();
arguments.addArgument("text","输入报文");
arguments.addArgument("publicKey","输入密钥");
return arguments;
}
参数具体值的输入由脚本编写人员在 JMeter 界面上编辑脚本时指定,或者在运行期间使用指定变量的值。而为了方便脚本编写人员了解并更改所需的参数,我们通过 getDefaultParameters 方法将这些参数在界面上暴露出来。
实现启动获取参数的操作。
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);
}
完成了代码的编写,需要将代码进行编译和部署。这里有两点需要注意:
在插件工程新建一个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 对国密算法的测试支持,希望能给大家带来帮助。
相关代码:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。