Compare commits

...

10 Commits

Author SHA1 Message Date
cheney
09a910006f SM3 性能优化 2026-06-10 10:21:15 +08:00
cheney
83e5033ba0 jmeter 测试用例完成 2026-06-09 09:41:10 +08:00
cheney
664bd110c6 jmeter 测试可用 2026-06-08 18:08:10 +08:00
cheney
b82002801d jmeter 测试可用 2026-06-08 17:03:46 +08:00
cheney
d6a27f3341 性能简单测试 2026-06-08 15:14:22 +08:00
cheney
01be8429be 功能测试通过 2026-06-08 14:08:25 +08:00
cheney
76809e5521 性能测试代码 2026-06-03 17:23:41 +08:00
cheney
983dc8a47d 小于 4M 可以 2026-06-03 16:34:41 +08:00
cheney
0dc2d7c026 小数据测试通过 2026-06-03 14:08:19 +08:00
cheney
02fd07def2 byte 转长度 2026-06-03 11:44:40 +08:00
10 changed files with 4763 additions and 34 deletions

View File

@ -1,3 +1,24 @@
# sydapi4j
加密机 java 接口,基于 jna。
## 启动 Slave
在作为负载机的 Slave 机器上进行配置,主要有两种方式:
方法一:配置 jmeter.properties 文件
编辑 $JMETER_HOME/bin/jmeter.properties 文件,确认或取消注释以下配置:
```
server.rmi.ssl.disable=true # 禁用SSL简化内网配置
server.rmi.localport=1099 # 固定RMI端口方便防火墙放行
java.rmi.server.hostname=Slave_IP # 绑定本机网卡IP避免多网卡问题
```
配置完成后,在 Slave 的 bin 目录下启动服务:
Windows: 双击 jmeter-server.bat
Linux/Mac: 运行 ./jmeter-server
./jmeter-server -Djava.rmi.server.hostname=172.1.41.24 -Dserver.rmi.localport=1099

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,9 @@ public class SydApiException extends RuntimeException{
case 4:
msg = "DER 编码格式错误(公钥) ";
break;
case 31:
msg = "缓冲区索引错误";
break;
case 0xd:
msg = "公钥加密错误";
break;

View File

@ -0,0 +1,103 @@
package com.sunyard.entity;
/**
* SM2加密解密时间统计类
* 用于记录发送计算接收三个阶段的耗时
*/
public class TimeStats {
// 发送阶段总耗时毫秒- 循环发送数据块的时间
private long sendTime;
// 计算阶段耗时毫秒- 执行加密/解密计算的时间
private long computeTime;
// 接收阶段总耗时毫秒- 循环接收数据块的时间
private long receiveTime;
// 发送次数
private int sendCount;
// 接收次数
private int receiveCount;
public TimeStats() {
this.sendTime = 0;
this.computeTime = 0;
this.receiveTime = 0;
this.sendCount = 0;
this.receiveCount = 0;
}
public long getSendTime() {
return sendTime;
}
public void setSendTime(long sendTime) {
this.sendTime = sendTime;
}
public long getComputeTime() {
return computeTime;
}
public void setComputeTime(long computeTime) {
this.computeTime = computeTime;
}
public long getReceiveTime() {
return receiveTime;
}
public void setReceiveTime(long receiveTime) {
this.receiveTime = receiveTime;
}
public int getSendCount() {
return sendCount;
}
public void setSendCount(int sendCount) {
this.sendCount = sendCount;
}
public int getReceiveCount() {
return receiveCount;
}
public void setReceiveCount(int receiveCount) {
this.receiveCount = receiveCount;
}
/**
* 获取总耗时
*/
public long getTotalTime() {
return sendTime + computeTime + receiveTime;
}
/**
* 获取各阶段耗时占比
*/
public double getSendPercentage() {
long total = getTotalTime();
return total == 0 ? 0 : (double) sendTime / total * 100;
}
public double getComputePercentage() {
long total = getTotalTime();
return total == 0 ? 0 : (double) computeTime / total * 100;
}
public double getReceivePercentage() {
long total = getTotalTime();
return total == 0 ? 0 : (double) receiveTime / total * 100;
}
@Override
public String toString() {
return String.format(
"TimeStats{sendTime=%dms(%.1f%%), computeTime=%dms(%.1f%%), receiveTime=%dms(%.1f%%), total=%dms, sendCount=%d, receiveCount=%d}",
sendTime, getSendPercentage(),
computeTime, getComputePercentage(),
receiveTime, getReceivePercentage(),
getTotalTime(),
sendCount, receiveCount
);
}
}

View File

@ -0,0 +1,174 @@
package com.sunyard.util;
import java.nio.ByteOrder;
/**
* 字节数组转换工具类提供常见的基本类型与字节数组之间的互转功能
* 默认采用大端字节序高位在前也支持通过参数指定字节序
*
* @author YourName
*/
public final class BytesUtil {
private BytesUtil() {
// 私有构造方法防止实例化
}
// ==================== 无符号 short 转字节数组 ====================
/**
* 将无符号 short int 形式传入范围 0 ~ 65535转换为大端字节序的字节数组2字节
*
* @param value 无符号 short 0 65535
* @return 长度为 2 的字节数组高位在前
* @throws IllegalArgumentException 如果 value 超出 0~65535 范围
*/
public static byte[] unsignedShortToBytes(int value) {
if (value < 0 || value > 0xFFFF) {
throw new IllegalArgumentException("Value out of range for unsigned short: " + value);
}
return new byte[]{
(byte) ((value >> 8) & 0xFF),
(byte) (value & 0xFF)
};
}
/**
* 将无符号 short short 类型传入自动按无符号处理转换为大端字节序的字节数组2字节
* 例如传入 (short) 0x8001 会得到 { (byte)0x80, (byte)0x01 }
*
* @param value short 类型将按其二进制补码表示直接作为无符号值处理
* @return 长度为 2 的字节数组高位在前
*/
public static byte[] unsignedShortToBytes(short value) {
// short 转为无符号 int
int unsignedValue = value & 0xFFFF;
return unsignedShortToBytes(unsignedValue);
}
/**
* 将无符号 short int 类型转换为指定字节序的字节数组2字节
*
* @param value 无符号 short 0 65535
* @param byteOrder 字节序ByteOrder.BIG_ENDIAN ByteOrder.LITTLE_ENDIAN
* @return 长度为 2 的字节数组
* @throws IllegalArgumentException 如果 value 超出范围或 byteOrder null
*/
public static byte[] unsignedShortToBytes(int value, ByteOrder byteOrder) {
if (byteOrder == null) {
throw new IllegalArgumentException("ByteOrder must not be null");
}
byte[] bytes = unsignedShortToBytes(value);
if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
// 交换高低位
byte tmp = bytes[0];
bytes[0] = bytes[1];
bytes[1] = tmp;
}
return bytes;
}
/**
* 将无符号 short short 类型转换为指定字节序的字节数组2字节
*
* @param value short 类型按无符号处理
* @param byteOrder 字节序
* @return 长度为 2 的字节数组
*/
public static byte[] unsignedShortToBytes(short value, ByteOrder byteOrder) {
return unsignedShortToBytes(value & 0xFFFF, byteOrder);
}
// ==================== 字节数组转无符号 short ====================
/**
* 从字节数组的起始位置读取 2 字节按大端序转换为无符号 short 返回 int 类型
*
* @param bytes 字节数组
* @param offset 起始偏移量
* @return 无符号 short 0 ~ 65535
* @throws IllegalArgumentException 如果 bytes null 或长度不足
*/
public static int bytesToUnsignedShort(byte[] bytes, int offset) {
if (bytes == null || offset + 2 > bytes.length) {
throw new IllegalArgumentException("Invalid byte array or offset");
}
return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF);
}
/**
* 从字节数组的起始位置读取 2 字节按指定字节序转换为无符号 short
*
* @param bytes 字节数组
* @param offset 起始偏移量
* @param byteOrder 字节序
* @return 无符号 short
*/
public static int bytesToUnsignedShort(byte[] bytes, int offset, ByteOrder byteOrder) {
if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
return ((bytes[offset + 1] & 0xFF) << 8) | (bytes[offset] & 0xFF);
} else {
return bytesToUnsignedShort(bytes, offset);
}
}
// ==================== 其他常见转换扩展 ====================
/**
* int 值转换为大端序的 4 字节数组
*/
public static byte[] intToBytes(int value) {
return new byte[]{
(byte) ((value >> 24) & 0xFF),
(byte) ((value >> 16) & 0xFF),
(byte) ((value >> 8) & 0xFF),
(byte) (value & 0xFF)
};
}
/**
* 将大端序的 4 字节数组转换为 int
*/
public static int bytesToInt(byte[] bytes, int offset) {
if (bytes == null || offset + 4 > bytes.length) {
throw new IllegalArgumentException("Invalid byte array or offset");
}
return ((bytes[offset] & 0xFF) << 24)
| ((bytes[offset + 1] & 0xFF) << 16)
| ((bytes[offset + 2] & 0xFF) << 8)
| (bytes[offset + 3] & 0xFF);
}
/**
* long 值转换为大端序的 8 字节数组
*/
public static byte[] longToBytes(long value) {
return new byte[]{
(byte) ((value >> 56) & 0xFF),
(byte) ((value >> 48) & 0xFF),
(byte) ((value >> 40) & 0xFF),
(byte) ((value >> 32) & 0xFF),
(byte) ((value >> 24) & 0xFF),
(byte) ((value >> 16) & 0xFF),
(byte) ((value >> 8) & 0xFF),
(byte) (value & 0xFF)
};
}
/**
* 将大端序的 8 字节数组转换为 long
*/
public static long bytesToLong(byte[] bytes, int offset) {
if (bytes == null || offset + 8 > bytes.length) {
throw new IllegalArgumentException("Invalid byte array or offset");
}
return ((long) (bytes[offset] & 0xFF) << 56)
| ((long) (bytes[offset + 1] & 0xFF) << 48)
| ((long) (bytes[offset + 2] & 0xFF) << 40)
| ((long) (bytes[offset + 3] & 0xFF) << 32)
| ((long) (bytes[offset + 4] & 0xFF) << 24)
| ((long) (bytes[offset + 5] & 0xFF) << 16)
| ((long) (bytes[offset + 6] & 0xFF) << 8)
| ((long) (bytes[offset + 7] & 0xFF));
}
}

