This commit is contained in:
liulu 2024-12-09 11:10:09 +08:00
parent 48fb1db044
commit 9e8b3fa5c8
8 changed files with 202 additions and 16 deletions

View File

@ -12,6 +12,8 @@ public interface ParamConfKeyConstant {
*/
String IP_WHITELIST_SWITCH = "ipWhitelistSwitch";
String TMK_INIT = "tmk_init";
/**
* 通讯超时时间
*/
@ -105,18 +107,20 @@ public interface ParamConfKeyConstant {
/**
* 系统初始化配置文件路劲
*/
String SYS_PARAM_CONFIG_FILE_PATH = System.getProperty("user.dir") + "/config/sysParam.config.json";
String SYS_PARAM_CONFIG_FILE_PATH = System.getProperty("user.dir") + "/config/sysParam.config.json";
/**
* 调试模式开关枚举
*/
enum SYS_DEBUG_SWITCH_VALUE{
enum SYS_DEBUG_SWITCH_VALUE {
DEV("dev"), CONFIG("config"), PRODUCT("product");
private String value;
private SYS_DEBUG_SWITCH_VALUE(String value){
private SYS_DEBUG_SWITCH_VALUE(String value) {
this.value = value;
}
public String getValue(){
public String getValue() {
return value;
}
}

View File

@ -0,0 +1,14 @@
package com.sunyard.chsm.enums;
/**
* @author liulu
* @since 2024/12/7
*/
public enum TmkStatusEnum {
device_error,
key_error,
available,
finished,
}

View File

@ -13,7 +13,6 @@ import com.sunyard.chsm.sdf.model.SDF_DeviceInfo;
import com.sunyard.chsm.sdf.util.LangUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.util.Assert;
import java.util.Map;
@ -35,6 +34,7 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
protected final SdfLibrary sdfLibrary;
protected abstract int getAlgId(AlgId alg);
protected abstract void checkRes(int res);
@Override
public String openDevice() {
@ -126,7 +126,6 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
byte[] pubKey = new byte[132];
Pointer hSessionHandle = getSessionHandle(sessionHandle);
sdfLibrary.SDF_ExportEncPublicKey_ECC(hSessionHandle, uiKeyIndex, pubKey);
log.info("sdf pubkey: {}", Hex.toHexString(pubKey));
return EccPubKey.fromBytes(pubKey);
}
@ -139,7 +138,6 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
public boolean getPrivateKeyAccessRight(String sessionHandle, int uiKeyIndex, byte[] pucPassword) {
Pointer hSessionHandle = getSessionHandle(sessionHandle);
int res = sdfLibrary.SDF_GetPrivateKeyAccessRight(hSessionHandle, uiKeyIndex, pucPassword, pucPassword.length);
log.info("SDF_GetPrivateKeyAccessRight: {}, {}", res, Integer.toHexString(res));
return res == 0;
}
@ -148,8 +146,7 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
Pointer hSessionHandle = getSessionHandle(sessionHandle);
PointerByReference phKeyHandle = new PointerByReference();
int res = sdfLibrary.SDF_ImportKeyWithISK_ECC(hSessionHandle, uiIskIndex, eccCipher.toSdfData(), phKeyHandle);
log.info("SDF_ImportKeyWithISK_ECC: {}, {}", res, Integer.toHexString(res));
sdfLibrary.SDF_ImportKeyWithISK_ECC(hSessionHandle, uiIskIndex, eccCipher.toSdfData(), phKeyHandle);
String key = UUID.randomUUID().toString();
KEY_HANDLE_CONTEXT.put(key, phKeyHandle.getValue());
return key;
@ -176,9 +173,8 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
Pointer hSessionHandle = getSessionHandle(sessionHandle);
byte[] pucEncDateOut = new byte[164 + pucEncDateIn.getL()];
int res = sdfLibrary.SDF_ExchangeDigitEnvelopeBaseOnECC(hSessionHandle, uiKeyIndex, getAlgId(AlgId.SGD_SM2_1),
sdfLibrary.SDF_ExchangeDigitEnvelopeBaseOnECC(hSessionHandle, uiKeyIndex, getAlgId(AlgId.SGD_SM2_1),
pubKey.toSdfData(), pucEncDateIn.toSdfData(), pucEncDateOut);
log.info("SDF_ExchangeDigitEnvelopeBaseOnECC: {}, {}", res, Integer.toHexString(res));
return EccCipher.fromBytes(pucEncDateOut);
}
@ -187,7 +183,6 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
byte[] encData = new byte[128 + 32 + 4 + pucData.length];
Pointer hSessionHandle = getSessionHandle(sessionHandle);
sdfLibrary.SDF_ExternalEncrypt_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_3), pubKey.toSdfData(), pucData, pucData.length, encData);
log.info("sdfEncryptECC: {}", Hex.toHexString(encData));
return EccCipher.fromBytes(encData);
}

View File

@ -31,4 +31,7 @@ public class SdfApiAdapterFactory {
}
}

View File

@ -3,9 +3,17 @@ package com.sunyard.chsm.sdf.adapter;
import com.sun.jna.Native;
import com.sun.jna.ptr.PointerByReference;
import com.sunyard.chsm.sdf.context.AlgId;
import com.sunyard.chsm.sdf.context.SdrCode;
import com.sunyard.chsm.sdf.context.SunyardAlgId;
import com.sunyard.chsm.sdf.lib.SdfLibrary;
import com.sunyard.chsm.sdf.lib.SunyardSdfLibrary;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ClassUtils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@ -14,6 +22,7 @@ import java.util.concurrent.ConcurrentHashMap;
* @author liulu
* @since 2024/11/4
*/
@Slf4j
public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
private static final Map<String, SunyardSdfLibrary> SDF_LIB_MAP = new ConcurrentHashMap<>();
@ -37,7 +46,30 @@ public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
}
public SunyardJnaSdfAdaptor(String ip, int port, String libName, int connTimeout, int dealTimeout) {
super(SDF_LIB_MAP.computeIfAbsent(libName, k -> Native.load(libName, SunyardSdfLibrary.class)));
super((SdfLibrary) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(),
new Class[]{SdfLibrary.class},
new InvocationHandler() {
private final SunyardSdfLibrary sunyardSdfLibrary;
{
sunyardSdfLibrary = SDF_LIB_MAP.computeIfAbsent(libName, k -> Native.load(libName, SunyardSdfLibrary.class));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = method.invoke(sunyardSdfLibrary, args);
if (method.getName().startsWith("SDF_") && res instanceof Integer) {
int resInt = (Integer) res;
if (resInt != SdrCode.SDR_OK.getCode()) {
log.warn("调用异常: {}, 返回值: {} -{}", method.getName(), Integer.toHexString(resInt), resInt);
SdrCode sdrCode = SdrCode.of((Integer) res);
throw new IllegalArgumentException(sdrCode != null ? sdrCode.getMsg() : "调用sdf接口异常: " + Integer.toHexString(resInt));
}
}
return res;
}
}
));
this.ip = ip;
this.port = port;
this.connTimeout = connTimeout;
@ -59,6 +91,11 @@ public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
return SunyardAlgId.valueOf(alg.name()).getValue();
}
@Override
protected void checkRes(int res) {
}
public static byte[] safeStringBytes(String str) {
if (null == str || str.isEmpty()) {
return new byte[]{0x30};
@ -69,4 +106,15 @@ public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
return ret;
}
@RequiredArgsConstructor
public static class CheckProxy implements InvocationHandler {
private final SdfLibrary sdfLibrary;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
}

View File

@ -0,0 +1,90 @@
package com.sunyard.chsm.sdf.context;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.Objects;
/**
* @author liulu
* @since 2024/12/7
*/
@Getter
@RequiredArgsConstructor
public enum SdrCode {
SDR_OK(0x0, "操作成功"),
SDR_BASE(0x01000000, "错误码基础值"),
SDR_UNKNOWER(SDR_BASE.code + 0x00000001, "未知错误"),
SDR_NOTSUPPORT(SDR_BASE.code + 0x00000002, "不支持的接口调用"),
SDR_COMMFAIL(SDR_BASE.code + 0x00000003, "与设备通信失败"),
SDR_HARDFAIL(SDR_BASE.code + 0x00000004, "运算模块无响应"),
SDR_OPENDEVICE(SDR_BASE.code + 0x00000005, "打开设备失败"),
SDR_OPENSESSION(SDR_BASE.code + 0x00000006, "创建会话失败"),
SDR_PARDENY(SDR_BASE.code + 0x00000007, "无私钥使用权限"),
SDR_KEYNOTEXIST(SDR_BASE.code + 0x00000008, "不存在的密钥调用"),
SDR_ALGNOTSUPPORT(SDR_BASE.code + 0x00000009, "不支持的算法调用"),
SDR_ALGMODNOTSUPPORT(SDR_BASE.code + 0x0000000A, "不支持的算法模式调用"),
SDR_PKOPERR(SDR_BASE.code + 0x0000000B, "公钥运算失败"),
SDR_SKOPERR(SDR_BASE.code + 0x0000000C, "私钥运算失败"),
SDR_SIGNERR(SDR_BASE.code + 0x0000000D, "签名运算失败"),
SDR_VERIFYERR(SDR_BASE.code + 0x0000000E, "验证签名失败"),
SDR_SYMOPERR(SDR_BASE.code + 0x0000000F, "对称算法运算失败"),
SDR_STEPERR(SDR_BASE.code + 0x00000010, "多步运算步骤错误"),
SDR_FILESIZEERR(SDR_BASE.code + 0x00000011, "文件长度超出限制"),
SDR_FILENOEXIST(SDR_BASE.code + 0x00000012, "指定的文件不存在"),
SDR_FILEOFSERR(SDR_BASE.code + 0x00000013, "文件起始位置错误"),
SDR_KEYTYPEERR(SDR_BASE.code + 0x00000014, "密钥类型错误"),
SDR_KEYERR(SDR_BASE.code + 0x00000015, "密钥错误"),
SDR_ENCDATAERR(SDR_BASE.code + 0x00000016, "ECC加密数据错误"),
SDR_RANDERR(SDR_BASE.code + 0x00000017, "随机数产生失败"),
SDR_PRKERR(SDR_BASE.code + 0x00000018, "私钥使用权限获取失败"),
SDR_MACERR(SDR_BASE.code + 0x00000019, "MAC运算失败"),
SDR_FILEEXISTS(SDR_BASE.code + 0x0000001A, "指定文件已存在"),
SDR_FILEWERR(SDR_BASE.code + 0x0000001B, "文件写入失败"),
SDR_NOBUFFER(SDR_BASE.code + 0x0000001C, "存储空间不足"),
SDR_INARGERR(SDR_BASE.code + 0x0000001D, "输入参数错误"),
SDR_OUTARGERR(SDR_BASE.code + 0x0000001E, "输出参数错误"),
SDR_FILERDERR(SDR_BASE.code + 0x0000001F, "文件读取失败"),
SDR_CONSULTERR(SDR_BASE.code + 0x00000020, "密钥协商错误"),
SDR_LEVELERR(SDR_BASE.code + 0x00000021, "权限不足"),
SDR_INDEXERR(SDR_BASE.code + 0x00000022, "索引错误"),
SDR_KEYLENERR(SDR_BASE.code + 0x00000023, "密钥长度错误"),
SDR_DATALENERR(SDR_BASE.code + 0x00000024, "数据长度错误"),
SDR_RIGHTLENERR(SDR_BASE.code + 0x00000025, "私钥授权码长度错误"),
SDR_RIGHTERR(SDR_BASE.code + 0x00000026, "私钥授权码错误"),
SDR_FILEEMPTYERR(SDR_BASE.code + 0x00000027, "文件为空"),
SDR_ERRSTATE(SDR_BASE.code + 0x00000028, "处于错误状态"),
SDR_INITSTATE(SDR_BASE.code + 0x00000029, "处于初始状态"),
SDR_RPRKERR(SDR_BASE.code + 0x0000002A, "私钥使用权限释放失败"),
SDR_SIGNPRKERR(SDR_BASE.code + 0x0000002B, "签名公钥导出失败"),
SDR_ENCPRKERR(SDR_BASE.code + 0x0000002C, "加密公钥导出失败"),
SDR_KPERR(SDR_BASE.code + 0x0000002D, "密钥对生成失败"),
SDR_GENERATEKEYERR(SDR_BASE.code + 0x0000002E, "会话密钥生成失败"),
SDR_IMKEYERR(SDR_BASE.code + 0x0000002F, "导入密钥失败"),
SDR_INTOEXERR(SDR_BASE.code + 0x00000030, "数字信封转换失败"),
/* API新增错误码 */
SRD_DEV_FILE_CONFIG_ERR(SDR_BASE.code + 0x00000040, "配置文件信息错误(请检查配置文件的信息是否有误)"),
SDR_DEVICEHANDLE_INVAILD(SDR_BASE.code + 0x00000041, "设备句柄错误(请检查句柄是否初始化或已经被释放)"),
SDR_SESSIONHANLE_INVAILD(SDR_BASE.code + 0x00000042, "会话句柄错误(请检查句柄是否初始化或已经被释放)"),
SDR_KEYHANLE_INVAILD(SDR_BASE.code + 0x00000043, "密钥句柄错误(请检查句柄是否初始化或已经被释放)"),
SDR_AGREEMENTHANLE_INVAILD(SDR_BASE.code + 0x00000044, "协商句柄错误(请检查句柄是否初始化或已经被释放)"),
SDR_UNKNOWN_HANDLE(SDR_BASE.code + 0x00000045, "未知的句柄"),
SDR_NO_AVAILABL_DEVICE(SDR_BASE.code + 0x00000046, "此设备无法连接, 请检查IP和端口是否正确"),
;
private final int code;
private final String msg;
public static SdrCode of(int code) {
return Arrays.stream(SdrCode.values())
.filter(it -> Objects.equals(it.code, code))
.findFirst()
.orElse(null);
}
}

View File

@ -8,6 +8,7 @@ import com.sunyard.chsm.dto.DeviceDTO;
import com.sunyard.chsm.dto.TmkStatus;
import com.sunyard.chsm.enums.ManufacturerEnum;
import com.sunyard.chsm.enums.ManufacturerModelEnum;
import com.sunyard.chsm.enums.TmkStatusEnum;
import com.sunyard.chsm.mapper.ParamConfMapper;
import com.sunyard.chsm.mapper.SpDeviceMapper;
import com.sunyard.chsm.mapper.TmkInfoMapper;
@ -15,12 +16,15 @@ import com.sunyard.chsm.model.entity.Device;
import com.sunyard.chsm.model.entity.ParamConf;
import com.sunyard.chsm.model.entity.TmkInfo;
import com.sunyard.chsm.sdf.adapter.BcSdfApiAdaptor;
import com.sunyard.chsm.sdf.adapter.SdfApiAdapter;
import com.sunyard.chsm.sdf.adapter.SdfApiAdapterFactory;
import com.sunyard.chsm.sdf.model.EccCipher;
import com.sunyard.chsm.sdf.model.EccPubKey;
import com.sunyard.chsm.service.DeviceService;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.beans.BeanUtils;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
@ -146,6 +150,10 @@ public class DeviceServiceImpl implements DeviceService {
device.setWeight(1);
device.setCreateTime(LocalDateTime.now());
Pair<String, String> pair = checkDeviceSdf(save);
device.setTmkStatus(TmkStatusEnum.available.name());
device.setPubKey(pair.getFirst());
spDeviceMapper.insert(device);
return device.getId();
}
@ -158,6 +166,22 @@ public class DeviceServiceImpl implements DeviceService {
Assert.isNull(exist, "设备IP和端口已存在");
}
private Pair<String, String> checkDeviceSdf(DeviceDTO.DeviceSave save) {
SdfApiAdapter sdfApiAdapter = SdfApiAdapterFactory.newInstance(save.getManufacturerModel(), save.getServiceIp(), save.getServicePort());
String hd = sdfApiAdapter.openDevice();
String hs = null;
try {
hs = sdfApiAdapter.openSession(hd);
EccPubKey eccPubKey = sdfApiAdapter.exportEncPublicKeyECC(hs, save.getEncKeyIdx());
sdfApiAdapter.getPrivateKeyAccessRight(hs, save.getEncKeyIdx(), save.getAccessCredentials().getBytes());
return Pair.of(eccPubKey.getPubKeyHex(), "");
} finally {
Optional.ofNullable(hs).ifPresent(sdfApiAdapter::closeSession);
sdfApiAdapter.closeDevice(hd);
}
}
@Override
public void update(DeviceDTO.DeviceSave update) {
Assert.notNull(update.getId(), "id不能为空");
@ -167,8 +191,9 @@ public class DeviceServiceImpl implements DeviceService {
if (!Objects.equals(exist.getName(), update.getName())) {
checkName(update.getName());
}
if (!Objects.equals(exist.getServiceIp(), update.getServiceIp())
|| !Objects.equals(exist.getServicePort(), update.getServicePort())) {
boolean ipChanged = !Objects.equals(exist.getServiceIp(), update.getServiceIp())
|| !Objects.equals(exist.getServicePort(), update.getServicePort());
if (ipChanged) {
checkIpPort(update.getServiceIp(), update.getServicePort());
}
@ -176,6 +201,13 @@ public class DeviceServiceImpl implements DeviceService {
BeanUtils.copyProperties(update, up);
up.setUpdateTime(LocalDateTime.now());
if (ipChanged
|| !Objects.equals(exist.getEncKeyIdx(), update.getEncKeyIdx())
|| !Objects.equals(exist.getAccessCredentials(), update.getAccessCredentials())) {
Pair<String, String> pair = checkDeviceSdf(update);
up.setPubKey(pair.getFirst());
}
spDeviceMapper.updateById(up);
}

View File

@ -68,7 +68,7 @@ public class AuthHandler implements HandlerInterceptor, InitializingBean {
Collectors.mapping(CryptoServiceApi::getCryptoServiceId, Collectors.toList())));
});
if (codeServiceMap == null || !codeServiceMap.containsKey(code)) {
log.warn("app: {}-{}, 无权访问: {}", user.getAppId(), user.getName(), request.getRequestURI());
log.warn("app: {}-{}, 无权访问: {} - {}", user.getAppId(), user.getName(), code, request.getRequestURI());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("无权访问")));
return false;