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); } }