View File

@ -16,6 +16,7 @@ import com.sunyard.constant.CertUsage;
import com.sunyard.entity.ImportResult;
import com.sunyard.entity.MutiReturn7;
import com.sunyard.entity.Struct;
import com.sunyard.entity.TimeStats;
import com.sunyard.log.ILogFactory;
import com.sunyard.log.ILogger;
import com.sunyard.proto.Packet;
@ -46,10 +47,7 @@ import racal.sunyard.main.proto.*;
import javax.security.auth.x500.X500Principal;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
@ -334,6 +332,10 @@ public class SydApi4j implements SydApi {
byte[] publicKey,
byte[] orgData) {
if (SydApi.DATA_HASH == nOrgDataType) {
orgData = SM3Hash(Util.bytes2HexString(publicKey), orgData);
}
Proto74 proto = new Proto74();
// 填充数据
@ -6857,19 +6859,19 @@ public class SydApi4j implements SydApi {
ParamChecker.checkNotNull(publicKey, "publicKey");
ParamChecker.checkNotNull(pOrgData, "pOrgData");
final int CHUNK_SIZE = 63 * 1024; // 64 KB
final int CHUNK_SIZE = 62 * 1024; // 62 KB
int dataLen = pOrgData.length;
int offset = 0;
while (offset < dataLen) {
int len = Math.min(CHUNK_SIZE, dataLen - offset);
// 调用底层支持偏移量的加密方法
SYD_SM2Encrypt(1, publicKey, ByteBuffer.wrap(pOrgData, offset, len), offset);
SYD_SM2Encrypt(1, publicKey, ByteBuffer.wrap(pOrgData, offset, len), offset, len, dataLen);
offset += len;
}
// 计算
SYD_SM2Encrypt(2, publicKey, null, 0);
SYD_SM2Encrypt(2, publicKey, null, 0, 0, dataLen);
// 取回
int idx = 0;
@ -6878,7 +6880,7 @@ public class SydApi4j implements SydApi {
int isLast = 0;
while (isLast != 1) {
MutiReturn7 ret = SYD_SM2Encrypt(3, null, null, idx);
MutiReturn7 ret = SYD_SM2Encrypt(3, null, null, idx, 0, 0);
ByteBuffer bb = ret.getData();
isLast = ret.getIsLast();
@ -6905,7 +6907,7 @@ public class SydApi4j implements SydApi {
// @Override
// 支持大包加解密
private MutiReturn7 SYD_SM2Encrypt(int dataType, byte[] publicKey, ByteBuffer pOrgData, int idx) {
private MutiReturn7 SYD_SM2Encrypt(int dataType, byte[] publicKey, ByteBuffer pOrgData, int idx, int inLen, int totalLen) {
// 参数检查
ParamChecker.checkInRange(dataType, "dataType", 1, 3);
@ -6928,13 +6930,13 @@ public class SydApi4j implements SydApi {
bb.put(publicKey);
}
if ( 1 == dataType ) { // 数据
bb.put(ByteUtil.shortToBytes((short) pOrgData.limit(), ByteOrder.BIG_ENDIAN));
bb.put(com.sunyard.util.BytesUtil.unsignedShortToBytes(inLen, ByteOrder.BIG_ENDIAN));
bb.put(pOrgData);
bb.put(ByteUtil.intToBytes(idx));
bb.put(ByteUtil.intToBytes(idx, ByteOrder.BIG_ENDIAN));
}
if ( 3 == dataType) { // 仅数据长度
bb.put( ByteUtil.shortToBytes((short) (63*1024), ByteOrder.BIG_ENDIAN) );
bb.put( ByteUtil.shortToBytes((short) (62*1024), ByteOrder.BIG_ENDIAN) );
bb.put( ByteUtil.intToBytes(idx, ByteOrder.BIG_ENDIAN));
}
@ -6947,8 +6949,41 @@ public class SydApi4j implements SydApi {
// 通信
synchronized (this) {
// 响应解析
bb = syncRead(syncSend(bb));
int originalTimeout = -1;
boolean timeoutModified = false;
try {
// 仅当 dataType == 2 时才执行超时时间调整逻辑
if (false && dataType == 2) {
// 获取当前 Socket 超时时间毫秒可能为 -1无限等待 0立即超时
originalTimeout = this.socket.getSoTimeout();
// 计算 totalLen 1MB 的多少倍整数倍 2M23M34M4
int rate = totalLen / (1024 * 1024);
// 仅当倍数 >1 且原超时时间为正数时才按比例放大超时时间
if (rate > 1 && originalTimeout > 0) {
int newTimeout = originalTimeout * rate;
this.socket.setSoTimeout(newTimeout);
timeoutModified = true; // 标记已修改以便 finally 中恢复
}
}
// 响应解析无论是否调整超时都正常执行
bb = syncRead(syncSend(bb));
} catch (SocketException e) {
throw new SydApiException("socket 状态错误", -5, e);
} finally {
// 仅当超时时间被实际修改过时才恢复原值
if (timeoutModified) {
try {
this.socket.setSoTimeout(originalTimeout);
} catch (SocketException e) {
// 恢复失败时可根据需要记录日志此处忽略
}
}
}
}
bb.flip();
@ -6966,9 +7001,10 @@ public class SydApi4j implements SydApi {
int isLast = bb.get();
byte[] dataLenArr = new byte[2];
bb.get(dataLenArr);
int dataLen = ByteUtil.bytesToInt(dataLenArr, ByteOrder.BIG_ENDIAN);
int dataLen = Short.toUnsignedInt(ByteUtil.bytesToShort(dataLenArr, ByteOrder.BIG_ENDIAN));
// byte[] data = new byte[dataLen];
// bb.get(data);
// 从返回数据中创建密文切片此时不拷贝数据
ByteBuffer slice = ByteBufferUtil.sliceAndConsume(bb, dataLen);
return new MutiReturn7(retCode, isLast, slice);
} else {
@ -6989,19 +7025,19 @@ public class SydApi4j implements SydApi {
ParamChecker.checkNotNull(privateKey, "privateKey");
ParamChecker.checkNotNull(pCipherData, "pCipherData");
final int CHUNK_SIZE = 63 * 1024; // 63 KB与加密保持一致
final int CHUNK_SIZE = 62 * 1024; // 62 KB与加密保持一致
int dataLen = pCipherData.length;
int offset = 0;
// 1. 分块传入密文
while (offset < dataLen) {
int len = Math.min(CHUNK_SIZE, dataLen - offset);
SYD_SM2Decrypt(1, privateKey, ByteBuffer.wrap(pCipherData, offset, len), offset);
SYD_SM2Decrypt(1, privateKey, ByteBuffer.wrap(pCipherData, offset, len), offset, len, 0);
offset += len;
}
// 2. 传入私钥触发解密处理
SYD_SM2Decrypt(2, privateKey, null, 0);
SYD_SM2Decrypt(2, privateKey, null, 0, 0, dataLen);
// 3. 分块取回明文
int idx = 0;
@ -7010,7 +7046,7 @@ public class SydApi4j implements SydApi {
int isLast = 0;
while (isLast != 1) {
MutiReturn7 ret = SYD_SM2Decrypt(3, null, null, idx);
MutiReturn7 ret = SYD_SM2Decrypt(3, null, null, idx, 0, 0);
ByteBuffer bb = ret.getData();
isLast = ret.getIsLast();
@ -7042,7 +7078,7 @@ public class SydApi4j implements SydApi {
* @param idx 偏移量索引
* @return MutiReturn7 包含返回码isLast标志及数据片
*/
private MutiReturn7 SYD_SM2Decrypt(int dataType, byte[] privateKey, ByteBuffer pCipherData, int idx) {
private MutiReturn7 SYD_SM2Decrypt(int dataType, byte[] privateKey, ByteBuffer pCipherData, int idx, int inLen, int totalLen) {
ParamChecker.checkInRange(dataType, "dataType", 1, 3);
// 估算缓存大小
@ -7059,16 +7095,17 @@ public class SydApi4j implements SydApi {
bb.put((byte) dataType);
if (dataType == 2) { // 私钥
bb.put("999999999999999999999999999".getBytes());
bb.put(ByteUtil.shortToBytes((short) privateKey.length, ByteOrder.BIG_ENDIAN));
bb.put(privateKey);
}
if (dataType == 1) { // 密文块
bb.put(ByteUtil.shortToBytes((short) pCipherData.limit(), ByteOrder.BIG_ENDIAN));
bb.put( com.sunyard.util.BytesUtil.unsignedShortToBytes(inLen, ByteOrder.BIG_ENDIAN) );
bb.put(pCipherData);
bb.put(ByteUtil.intToBytes(idx, ByteOrder.BIG_ENDIAN));
}
if (dataType == 3) { // 请求明文块
bb.put(ByteUtil.shortToBytes((short) (63 * 1024), ByteOrder.BIG_ENDIAN));
bb.put(ByteUtil.shortToBytes((short) (62 * 1024), ByteOrder.BIG_ENDIAN));
bb.put(ByteUtil.intToBytes(idx, ByteOrder.BIG_ENDIAN));
}
@ -7079,7 +7116,41 @@ public class SydApi4j implements SydApi {
// 通信
synchronized (this) {
bb = syncRead(syncSend(bb));
int originalTimeout = -1;
boolean timeoutModified = false;
try {
// 仅当 dataType == 2 时才执行超时时间调整逻辑
if (false && dataType == 2) {
// 获取当前 Socket 超时时间毫秒可能为 -1无限等待 0立即超时
originalTimeout = this.socket.getSoTimeout();
// 计算 totalLen 1MB 的多少倍整数倍 2M23M34M4
int rate = totalLen / (1024 * 1024);
// 仅当倍数 >1 且原超时时间为正数时才按比例放大超时时间
if (rate > 1 && originalTimeout > 0) {
int newTimeout = originalTimeout * rate;
this.socket.setSoTimeout(newTimeout);
timeoutModified = true; // 标记已修改以便 finally 中恢复
}
}
// 响应解析无论是否调整超时都正常执行
bb = syncRead(syncSend(bb));
} catch (SocketException e) {
throw new SydApiException("socket 状态错误", -5, e);
} finally {
// 仅当超时时间被实际修改过时才恢复原值
if (timeoutModified) {
try {
this.socket.setSoTimeout(originalTimeout);
} catch (SocketException e) {
// 恢复失败时可根据需要记录日志此处忽略
}
}
}
}
bb.flip();
@ -7096,7 +7167,7 @@ public class SydApi4j implements SydApi {
int isLast = bb.get();
byte[] dataLenArr = new byte[2];
bb.get(dataLenArr);
int dataLen = ByteUtil.bytesToInt(dataLenArr, ByteOrder.BIG_ENDIAN);
int dataLen = Short.toUnsignedInt(ByteUtil.bytesToShort(dataLenArr, ByteOrder.BIG_ENDIAN));
ByteBuffer slice = ByteBufferUtil.sliceAndConsume(bb, dataLen);
return new MutiReturn7(retCode, isLast, slice);
} else {
@ -7104,6 +7175,149 @@ public class SydApi4j implements SydApi {
}
}
/**
* SM2 加密支持大包分段- 带时间统计
* @param publicKey 公钥字节数组
* @param pOrgData 明文数据
* @param timeStats 时间统计对象输出参数
* @return 加密后的密文
*/
public byte[] SYD_SM2Encrypt(byte[] publicKey, byte[] pOrgData, TimeStats timeStats){
ParamChecker.checkNotNull(publicKey, "publicKey");
ParamChecker.checkNotNull(pOrgData, "pOrgData");
final int CHUNK_SIZE = 62 * 1024; // 62 KB
int dataLen = pOrgData.length;
int offset = 0;
long sendStartTime = System.currentTimeMillis();
int sendCount = 0;
while (offset < dataLen) {
int len = Math.min(CHUNK_SIZE, dataLen - offset);
SYD_SM2Encrypt(1, publicKey, ByteBuffer.wrap(pOrgData, offset, len), offset, len, dataLen);
offset += len;
sendCount++;
}
long sendEndTime = System.currentTimeMillis();
long computeStartTime = System.currentTimeMillis();
SYD_SM2Encrypt(2, publicKey, null, 0, 0, dataLen);
long computeEndTime = System.currentTimeMillis();
long receiveStartTime = System.currentTimeMillis();
int idx = 0;
List<ByteBuffer> chunks = new ArrayList<>();
int totalLen = 0;
int isLast = 0;
int receiveCount = 0;
while (isLast != 1) {
MutiReturn7 ret = SYD_SM2Encrypt(3, null, null, idx, 0, 0);
ByteBuffer bb = ret.getData();
isLast = ret.getIsLast();
if (bb != null && bb.remaining() > 0) {
int remaining = bb.remaining();
chunks.add(bb);
totalLen += remaining;
idx += remaining;
receiveCount++;
} else if (isLast != 1) {
throw new RuntimeException("Empty chunk with isLast=0");
}
}
long receiveEndTime = System.currentTimeMillis();
byte[] result = new byte[totalLen];
int offset2 = 0;
for (ByteBuffer chunk : chunks) {
int len = chunk.remaining();
chunk.get(result, offset2, len);
offset2 += len;
}
if (timeStats != null) {
timeStats.setSendTime(sendEndTime - sendStartTime);
timeStats.setComputeTime(computeEndTime - computeStartTime);
timeStats.setReceiveTime(receiveEndTime - receiveStartTime);
timeStats.setSendCount(sendCount);
timeStats.setReceiveCount(receiveCount);
}
return result;
}
/**
* SM2 解密支持大包分段- 带时间统计
* @param privateKey 私钥字节数组
* @param pCipherData 密文数据
* @param timeStats 时间统计对象输出参数
* @return 解密后的明文
*/
public byte[] SYD_SM2Decrypt(byte[] privateKey, byte[] pCipherData, TimeStats timeStats) {
ParamChecker.checkNotNull(privateKey, "privateKey");
ParamChecker.checkNotNull(pCipherData, "pCipherData");
final int CHUNK_SIZE = 62 * 1024; // 62 KB与加密保持一致
int dataLen = pCipherData.length;
int offset = 0;
long sendStartTime = System.currentTimeMillis();
int sendCount = 0;
while (offset < dataLen) {
int len = Math.min(CHUNK_SIZE, dataLen - offset);
SYD_SM2Decrypt(1, privateKey, ByteBuffer.wrap(pCipherData, offset, len), offset, len, 0);
offset += len;
sendCount++;
}
long sendEndTime = System.currentTimeMillis();
long computeStartTime = System.currentTimeMillis();
SYD_SM2Decrypt(2, privateKey, null, 0, 0, dataLen);
long computeEndTime = System.currentTimeMillis();
long receiveStartTime = System.currentTimeMillis();
int idx = 0;
List<ByteBuffer> chunks = new ArrayList<>();
int totalLen = 0;
int isLast = 0;
int receiveCount = 0;
while (isLast != 1) {
MutiReturn7 ret = SYD_SM2Decrypt(3, null, null, idx, 0, 0);
ByteBuffer bb = ret.getData();
isLast = ret.getIsLast();
if (bb != null && bb.remaining() > 0) {
chunks.add(bb);
totalLen += bb.remaining();
idx += bb.remaining();
receiveCount++;
} else if (isLast != 1) {
throw new RuntimeException("Empty plain chunk with isLast=0");
}
}
long receiveEndTime = System.currentTimeMillis();
byte[] result = new byte[totalLen];
int offset2 = 0;
for (ByteBuffer chunk : chunks) {
int len = chunk.remaining();
chunk.get(result, offset2, len);
offset2 += len;
}
if (timeStats != null) {
timeStats.setSendTime(sendEndTime - sendStartTime);
timeStats.setComputeTime(computeEndTime - computeStartTime);
timeStats.setReceiveTime(receiveEndTime - receiveStartTime);
timeStats.setSendCount(sendCount);
timeStats.setReceiveCount(receiveCount);
}
return result;
}
@Override
public String SM2Encrypt(byte[] publicKey, byte[] pOrgData) {
@ -7531,7 +7745,7 @@ public class SydApi4j implements SydApi {
// 填充数据
PacketSN sn = PacketSN.gen();
final int packLen = 4064; // 2048
final int packLen = 8192; //4064 // 2048
int loop = msg.length / packLen;
if (msg.length % packLen > 0) {
loop++;
@ -7587,7 +7801,7 @@ public class SydApi4j implements SydApi {
}
ByteBuffer bb = ByteBuffer.allocate(4 * 1024 + 128);
ByteBuffer bb = ByteBuffer.allocate(10 * 1024 );
byte[] ret = new byte[2];
bb.put(ret);

View File

@ -16,7 +16,10 @@ public class FunctionTest {
private byte[] publicKey4Sign;
private byte[] privateKey4Ende;
private byte[] publicKey4Ende;
private byte[] orgData = new byte[15];
private byte[] orgData = new byte[1024];
private byte[] orgData2K = new byte[ 2 * 1024 ];
private byte[] orgData2M = new byte[ 2 * 1024 * 1024 ];
private byte[] orgData10M = new byte[ 10 * 1024 * 1024 ];
private String sign;
@Before
@ -26,7 +29,7 @@ public class FunctionTest {
System.setProperty("com.sunyard.sydapi4j.debug", "true");
// 建立链接单台
this.api = (SydApi4j) new SydApi4j().connect("192.168.100.145", 8889, null, 5000);
this.api = (SydApi4j) new SydApi4j().connect("192.168.100.145", 8889, null, 30000);
// RetWrap keypair = this.getPrivateKeyAndPublickKey(keypairIndex4Sign);
// this.publicKey4Sign = Util.hexString2Bytes( keypair.get("pk").toString() );
@ -36,7 +39,9 @@ public class FunctionTest {
// this.publicKey4Ende = Util.hexString2Bytes( keypair4Ende.get("pk").toString() );
// this.privateKey4Ende = Util.hexString2Bytes( keypair4Ende.get("sk").toString() );
// 使用预置密钥对
this.publicKey4Sign = Util.hexString2Bytes( "034200046508BC4FE965BEB1D57715C180135FC861FDC6527E82E7FD7A6CA25E7CE9CE75101181D7E2CDD16C1974652B38A045465C7FFBAC700E49F949AE5F4C57AEBEAA" );
this.privateKey4Sign = Util.hexString2Bytes( "00010000CF945DAFF49B9F3AB67A23E1E1BA700FF1F78F5DFFCBB518FD1303A51DABA6FC0000000000000000000000000000000000000000000000000000000000000000" );
this.publicKey4Ende = Util.hexString2Bytes("03420004AF3D4E55D26564C6C937E6EA9232691C01AC5E7916AD2136F788CE7C1E4D0AE8C4754DEC2F7F6A78962D51A171A6F5B4F11823390AEC8B5B0246CD2CCF8052B7");
this.privateKey4Ende = Util.hexString2Bytes("00010000963F7C3A98B7810F52D2861A060E18A9D4D59796CF33967DD61EEDA091E1AD9B0000000000000000000000000000000000000000000000000000000000000000");
}
@ -90,8 +95,23 @@ public class FunctionTest {
@Test
public void SYD_SM2_Sign(){
String sign = this.api.SYD_SM2_Sign_HA(1, privateKey4Sign, publicKey4Sign, orgData);
this.api.SYD_SM2_Verify_HA(1, publicKey4Sign, orgData, sign);
String sign = this.api.SYD_SM2_Sign_HA( SydApi.DATA_HASH, privateKey4Sign, publicKey4Sign, orgData);
this.api.SYD_SM2_Verify_HA(SydApi.DATA_HASH, publicKey4Sign, orgData, sign);
}
@Test
public void SYD_SM2_Sign_2M(){
String sign = this.api.SYD_SM2_Sign_HA( SydApi.DATA_HASH, privateKey4Sign, publicKey4Sign, orgData2M);
this.api.SYD_SM2_Verify_HA(SydApi.DATA_HASH, publicKey4Sign, orgData2M, sign);
}
@Test
public void SYD_SM2_Sign_10M(){
String sign = this.api.SYD_SM2_Sign_HA( SydApi.DATA_HASH, privateKey4Sign, publicKey4Sign, orgData10M);
this.api.SYD_SM2_Verify_HA(SydApi.DATA_HASH, publicKey4Sign, orgData10M, sign);
}
@ -99,8 +119,36 @@ public class FunctionTest {
@Test
public void SYD_SM2_Encrypt(){
byte[] enData = this.api.SYD_SM2Encrypt(publicKey4Ende, orgData);
// byte[] deData = this.api.SYD_SM2Decrypt(publicKey4Ende, enData);
// Assert.assertArrayEquals(enData, deData);
System.out.println("密文=" + Util.bytes2HexString(enData));
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData);
Assert.assertArrayEquals(orgData, deData);
}
@Test
public void SYD_SM2_Encrypt_2K(){
byte[] enData = this.api.SYD_SM2Encrypt(publicKey4Ende, orgData2K);
System.out.println("密文=" + Util.bytes2HexString(enData));
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData);
Assert.assertArrayEquals(orgData2K, deData);
}
@Test
public void SYD_SM2_Encrypt_2M(){
byte[] enData = this.api.SYD_SM2Encrypt(publicKey4Ende, orgData2M);
System.out.println("密文长度=" + enData.length);
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData);
Assert.assertArrayEquals(orgData2M, deData);
}
@Test
public void SYD_SM2_Encrypt_10M(){
byte[] enData = this.api.SYD_SM2Encrypt(publicKey4Ende, orgData10M);
System.out.println("密文=" + Util.bytes2HexString(enData));
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData);
Assert.assertArrayEquals(orgData10M, deData);
}
}

View File

@ -1,35 +1,105 @@
package cmbpoc;
import com.sunyard.SydApi;
import com.sunyard.proto.Util;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
import racal.sunyard.main.SydApi4j;
import java.util.Random;
public class JmeterTest extends AbstractJavaSamplerClient {
private byte[] publicKey;
private byte[] plainData;
private byte[] encryptedData;
private String sign;
private int sleep = 1;
private byte[] privateKey4Sign;
private byte[] publicKey4Sign;
private byte[] privateKey4Ende;
private byte[] publicKey4Ende;
private String ip ;
private int port;
private int timeout;
private String ip2 ;
private ThreadLocal<SydApi4j> api;
@Override
public Arguments getDefaultParameters() {
Arguments params = new Arguments();
params.addArgument("function", "sleep");
params.addArgument("sleep", "1");
params.addArgument("plainDataLen", "1024");
params.addArgument("publicKey4Ende", "", "加密用的公钥");
params.addArgument("privateKey4Ende", "", "解密用的公钥");
params.addArgument("publicKey4Sign", "", "验签用的公钥");
params.addArgument("privateKey4Sign", "", "签名用的公钥");
params.addArgument("ip", "192.168.100.145");
params.addArgument("ip2", "172.1.41.96");
params.addArgument("port", "8889");
params.addArgument("timeout", "3000");
return params;
}
@Override
public void setupTest(JavaSamplerContext context) {
// 签名密钥对
String publicKey4Sign = context.getParameter("publicKey4Sign");
if ( null != publicKey4Sign && !publicKey4Sign.isEmpty()) {
this.publicKey4Sign = Util.hexString2Bytes(publicKey4Sign);
}
String privateKey4Sign = context.getParameter("privateKey4Sign");
if ( null != privateKey4Sign && !privateKey4Sign.isEmpty()) {
this.privateKey4Sign = Util.hexString2Bytes(privateKey4Sign);
}
// 加密密钥对
String publicKey4Ende = context.getParameter("publicKey4Ende");
if ( null != publicKey4Ende && !publicKey4Ende.isEmpty()) {
this.publicKey4Ende = Util.hexString2Bytes(publicKey4Ende);
}
String privateKey4Ende = context.getParameter("privateKey4Ende");
if ( null != privateKey4Ende && !privateKey4Ende.isEmpty()) {
this.privateKey4Ende = Util.hexString2Bytes(privateKey4Ende);
}
// 原始数据
int plainDataLen = context.getIntParameter("plainDataLen");
plainData = new byte[plainDataLen];
new Random().nextBytes(plainData);
System.out.println("原始数据长度:" + plainDataLen);
// 校准测试
sleep = context.getIntParameter("sleep", 1);
// api
ip = context.getParameter("ip");
ip2 = context.getParameter("ip2");
port = context.getIntParameter("port");
timeout = context.getIntParameter("timeout");
api = new ThreadLocal<SydApi4j>() {
@Override
public SydApi4j initialValue() {
return (SydApi4j) new SydApi4j().connect(ip, port, null, timeout);
}
};
// 线程开始时准备解密验签数据
String function = context.getParameter("function");
switch (function) {
case "SYD_SM2_Sign":
case "SYD_SM2_Decrypt":
this.encryptedData = this.api.get().SYD_SM2Encrypt(this.publicKey4Ende, this.plainData);
break;
case "SYD_SM2_Verify":
this.sign = this.api.get().SYD_SM2_Sign_HA(SydApi.DATA_HASH, this.privateKey4Sign, this.publicKey4Sign, this.plainData);
break;
default:
break;
@ -46,7 +116,17 @@ public class JmeterTest extends AbstractJavaSamplerClient {
result.sampleStart(); // 开始计时
try {
switch (function) {
case "SYD_SM2_Encrypt":
this.api.get().SYD_SM2Encrypt(publicKey4Ende, this.plainData);
break;
case "SYD_SM2_Decrypt":
this.api.get().SYD_SM2Decrypt(privateKey4Ende, this.encryptedData);
break;
case "SYD_SM2_Sign":
this.api.get().SYD_SM2_Sign_HA(SydApi.DATA_HASH, privateKey4Sign, publicKey4Sign, this.plainData);
break;
case "SYD_SM2_Verify":
this.api.get().SYD_SM2_Verify_HA(SydApi.DATA_HASH, publicKey4Sign, this.plainData, this.sign);
break;
case "sleep":
Thread.sleep( this.sleep );

View File

@ -0,0 +1,51 @@
package cmbpoc;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
public class JmeterTestTest {
public static void main(String[] args) {
// 1. 创建 JMeter 参数集并填入您提供的所有参数
Arguments jmeterArgs = new Arguments();
jmeterArgs.addArgument("function", "SYD_SM2_Encrypt");
jmeterArgs.addArgument("sleep", "1");
jmeterArgs.addArgument("plainDataLen", "2048");
jmeterArgs.addArgument("publicKey4Ende", "03420004AF3D4E55D26564C6C937E6EA9232691C01AC5E7916AD2136F788CE7C1E4D0AE8C4754DEC2F7F6A78962D51A171A6F5B4F11823390AEC8B5B0246CD2CCF8052B7");
jmeterArgs.addArgument("privateKey4Ende", "00010000963F7C3A98B7810F52D2861A060E18A9D4D59796CF33967DD61EEDA091E1AD9B0000000000000000000000000000000000000000000000000000000000000000");
jmeterArgs.addArgument("ip", "192.168.100.145");
jmeterArgs.addArgument("ip2", "172.1.41.96");
jmeterArgs.addArgument("port", "8889");
jmeterArgs.addArgument("timeout", "3000");
// 2. 基于参数集创建 JMeter 上下文对象
JavaSamplerContext context = new JavaSamplerContext(jmeterArgs);
// 3. 创建您的测试类实例
JmeterTest jmeterTest = new JmeterTest();
try {
// 4. 模拟 JMeter 执行周期setup -> run -> teardown
jmeterTest.setupTest(context);
SampleResult result = jmeterTest.runTest(context);
if (result != null) {
System.out.println("SampleResult 状态: " + result.getResponseCode());
System.out.println("响应数据: " + result.getResponseDataAsString());
System.out.println("是否成功: " + result.isSuccessful());
} else {
System.out.println("runTest 返回 null请检查实现逻辑");
}
jmeterTest.teardownTest(context);
} catch (Exception e) {
System.err.println("执行测试时发生异常:");
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,186 @@
package cmbpoc;
import com.sunyard.RetWrap;
import com.sunyard.SydApi;
import com.sunyard.entity.TimeStats;
import com.sunyard.proto.Util;
import org.junit.*;
import racal.sunyard.main.SydApi4j;
public class PerformanceTest {
private SydApi4j api;
private byte[] privateKey4Ende;
private byte[] publicKey4Ende;
private byte[] orgData2K = new byte[2 * 1024];
private byte[] orgData2M = new byte[2 * 1024 * 1024];
private byte[] orgData10M = new byte[10 * 1024 * 1024];
private static final int TEST_ROUNDS = 10;
@Before
public void start() {
System.setProperty("com.sunyard.sydapi4j.debug", "false");
String ip = System.getProperty("ip", "192.168.100.145");
System.out.println("ip=" + ip);
this.api = (SydApi4j) new SydApi4j().connect(ip, 8889, null, 30000);
this.publicKey4Ende = Util.hexString2Bytes("03420004AF3D4E55D26564C6C937E6EA9232691C01AC5E7916AD2136F788CE7C1E4D0AE8C4754DEC2F7F6A78962D51A171A6F5B4F11823390AEC8B5B0246CD2CCF8052B7");
this.privateKey4Ende = Util.hexString2Bytes("00010000963F7C3A98B7810F52D2861A060E18A9D4D59796CF33967DD61EEDA091E1AD9B0000000000000000000000000000000000000000000000000000000000000000");
}
@After
public void stop() {
if (null != api) {
this.api.disconnect();
this.api = null;
}
}
@Test
public void SYD_SM2_Encrypt_Performance_2K() {
System.out.println("=== SYD_SM2_Encrypt Performance Test - 2K Data ===");
long totalEncryptTime = 0;
long totalDecryptTime = 0;
for (int i = 0; i < TEST_ROUNDS; i++) {
long encryptStart = System.currentTimeMillis();
byte[] enData = this.api.SYD_SM2Encrypt(publicKey4Ende, orgData2K);
long encryptEnd = System.currentTimeMillis();
long decryptStart = System.currentTimeMillis();
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData);
long decryptEnd = System.currentTimeMillis();
totalEncryptTime += (encryptEnd - encryptStart);
totalDecryptTime += (decryptEnd - decryptStart);
Assert.assertArrayEquals(orgData2K, deData);
}
double avgEncryptTime = (double) totalEncryptTime / TEST_ROUNDS;
double avgDecryptTime = (double) totalDecryptTime / TEST_ROUNDS;
double encryptThroughput = (2.0 / avgEncryptTime) * 1000;
double decryptThroughput = (2.0 / avgDecryptTime) * 1000;
System.out.println("Test Rounds: " + TEST_ROUNDS);
System.out.println("Data Size: 2KB");
System.out.printf("Average Encrypt Time: %.2f ms%n", avgEncryptTime);
System.out.printf("Average Decrypt Time: %.2f ms%n", avgDecryptTime);
System.out.printf("Encrypt Throughput: %.2f KB/s%n", encryptThroughput);
System.out.printf("Decrypt Throughput: %.2f KB/s%n", decryptThroughput);
System.out.println();
}
@Test
public void SYD_SM2_Encrypt_Performance_2M() {
System.out.println("=== SYD_SM2_Encrypt Performance Test - 2M Data ===");
long totalEncryptTime = 0;
long totalDecryptTime = 0;
for (int i = 0; i < TEST_ROUNDS; i++) {
long encryptStart = System.currentTimeMillis();
byte[] enData = this.api.SYD_SM2Encrypt(publicKey4Ende, orgData2M);
long encryptEnd = System.currentTimeMillis();
long decryptStart = System.currentTimeMillis();
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData);
long decryptEnd = System.currentTimeMillis();
totalEncryptTime += (encryptEnd - encryptStart);
totalDecryptTime += (decryptEnd - decryptStart);
Assert.assertArrayEquals(orgData2M, deData);
}
double avgEncryptTime = (double) totalEncryptTime / TEST_ROUNDS;
double avgDecryptTime = (double) totalDecryptTime / TEST_ROUNDS;
double encryptThroughput = (2048.0 / avgEncryptTime) * 1000;
double decryptThroughput = (2048.0 / avgDecryptTime) * 1000;
System.out.println("Test Rounds: " + TEST_ROUNDS);
System.out.println("Data Size: 2MB");
System.out.printf("Average Encrypt Time: %.2f ms%n", avgEncryptTime);
System.out.printf("Average Decrypt Time: %.2f ms%n", avgDecryptTime);
System.out.printf("Encrypt Throughput: %.2f KB/s%n", encryptThroughput);
System.out.printf("Decrypt Throughput: %.2f KB/s%n", decryptThroughput);
System.out.println();
}
@Test
public void SYD_SM2_Encrypt_Performance_10M() {
System.out.println("=== SYD_SM2_Encrypt Performance Test - 10M Data ===");
long totalEncryptTime = 0;
long totalDecryptTime = 0;
for (int i = 0; i < TEST_ROUNDS; i++) {
long encryptStart = System.currentTimeMillis();
byte[] enData = this.api.SYD_SM2Encrypt(publicKey4Ende, orgData10M);
long encryptEnd = System.currentTimeMillis();
long decryptStart = System.currentTimeMillis();
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData);
long decryptEnd = System.currentTimeMillis();
totalEncryptTime += (encryptEnd - encryptStart);
totalDecryptTime += (decryptEnd - decryptStart);
Assert.assertArrayEquals(orgData10M, deData);
}
double avgEncryptTime = (double) totalEncryptTime / TEST_ROUNDS;
double avgDecryptTime = (double) totalDecryptTime / TEST_ROUNDS;
double encryptThroughput = (10240.0 / avgEncryptTime) * 1000;
double decryptThroughput = (10240.0 / avgDecryptTime) * 1000;
System.out.println("Test Rounds: " + TEST_ROUNDS);
System.out.println("Data Size: 10MB");
System.out.printf("Average Encrypt Time: %.2f ms%n", avgEncryptTime);
System.out.printf("Average Decrypt Time: %.2f ms%n", avgDecryptTime);
System.out.printf("Encrypt Throughput: %.2f KB/s%n", encryptThroughput);
System.out.printf("Decrypt Throughput: %.2f KB/s%n", decryptThroughput);
System.out.println();
}
@Test
public void SYD_SM2_Encrypt_TimeStats_2M() {
System.out.println("=== SYD_SM2_Encrypt Time Statistics Test - 2M Data ===");
// 预热
for (int i = 0; i < 2; i++) {
byte[] enData = this.api.SYD_SM2Encrypt(publicKey4Ende, orgData2M);
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData);
}
// 正式测试
TimeStats encryptStats = new TimeStats();
TimeStats decryptStats = new TimeStats();
byte[] enData = this.api.SYD_SM2Encrypt(publicKey4Ende, orgData2M, encryptStats);
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData, decryptStats);
Assert.assertArrayEquals(orgData2M, deData);
System.out.println("\n--- 加密阶段时间统计 ---");
System.out.printf("发送阶段: %d ms (%.1f%%), 发送次数: %d%n",
encryptStats.getSendTime(), encryptStats.getSendPercentage(), encryptStats.getSendCount());
System.out.printf("计算阶段: %d ms (%.1f%%)%n",
encryptStats.getComputeTime(), encryptStats.getComputePercentage());
System.out.printf("接收阶段: %d ms (%.1f%%), 接收次数: %d%n",
encryptStats.getReceiveTime(), encryptStats.getReceivePercentage(), encryptStats.getReceiveCount());
System.out.printf("加密总耗时: %d ms%n", encryptStats.getTotalTime());
System.out.println("\n--- 解密阶段时间统计 ---");
System.out.printf("发送阶段: %d ms (%.1f%%), 发送次数: %d%n",
decryptStats.getSendTime(), decryptStats.getSendPercentage(), decryptStats.getSendCount());
System.out.printf("计算阶段: %d ms (%.1f%%)%n",
decryptStats.getComputeTime(), decryptStats.getComputePercentage());
System.out.printf("接收阶段: %d ms (%.1f%%), 接收次数: %d%n",
decryptStats.getReceiveTime(), decryptStats.getReceivePercentage(), decryptStats.getReceiveCount());
System.out.printf("解密总耗时: %d ms%n", decryptStats.getTotalTime());
System.out.println("\n--- 汇总 ---");
long totalTime = encryptStats.getTotalTime() + decryptStats.getTotalTime();
System.out.printf("加密解密总耗时: %d ms%n", totalTime);
System.out.printf("加密吞吐量: %.2f KB/s%n", (2048.0 / encryptStats.getTotalTime()) * 1000);
System.out.printf("解密吞吐量: %.2f KB/s%n", (2048.0 / decryptStats.getTotalTime()) * 1000);
}
}