小于 4M 可以

This commit is contained in:
cheney 2026-06-03 16:34:41 +08:00
parent 0dc2d7c026
commit 983dc8a47d
4 changed files with 298 additions and 26 deletions

View File

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

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

@ -46,10 +46,7 @@ import racal.sunyard.main.proto.*;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import java.io.*; import java.io.*;
import java.net.InetSocketAddress; import java.net.*;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -6857,19 +6854,19 @@ public class SydApi4j implements SydApi {
ParamChecker.checkNotNull(publicKey, "publicKey"); ParamChecker.checkNotNull(publicKey, "publicKey");
ParamChecker.checkNotNull(pOrgData, "pOrgData"); 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 dataLen = pOrgData.length;
int offset = 0; int offset = 0;
while (offset < dataLen) { while (offset < dataLen) {
int len = Math.min(CHUNK_SIZE, dataLen - offset); 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; offset += len;
} }
// 计算 // 计算
SYD_SM2Encrypt(2, publicKey, null, 0); SYD_SM2Encrypt(2, publicKey, null, 0, 0, dataLen);
// 取回 // 取回
int idx = 0; int idx = 0;
@ -6878,7 +6875,7 @@ public class SydApi4j implements SydApi {
int isLast = 0; int isLast = 0;
while (isLast != 1) { 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(); ByteBuffer bb = ret.getData();
isLast = ret.getIsLast(); isLast = ret.getIsLast();
@ -6905,7 +6902,7 @@ public class SydApi4j implements SydApi {
// @Override // @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); ParamChecker.checkInRange(dataType, "dataType", 1, 3);
@ -6928,13 +6925,13 @@ public class SydApi4j implements SydApi {
bb.put(publicKey); bb.put(publicKey);
} }
if ( 1 == dataType ) { // 数据 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(pOrgData);
bb.put(ByteUtil.intToBytes(idx)); bb.put(ByteUtil.intToBytes(idx, ByteOrder.BIG_ENDIAN));
} }
if ( 3 == dataType) { // 仅数据长度 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)); bb.put( ByteUtil.intToBytes(idx, ByteOrder.BIG_ENDIAN));
} }
@ -6947,8 +6944,41 @@ public class SydApi4j implements SydApi {
// 通信 // 通信
synchronized (this) { synchronized (this) {
// 响应解析 int originalTimeout = -1;
bb = syncRead(syncSend(bb)); 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(); bb.flip();
@ -6966,9 +6996,10 @@ public class SydApi4j implements SydApi {
int isLast = bb.get(); int isLast = bb.get();
byte[] dataLenArr = new byte[2]; byte[] dataLenArr = new byte[2];
bb.get(dataLenArr); bb.get(dataLenArr);
int dataLen = ByteUtil.bytesToShort(dataLenArr, ByteOrder.BIG_ENDIAN); int dataLen = Short.toUnsignedInt(ByteUtil.bytesToShort(dataLenArr, ByteOrder.BIG_ENDIAN));
// byte[] data = new byte[dataLen]; // byte[] data = new byte[dataLen];
// bb.get(data); // bb.get(data);
// 从返回数据中创建密文切片此时不拷贝数据
ByteBuffer slice = ByteBufferUtil.sliceAndConsume(bb, dataLen); ByteBuffer slice = ByteBufferUtil.sliceAndConsume(bb, dataLen);
return new MutiReturn7(retCode, isLast, slice); return new MutiReturn7(retCode, isLast, slice);
} else { } else {
@ -6989,19 +7020,19 @@ public class SydApi4j implements SydApi {
ParamChecker.checkNotNull(privateKey, "privateKey"); ParamChecker.checkNotNull(privateKey, "privateKey");
ParamChecker.checkNotNull(pCipherData, "pCipherData"); 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 dataLen = pCipherData.length;
int offset = 0; int offset = 0;
// 1. 分块传入密文 // 1. 分块传入密文
while (offset < dataLen) { while (offset < dataLen) {
int len = Math.min(CHUNK_SIZE, dataLen - offset); 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; offset += len;
} }
// 2. 传入私钥触发解密处理 // 2. 传入私钥触发解密处理
SYD_SM2Decrypt(2, privateKey, null, 0); SYD_SM2Decrypt(2, privateKey, null, 0, 0, dataLen);
// 3. 分块取回明文 // 3. 分块取回明文
int idx = 0; int idx = 0;
@ -7010,7 +7041,7 @@ public class SydApi4j implements SydApi {
int isLast = 0; int isLast = 0;
while (isLast != 1) { 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(); ByteBuffer bb = ret.getData();
isLast = ret.getIsLast(); isLast = ret.getIsLast();
@ -7042,7 +7073,7 @@ public class SydApi4j implements SydApi {
* @param idx 偏移量索引 * @param idx 偏移量索引
* @return MutiReturn7 包含返回码isLast标志及数据片 * @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); ParamChecker.checkInRange(dataType, "dataType", 1, 3);
// 估算缓存大小 // 估算缓存大小
@ -7064,12 +7095,12 @@ public class SydApi4j implements SydApi {
bb.put(privateKey); bb.put(privateKey);
} }
if (dataType == 1) { // 密文块 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(pCipherData);
bb.put(ByteUtil.intToBytes(idx, ByteOrder.BIG_ENDIAN)); bb.put(ByteUtil.intToBytes(idx, ByteOrder.BIG_ENDIAN));
} }
if (dataType == 3) { // 请求明文块 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)); bb.put(ByteUtil.intToBytes(idx, ByteOrder.BIG_ENDIAN));
} }
@ -7080,7 +7111,41 @@ public class SydApi4j implements SydApi {
// 通信 // 通信
synchronized (this) { 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(); bb.flip();
@ -7097,7 +7162,7 @@ public class SydApi4j implements SydApi {
int isLast = bb.get(); int isLast = bb.get();
byte[] dataLenArr = new byte[2]; byte[] dataLenArr = new byte[2];
bb.get(dataLenArr); bb.get(dataLenArr);
int dataLen = ByteUtil.bytesToShort(dataLenArr, ByteOrder.BIG_ENDIAN); int dataLen = Short.toUnsignedInt(ByteUtil.bytesToShort(dataLenArr, ByteOrder.BIG_ENDIAN));
ByteBuffer slice = ByteBufferUtil.sliceAndConsume(bb, dataLen); ByteBuffer slice = ByteBufferUtil.sliceAndConsume(bb, dataLen);
return new MutiReturn7(retCode, isLast, slice); return new MutiReturn7(retCode, isLast, slice);
} else { } else {

View File

@ -16,7 +16,10 @@ public class FunctionTest {
private byte[] publicKey4Sign; private byte[] publicKey4Sign;
private byte[] privateKey4Ende; private byte[] privateKey4Ende;
private byte[] publicKey4Ende; 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[ 4 * 1024 * 1024 - 1024];
private String sign; private String sign;
@Before @Before
@ -26,7 +29,7 @@ public class FunctionTest {
System.setProperty("com.sunyard.sydapi4j.debug", "true"); 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); // RetWrap keypair = this.getPrivateKeyAndPublickKey(keypairIndex4Sign);
// this.publicKey4Sign = Util.hexString2Bytes( keypair.get("pk").toString() ); // this.publicKey4Sign = Util.hexString2Bytes( keypair.get("pk").toString() );
@ -103,6 +106,33 @@ public class FunctionTest {
byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData); byte[] deData = this.api.SYD_SM2Decrypt(privateKey4Ende, enData);
Assert.assertArrayEquals(orgData, deData); 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("密文=" + Util.bytes2HexString(enData));
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);
}
} }