主密钥校验值
This commit is contained in:
parent
8be178317a
commit
ad679f48fd
@ -13,6 +13,7 @@ public interface ParamConfKeyConstant {
|
|||||||
String IP_WHITELIST_SWITCH = "ipWhitelistSwitch";
|
String IP_WHITELIST_SWITCH = "ipWhitelistSwitch";
|
||||||
|
|
||||||
String TMK_INIT = "tmk_init";
|
String TMK_INIT = "tmk_init";
|
||||||
|
String TMK_CHECK_VALUE = "tmk_check_value";
|
||||||
|
|
||||||
String ENABLE_SOFT_DEVICE = "enable_soft_device";
|
String ENABLE_SOFT_DEVICE = "enable_soft_device";
|
||||||
|
|
||||||
|
@ -17,6 +17,9 @@ public class TmkStatus {
|
|||||||
* 主密钥是否初始化
|
* 主密钥是否初始化
|
||||||
*/
|
*/
|
||||||
private boolean tmkInit;
|
private boolean tmkInit;
|
||||||
|
/**
|
||||||
|
* 主密钥校验值
|
||||||
|
*/
|
||||||
|
private String checkValue;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,16 @@ import com.sunyard.chsm.sdf.context.AlgId;
|
|||||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||||
|
import com.sunyard.chsm.sdf.util.LangUtils;
|
||||||
import com.sunyard.chsm.utils.CodecUtils;
|
import com.sunyard.chsm.utils.CodecUtils;
|
||||||
|
import com.sunyard.chsm.utils.gm.BCECUtils;
|
||||||
|
import com.sunyard.chsm.utils.gm.BCSM2Utils;
|
||||||
|
import com.sunyard.chsm.utils.gm.BCSM3Utils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||||
|
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
@ -59,6 +66,8 @@ public class TmkService {
|
|||||||
byte[] prk = sdfApi.symDecrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], encrk);
|
byte[] prk = sdfApi.symDecrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], encrk);
|
||||||
Assert.isTrue(Arrays.equals(rk, prk), "密码机加解密异常");
|
Assert.isTrue(Arrays.equals(rk, prk), "密码机加解密异常");
|
||||||
|
|
||||||
|
byte[] hash = BCSM3Utils.hash(rk);
|
||||||
|
|
||||||
sdfApi.destroyKey(hs, hk);
|
sdfApi.destroyKey(hs, hk);
|
||||||
sdfApi.closeSession(hs);
|
sdfApi.closeSession(hs);
|
||||||
sdfApi.closeDevice(hd);
|
sdfApi.closeDevice(hd);
|
||||||
@ -72,7 +81,7 @@ public class TmkService {
|
|||||||
up.setTmkStatus(DeviceTmkStatus.finished.name());
|
up.setTmkStatus(DeviceTmkStatus.finished.name());
|
||||||
spDeviceMapper.updateById(up);
|
spDeviceMapper.updateById(up);
|
||||||
}
|
}
|
||||||
updateTmkInit(true);
|
updateTmkInit(true, hash);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +91,10 @@ public class TmkService {
|
|||||||
if (init) {
|
if (init) {
|
||||||
status.setHasDevice(true);
|
status.setHasDevice(true);
|
||||||
status.setTmkInit(true);
|
status.setTmkInit(true);
|
||||||
|
ParamConf paramConf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_CHECK_VALUE);
|
||||||
|
if (paramConf != null) {
|
||||||
|
status.setCheckValue(paramConf.getValue());
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
status.setTmkInit(false);
|
status.setTmkInit(false);
|
||||||
@ -90,6 +103,88 @@ public class TmkService {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String backup(String pubKey) {
|
||||||
|
|
||||||
|
boolean tmkInit = isTmkInit();
|
||||||
|
Assert.isTrue(tmkInit, "主密钥未初始化");
|
||||||
|
Device device = getOneByStatus(DeviceTmkStatus.finished);
|
||||||
|
Assert.notNull(device, "没有可以用于备份主密钥的设备");
|
||||||
|
byte[] xy;
|
||||||
|
try {
|
||||||
|
String pubBase6 = pubKey.replace("-----BEGIN ECDSA PUBLIC KEY-----", "").replace("-----END ECDSA PUBLIC KEY-----", "")
|
||||||
|
.replace("\n", "");
|
||||||
|
byte[] pubBytes = CodecUtils.decodeBase64(pubBase6);
|
||||||
|
SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
|
||||||
|
BCECPublicKey key = BCECUtils.createPublicKeyFromSubjectPublicKeyInfo(keyInfo);
|
||||||
|
xy = LangUtils.merge(key.getQ().getXCoord().getEncoded(), key.getQ().getYCoord().getEncoded());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
SdfApiAdapter sdfApi = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort());
|
||||||
|
|
||||||
|
String hd = sdfApi.openDevice();
|
||||||
|
String hs = sdfApi.openSession(hd);
|
||||||
|
sdfApi.getPrivateKeyAccessRight(hs, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
||||||
|
|
||||||
|
EccCipher cipher = sdfApi.exchangeDigitEnvelopeBaseOnECC(hs, device.getEncKeyIdx(), EccPubKey.fromBytes(xy), EccCipher.fromHex(device.getEncTmk()));
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] der = BCSM2Utils.encodeSM2CipherToDER(LangUtils.merge(new byte[]{0x04}, cipher.getC1C3C2Bytes()));
|
||||||
|
return CodecUtils.encodeBase64(der);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pair<Long, String> getDevicePubKey() {
|
||||||
|
Device device = getOneByStatus(DeviceTmkStatus.available);
|
||||||
|
Assert.notNull(device, "没有可以用于导入主密钥的设备");
|
||||||
|
SdfApiAdapter sdfApi = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort());
|
||||||
|
String hd = sdfApi.openDevice();
|
||||||
|
String hs = sdfApi.openSession(hd);
|
||||||
|
EccPubKey pubKey = sdfApi.exportEncPublicKeyECC(hs, device.getEncKeyIdx());
|
||||||
|
|
||||||
|
BCECPublicKey publicKey = BCECUtils.createPublicKey(pubKey.getPubKeyHex());
|
||||||
|
return Pair.of(device.getId(), CodecUtils.encodeBase64(publicKey.getEncoded()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void importTmk(Long deviceId, String encTmk) {
|
||||||
|
boolean tmkInit = isTmkInit();
|
||||||
|
Assert.isTrue(!tmkInit, "主密钥已经初始化");
|
||||||
|
|
||||||
|
Device device = getOneByStatus(DeviceTmkStatus.available);
|
||||||
|
Assert.notNull(device, "没有可以用于导入主密钥的设备");
|
||||||
|
SdfApiAdapter sdfApi = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort());
|
||||||
|
String hd = sdfApi.openDevice();
|
||||||
|
String hs = sdfApi.openSession(hd);
|
||||||
|
byte[] rk = CodecUtils.decodeBase64(encTmk);
|
||||||
|
EccPubKey pubKey = sdfApi.exportEncPublicKeyECC(hs, device.getEncKeyIdx());
|
||||||
|
EccCipher cipher = sdfApi.externalEncryptECC(hs, pubKey, rk);
|
||||||
|
sdfApi.getPrivateKeyAccessRight(hs, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
||||||
|
String hk = sdfApi.importKeyWithISKECC(hs, device.getEncKeyIdx(), cipher);
|
||||||
|
byte[] encrk = sdfApi.symEncrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], rk);
|
||||||
|
byte[] prk = sdfApi.symDecrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], encrk);
|
||||||
|
Assert.isTrue(Arrays.equals(rk, prk), "密码机加解密异常");
|
||||||
|
|
||||||
|
byte[] hash = BCSM3Utils.hash(rk);
|
||||||
|
|
||||||
|
sdfApi.destroyKey(hs, hk);
|
||||||
|
sdfApi.closeSession(hs);
|
||||||
|
sdfApi.closeDevice(hd);
|
||||||
|
|
||||||
|
if (Objects.equals(device.getManufacturerModel(), BouncyCastleProvider.PROVIDER_NAME)) {
|
||||||
|
updateSoftDeviceEncTmk(cipher.getC1C3C2Bytes());
|
||||||
|
} else {
|
||||||
|
Device up = new Device();
|
||||||
|
up.setId(device.getId());
|
||||||
|
up.setEncTmk(cipher.getC1C3C2Hex());
|
||||||
|
up.setTmkStatus(DeviceTmkStatus.finished.name());
|
||||||
|
spDeviceMapper.updateById(up);
|
||||||
|
}
|
||||||
|
updateTmkInit(true, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public DeviceCheckRes checkDevice(Device check) {
|
public DeviceCheckRes checkDevice(Device check) {
|
||||||
|
|
||||||
@ -209,6 +304,7 @@ public class TmkService {
|
|||||||
}
|
}
|
||||||
if (isEnableSoftDevice()) {
|
if (isEnableSoftDevice()) {
|
||||||
device = new Device();
|
device = new Device();
|
||||||
|
device.setId(0L);
|
||||||
device.setManufacturerModel(BouncyCastleProvider.PROVIDER_NAME);
|
device.setManufacturerModel(BouncyCastleProvider.PROVIDER_NAME);
|
||||||
device.setEncKeyIdx(1);
|
device.setEncKeyIdx(1);
|
||||||
device.setServiceIp("127.0.0.1");
|
device.setServiceIp("127.0.0.1");
|
||||||
@ -241,7 +337,7 @@ public class TmkService {
|
|||||||
return conf != null && String.valueOf(true).equals(conf.getValue());
|
return conf != null && String.valueOf(true).equals(conf.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTmkInit(boolean value) {
|
private void updateTmkInit(boolean value, byte[] hash) {
|
||||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
|
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
|
||||||
if (conf == null) {
|
if (conf == null) {
|
||||||
conf = new ParamConf();
|
conf = new ParamConf();
|
||||||
@ -253,6 +349,18 @@ public class TmkService {
|
|||||||
conf.setValue(String.valueOf(value));
|
conf.setValue(String.valueOf(value));
|
||||||
paramConfMapper.updateById(conf);
|
paramConfMapper.updateById(conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParamConf check = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_CHECK_VALUE);
|
||||||
|
if (check == null) {
|
||||||
|
check = new ParamConf();
|
||||||
|
check.setValue(CodecUtils.encodeHex(hash));
|
||||||
|
check.setKey(ParamConfKeyConstant.TMK_CHECK_VALUE);
|
||||||
|
check.setCreatTime(LocalDateTime.now());
|
||||||
|
paramConfMapper.insert(conf);
|
||||||
|
} else {
|
||||||
|
check.setValue(CodecUtils.encodeHex(hash));
|
||||||
|
paramConfMapper.updateById(conf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized byte[] getSoftDeviceEncTmk() {
|
public synchronized byte[] getSoftDeviceEncTmk() {
|
||||||
|
@ -61,7 +61,7 @@ import java.util.Arrays;
|
|||||||
/**
|
/**
|
||||||
* 这个工具类的方法,也适用于其他基于BC库的ECC算法
|
* 这个工具类的方法,也适用于其他基于BC库的ECC算法
|
||||||
*/
|
*/
|
||||||
public class BCECUtils {
|
public class BCECUtils extends GMBaseUtil {
|
||||||
private static final String ALGO_NAME_EC = "EC";
|
private static final String ALGO_NAME_EC = "EC";
|
||||||
private static final String PEM_STRING_PUBLIC = "PUBLIC KEY";
|
private static final String PEM_STRING_PUBLIC = "PUBLIC KEY";
|
||||||
private static final String PEM_STRING_ECPRIVATEKEY = "EC PRIVATE KEY";
|
private static final String PEM_STRING_ECPRIVATEKEY = "EC PRIVATE KEY";
|
||||||
|
@ -3,13 +3,19 @@ package com.sunyard.chsm.controller;
|
|||||||
import com.sunyard.chsm.model.R;
|
import com.sunyard.chsm.model.R;
|
||||||
import com.sunyard.chsm.model.dto.TmkStatus;
|
import com.sunyard.chsm.model.dto.TmkStatus;
|
||||||
import com.sunyard.chsm.service.TmkService;
|
import com.sunyard.chsm.service.TmkService;
|
||||||
|
import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主密钥管理
|
* 主密钥管理
|
||||||
@ -45,5 +51,63 @@ public class TmkController {
|
|||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备份主密钥
|
||||||
|
*/
|
||||||
|
@PostMapping("/backup")
|
||||||
|
public R<String> backup(@Valid @RequestBody TmkBackupReq req) {
|
||||||
|
String en = tmkService.backup(req.pubKey);
|
||||||
|
return R.data(en);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备公钥
|
||||||
|
*/
|
||||||
|
@GetMapping("/devicePubKey")
|
||||||
|
public R<DevicePubKey> getDevicePubKey() {
|
||||||
|
Pair<Long, String> pair = tmkService.getDevicePubKey();
|
||||||
|
DevicePubKey res = new DevicePubKey();
|
||||||
|
res.deviceId = pair.getLeft();
|
||||||
|
res.pubKey = pair.getRight();
|
||||||
|
return R.data(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入主密钥
|
||||||
|
*/
|
||||||
|
@PostMapping("/import")
|
||||||
|
public R<Void> importTmk(@Valid @RequestBody TmkImportReq req) {
|
||||||
|
tmkService.importTmk(req.deviceId, req.encTmk);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class DevicePubKey {
|
||||||
|
private Long deviceId;
|
||||||
|
private String pubKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class TmkBackupReq {
|
||||||
|
/**
|
||||||
|
* ukey公钥
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "公钥不能为空")
|
||||||
|
private String pubKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class TmkImportReq {
|
||||||
|
/**
|
||||||
|
* 设备id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "设备id不能为空")
|
||||||
|
private Long deviceId;
|
||||||
|
/**
|
||||||
|
* 加密主密钥
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "加密主密钥不能为空")
|
||||||
|
private String encTmk;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ CREATE TABLE "SC_PERMISSION"(
|
|||||||
|
|
||||||
|
|
||||||
-- 初始化数据
|
-- 初始化数据
|
||||||
INSERT INTO SC_PARAM_CONF (ITEM, KEY, VALUE, TYPE, STATUS, MEMO) VALUES (0, 'ipWhitelistSwitch', 'true', 'OBJECT', 0, null);
|
INSERT INTO SC_PARAM_CONF (ITEM, KEY, VALUE, TYPE, STATUS, MEMO) VALUES (0, 'ipWhitelistSwitch', 'false', 'OBJECT', 0, null);
|
||||||
INSERT INTO SC_PARAM_CONF (ITEM, KEY, VALUE, TYPE, STATUS, MEMO) VALUES (1, 'communicateTimeOut', '30', 'OBJECT', 0, null);
|
INSERT INTO SC_PARAM_CONF (ITEM, KEY, VALUE, TYPE, STATUS, MEMO) VALUES (1, 'communicateTimeOut', '30', 'OBJECT', 0, null);
|
||||||
INSERT INTO SC_PARAM_CONF (ITEM, KEY, VALUE, TYPE, STATUS, MEMO) VALUES (1, 'heartDetectTime', '5', 'OBJECT', 0, null);
|
INSERT INTO SC_PARAM_CONF (ITEM, KEY, VALUE, TYPE, STATUS, MEMO) VALUES (1, 'heartDetectTime', '5', 'OBJECT', 0, null);
|
||||||
INSERT INTO SC_PARAM_CONF (ITEM, KEY, VALUE, TYPE, STATUS, MEMO) VALUES (1, 'ftpUploadPath', '/app/upload', 'OBJECT', 0, null);
|
INSERT INTO SC_PARAM_CONF (ITEM, KEY, VALUE, TYPE, STATUS, MEMO) VALUES (1, 'ftpUploadPath', '/app/upload', 'OBJECT', 0, null);
|
||||||
@ -216,7 +216,7 @@ INSERT INTO SC_DICT (ID, TYPE, TITLE, SCOPE, SORT_ORDER, DESCRIPTION) VALUES (42
|
|||||||
INSERT INTO SC_DICT (ID, TYPE, TITLE, SCOPE, SORT_ORDER, DESCRIPTION) VALUES (76, 'Publickey_format', '公钥格式', 1, 0, null);
|
INSERT INTO SC_DICT (ID, TYPE, TITLE, SCOPE, SORT_ORDER, DESCRIPTION) VALUES (76, 'Publickey_format', '公钥格式', 1, 0, null);
|
||||||
INSERT INTO SC_DICT (ID, TYPE, TITLE, SCOPE, SORT_ORDER, DESCRIPTION) VALUES (81, 'version', '系统版本号', 1, 0, '');
|
INSERT INTO SC_DICT (ID, TYPE, TITLE, SCOPE, SORT_ORDER, DESCRIPTION) VALUES (81, 'version', '系统版本号', 1, 0, '');
|
||||||
|
|
||||||
SET IDENTITY_INSERT SC_DICT_DATA ON
|
SET IDENTITY_INSERT SC_DICT_DATA ON;
|
||||||
INSERT INTO SC_DICT_DATA (ID, DICT_ID, TITLE, VALUE, SORT_ORDER, STATUS, DESCRIPTION) VALUES (25, 76, 'DER', 'DER', 1, 0, null);
|
INSERT INTO SC_DICT_DATA (ID, DICT_ID, TITLE, VALUE, SORT_ORDER, STATUS, DESCRIPTION) VALUES (25, 76, 'DER', 'DER', 1, 0, null);
|
||||||
INSERT INTO SC_DICT_DATA (ID, DICT_ID, TITLE, VALUE, SORT_ORDER, STATUS, DESCRIPTION) VALUES (26, 76, 'BASE64', 'BASE64', 2, 0, null);
|
INSERT INTO SC_DICT_DATA (ID, DICT_ID, TITLE, VALUE, SORT_ORDER, STATUS, DESCRIPTION) VALUES (26, 76, 'BASE64', 'BASE64', 2, 0, null);
|
||||||
INSERT INTO SC_DICT_DATA (ID, DICT_ID, TITLE, VALUE, SORT_ORDER, STATUS, DESCRIPTION) VALUES (27, 38, '30秒', '30000', 1, 0, null);
|
INSERT INTO SC_DICT_DATA (ID, DICT_ID, TITLE, VALUE, SORT_ORDER, STATUS, DESCRIPTION) VALUES (27, 38, '30秒', '30000', 1, 0, null);
|
||||||
|
Loading…
Reference in New Issue
Block a user