237 lines
9.2 KiB
Java
237 lines
9.2 KiB
Java
package com.sunyard.chsm.sdf;
|
|
|
|
import com.sunyard.chsm.enums.DeviceTmkStatus;
|
|
import com.sunyard.chsm.enums.Padding;
|
|
import com.sunyard.chsm.mapper.SpDeviceMapper;
|
|
import com.sunyard.chsm.model.dto.DeviceCheckRes;
|
|
import com.sunyard.chsm.model.entity.Device;
|
|
import com.sunyard.chsm.sdf.adapter.SdfApiAdapter;
|
|
import com.sunyard.chsm.sdf.adapter.SdfApiAdapterFactory;
|
|
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.EccKey;
|
|
import com.sunyard.chsm.sdf.model.EccPriKey;
|
|
import com.sunyard.chsm.sdf.model.EccPubKey;
|
|
import com.sunyard.chsm.sdf.model.EccSignature;
|
|
import com.sunyard.chsm.sdf.util.PaddingUtil;
|
|
import com.sunyard.chsm.service.TmkService;
|
|
import com.sunyard.chsm.utils.gm.BCECUtils;
|
|
import com.sunyard.chsm.utils.gm.BCSM3Utils;
|
|
import com.sunyard.chsm.utils.gm.SM2PreprocessSigner;
|
|
import lombok.NoArgsConstructor;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.bouncycastle.crypto.CipherParameters;
|
|
import org.bouncycastle.crypto.params.ParametersWithID;
|
|
import org.springframework.beans.factory.InitializingBean;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.util.Assert;
|
|
|
|
import javax.annotation.Resource;
|
|
import java.util.Objects;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
/**
|
|
* @author liulu
|
|
* @since 2024/12/11
|
|
*/
|
|
@Service
|
|
@NoArgsConstructor
|
|
public class SingleSdfApiService implements SdfApiService, InitializingBean {
|
|
|
|
private String tmkHandle;
|
|
private String deviceHandle;
|
|
private String sessionHandle;
|
|
private SdfApiAdapter sdfApiAdapter;
|
|
|
|
@Resource
|
|
public TmkService tmkService;
|
|
@Resource
|
|
private SpDeviceMapper spDeviceMapper;
|
|
|
|
public SingleSdfApiService(SdfApiAdapter sdfApiAdapter) {
|
|
this.sdfApiAdapter = sdfApiAdapter;
|
|
this.deviceHandle = sdfApiAdapter.openDevice();
|
|
this.sessionHandle = sdfApiAdapter.openSession(deviceHandle);
|
|
}
|
|
|
|
@Override
|
|
public byte[] generateRandom(int len) {
|
|
checkStatus();
|
|
return sdfApiAdapter.generateRandom(sessionHandle, len);
|
|
}
|
|
|
|
@Override
|
|
public byte[] symEncrypt(AlgId alg, Padding padding, byte[] key, byte[] iv, byte[] data) {
|
|
checkStatus();
|
|
byte[] pad = PaddingUtil.padding(padding, data);
|
|
String hk = sdfApiAdapter.importKey(sessionHandle, key);
|
|
byte[] encrypt = sdfApiAdapter.symEncrypt(sessionHandle, hk, alg, iv, pad);
|
|
sdfApiAdapter.destroyKey(sessionHandle, hk);
|
|
return encrypt;
|
|
}
|
|
|
|
@Override
|
|
public byte[] symDecrypt(AlgId alg, Padding padding, byte[] key, byte[] iv, byte[] data) {
|
|
checkStatus();
|
|
String hk = sdfApiAdapter.importKey(sessionHandle, key);
|
|
byte[] decrypt = sdfApiAdapter.symDecrypt(sessionHandle, hk, alg, iv, data);
|
|
sdfApiAdapter.destroyKey(sessionHandle, hk);
|
|
return PaddingUtil.unpadding(padding, decrypt);
|
|
}
|
|
|
|
@Override
|
|
public EccKey genKeyPairEcc() {
|
|
checkStatus();
|
|
return sdfApiAdapter.generateKeyPairECC(sessionHandle, AlgId.SGD_SM2_1);
|
|
}
|
|
|
|
@Override
|
|
public EccSignature externalSignECC(byte[] privateKey, byte[] pucData) {
|
|
return externalSignWithIdECC(privateKey, pucData, new byte[0]);
|
|
}
|
|
|
|
@Override
|
|
public EccSignature externalSignWithIdECC(byte[] privateKey, byte[] pucData, byte[] userId) {
|
|
EccPriKey sdfEccPrivateKey = EccPriKey.fromBytes(privateKey);
|
|
SM2PreprocessSigner signer = new SM2PreprocessSigner();
|
|
CipherParameters keyParameters = BCECUtils.createECPrivateKeyParameters(sdfEccPrivateKey.getD());
|
|
if (userId != null && userId.length > 0) {
|
|
keyParameters = new ParametersWithID(keyParameters, userId);
|
|
}
|
|
signer.init(true, keyParameters);
|
|
byte[] preHash = signer.preprocess(pucData);
|
|
return sdfApiAdapter.externalSignECC(sessionHandle, sdfEccPrivateKey, preHash);
|
|
}
|
|
|
|
@Override
|
|
public boolean externalVerifyWithIdECC(byte[] publicKey, byte[] pubData, byte[] signData, byte[] userId) {
|
|
EccPubKey eccPublicKey = EccPubKey.fromBytes(publicKey);
|
|
CipherParameters parameters = BCECUtils.createECPublicKeyParameters(eccPublicKey.getX(), eccPublicKey.getY());
|
|
if (userId != null && userId.length > 0) {
|
|
parameters = new ParametersWithID(parameters, userId);
|
|
}
|
|
SM2PreprocessSigner signer = new SM2PreprocessSigner();
|
|
signer.init(false, parameters);
|
|
byte[] preHash = signer.preprocess(pubData);
|
|
EccSignature eccSignature = EccSignature.fromBytes(signData);
|
|
|
|
return sdfApiAdapter.externalVerifyECC(sessionHandle, eccPublicKey, preHash, eccSignature);
|
|
}
|
|
|
|
@Override
|
|
public boolean externalVerifyECC(byte[] publicKey, byte[] pubData, byte[] signData) {
|
|
return externalVerifyWithIdECC(publicKey, pubData, signData, new byte[0]);
|
|
}
|
|
|
|
@Override
|
|
public EccCipher externalEncryptECC(byte[] publicKey, byte[] pucData) {
|
|
EccPubKey eccPublicKey = EccPubKey.fromBytes(publicKey);
|
|
return sdfApiAdapter.externalEncryptECC(sessionHandle, eccPublicKey, pucData);
|
|
}
|
|
|
|
@Override
|
|
public byte[] externalDecryptECC(byte[] privateKey, byte[] encData) {
|
|
EccPriKey sdfEccPrivateKey = EccPriKey.fromBytes(privateKey);
|
|
EccCipher eccCipher = EccCipher.fromBytes(encData);
|
|
return sdfApiAdapter.externalDecryptECC(sessionHandle, sdfEccPrivateKey, eccCipher);
|
|
}
|
|
|
|
@Override
|
|
public byte[] calculateMAC(AlgId algId, Padding padding, byte[] symKey, byte[] pucIv, byte[] pucData) {
|
|
checkStatus();
|
|
byte[] pad = PaddingUtil.padding(padding, pucData);
|
|
String hk = sdfApiAdapter.importKey(sessionHandle, symKey);
|
|
byte[] mac = sdfApiAdapter.calculateMAC(sessionHandle, hk, algId, pucIv, pad);
|
|
sdfApiAdapter.destroyKey(sessionHandle, hk);
|
|
return mac;
|
|
}
|
|
|
|
@Override
|
|
public byte[] hmac(byte[] key, byte[] srcData) {
|
|
return BCSM3Utils.hmac(key, srcData);
|
|
}
|
|
|
|
@Override
|
|
public byte[] hash(byte[] pucData) {
|
|
checkStatus();
|
|
String newSession = sdfApiAdapter.openSession(deviceHandle);
|
|
sdfApiAdapter.hashInit(newSession, AlgId.SGD_SM3, null, null);
|
|
sdfApiAdapter.hashUpdate(newSession, pucData);
|
|
byte[] hash = sdfApiAdapter.hashFinish(newSession);
|
|
sdfApiAdapter.closeSession(newSession);
|
|
return hash;
|
|
}
|
|
|
|
@Override
|
|
public byte[] encryptByTMK(byte[] data) {
|
|
checkKey();
|
|
byte[] pad = PaddingUtil.PKCS7Padding(data);
|
|
return sdfApiAdapter.symEncrypt(sessionHandle, tmkHandle, AlgId.SGD_SM4_CBC, new byte[8], pad);
|
|
}
|
|
|
|
@Override
|
|
public byte[] decryptByTMK(byte[] data) {
|
|
checkKey();
|
|
byte[] decrypt = sdfApiAdapter.symDecrypt(sessionHandle, tmkHandle, AlgId.SGD_SM4_CBC, new byte[8], data);
|
|
return PaddingUtil.PKCS7Unpadding(decrypt);
|
|
}
|
|
|
|
private void checkStatus() {
|
|
Assert.notNull(sdfApiAdapter, "没有可用设备");
|
|
}
|
|
|
|
private void checkKey() {
|
|
checkStatus();
|
|
Assert.hasText(tmkHandle, "没有可用的主密钥设备");
|
|
}
|
|
|
|
private void changeDevice(boolean tmkInit) {
|
|
DeviceTmkStatus status = tmkInit ? DeviceTmkStatus.finished : DeviceTmkStatus.available;
|
|
Device device = spDeviceMapper.selectOneByStatus(status);
|
|
if (Objects.nonNull(device)) {
|
|
DeviceCheckRes checkRes = tmkService.checkDevice(device);
|
|
if (!checkRes.isHasError()) {
|
|
this.sdfApiAdapter = checkRes.getSdfApiAdapter();
|
|
this.deviceHandle = sdfApiAdapter.openDevice();
|
|
this.sessionHandle = sdfApiAdapter.openSession(deviceHandle);
|
|
if (tmkInit) {
|
|
sdfApiAdapter.getPrivateKeyAccessRight(sessionHandle, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
|
this.tmkHandle = sdfApiAdapter.importKeyWithISKECC(sessionHandle, device.getEncKeyIdx(), EccCipher.fromHex(device.getEncTmk()));
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
if (tmkService.isEnableSoftDevice()) {
|
|
this.sdfApiAdapter = SdfApiAdapterFactory.getBcAdapter();
|
|
this.sessionHandle = sdfApiAdapter.openSession("");
|
|
if (tmkInit) {
|
|
byte[] encTmk = tmkService.getSoftDeviceEncTmk();
|
|
this.tmkHandle = sdfApiAdapter.importKeyWithISKECC(sessionHandle, device.getEncKeyIdx(), EccCipher.fromBytes(encTmk));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void afterPropertiesSet() throws Exception {
|
|
Executors.newSingleThreadScheduledExecutor()
|
|
.scheduleWithFixedDelay(() -> {
|
|
boolean tmkInit = tmkService.isTmkInit();
|
|
if (sdfApiAdapter == null) {
|
|
changeDevice(tmkInit);
|
|
return;
|
|
}
|
|
if (tmkInit && StringUtils.isEmpty(tmkHandle)) {
|
|
changeDevice(tmkInit);
|
|
return;
|
|
}
|
|
try {
|
|
DeviceInfo deviceInfo = sdfApiAdapter.getDeviceInfo(sessionHandle);
|
|
} catch (Exception ex) {
|
|
changeDevice(tmkInit);
|
|
}
|
|
}, 0L, 5L, TimeUnit.MINUTES);
|
|
}
|
|
}
|