diff --git a/chsm-common/src/main/java/com/sunyard/chsm/constant/ParamConfKeyConstant.java b/chsm-common/src/main/java/com/sunyard/chsm/constant/ParamConfKeyConstant.java index c34b803..d32c124 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/constant/ParamConfKeyConstant.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/constant/ParamConfKeyConstant.java @@ -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; } } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/enums/TmkStatusEnum.java b/chsm-common/src/main/java/com/sunyard/chsm/enums/TmkStatusEnum.java new file mode 100644 index 0000000..64a2858 --- /dev/null +++ b/chsm-common/src/main/java/com/sunyard/chsm/enums/TmkStatusEnum.java @@ -0,0 +1,14 @@ +package com.sunyard.chsm.enums; + +/** + * @author liulu + * @since 2024/12/7 + */ +public enum TmkStatusEnum { + + device_error, + key_error, + available, + finished, + +} diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java index 7223526..08a4c71 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java @@ -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); } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapterFactory.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapterFactory.java index 7d385fe..cd3492d 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapterFactory.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapterFactory.java @@ -31,4 +31,7 @@ public class SdfApiAdapterFactory { } + + + } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SunyardJnaSdfAdaptor.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SunyardJnaSdfAdaptor.java index 7f6bc04..1057eed 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SunyardJnaSdfAdaptor.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SunyardJnaSdfAdaptor.java @@ -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 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; + } + } + } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/context/SdrCode.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/context/SdrCode.java new file mode 100644 index 0000000..7488b37 --- /dev/null +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/context/SdrCode.java @@ -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); + } + +} diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java index 05a94ce..2b5e392 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java @@ -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 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 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 pair = checkDeviceSdf(update); + up.setPubKey(pair.getFirst()); + } + spDeviceMapper.updateById(up); } diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java index 7497756..c8d4b4d 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java @@ -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;