主密钥校验值

This commit is contained in:
liulu
2025-01-03 11:38:25 +08:00
parent 8be178317a
commit ad679f48fd
6 changed files with 182 additions and 6 deletions
@@ -13,6 +13,7 @@ public interface ParamConfKeyConstant {
String IP_WHITELIST_SWITCH = "ipWhitelistSwitch";
String TMK_INIT = "tmk_init";
String TMK_CHECK_VALUE = "tmk_check_value";
String ENABLE_SOFT_DEVICE = "enable_soft_device";
@@ -17,6 +17,9 @@ public class TmkStatus {
* 主密钥是否初始化
*/
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.EccCipher;
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.gm.BCECUtils;
import com.sunyard.chsm.utils.gm.BCSM2Utils;
import com.sunyard.chsm.utils.gm.BCSM3Utils;
import lombok.RequiredArgsConstructor;
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.springframework.stereotype.Component;
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);
Assert.isTrue(Arrays.equals(rk, prk), "密码机加解密异常");
byte[] hash = BCSM3Utils.hash(rk);
sdfApi.destroyKey(hs, hk);
sdfApi.closeSession(hs);
sdfApi.closeDevice(hd);
@@ -72,7 +81,7 @@ public class TmkService {
up.setTmkStatus(DeviceTmkStatus.finished.name());
spDeviceMapper.updateById(up);
}
updateTmkInit(true);
updateTmkInit(true, hash);
}
@@ -82,6 +91,10 @@ public class TmkService {
if (init) {
status.setHasDevice(true);
status.setTmkInit(true);
ParamConf paramConf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_CHECK_VALUE);
if (paramConf != null) {
status.setCheckValue(paramConf.getValue());
}
return status;
}
status.setTmkInit(false);
@@ -90,6 +103,88 @@ public class TmkService {
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) {
@@ -209,6 +304,7 @@ public class TmkService {
}
if (isEnableSoftDevice()) {
device = new Device();
device.setId(0L);
device.setManufacturerModel(BouncyCastleProvider.PROVIDER_NAME);
device.setEncKeyIdx(1);
device.setServiceIp("127.0.0.1");
@@ -241,7 +337,7 @@ public class TmkService {
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);
if (conf == null) {
conf = new ParamConf();
@@ -253,6 +349,18 @@ public class TmkService {
conf.setValue(String.valueOf(value));
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() {
@@ -61,7 +61,7 @@ import java.util.Arrays;
/**
* 这个工具类的方法,也适用于其他基于BC库的ECC算法
*/
public class BCECUtils {
public class BCECUtils extends GMBaseUtil {
private static final String ALGO_NAME_EC = "EC";
private static final String PEM_STRING_PUBLIC = "PUBLIC KEY";
private static final String PEM_STRING_ECPRIVATEKEY = "EC PRIVATE KEY";