From 2250a6234b12dee1b1b1e66987b52cf543c2afaf Mon Sep 17 00:00:00 2001 From: liulu Date: Wed, 11 Dec 2024 17:07:34 +0800 Subject: [PATCH] sdf api --- .../com/sunyard/chsm/sdf/BCSdfApiService.java | 372 +++++++++--------- .../chsm/sdf/adapter/BcSdfApiAdaptor.java | 30 ++ .../chsm/sdf/adapter/JnaSdfAdaptor.java | 66 ++++ .../chsm/sdf/adapter/SdfApiAdapter.java | 43 ++ .../com/sunyard/chsm/sdf/lib/SdfLibrary.java | 2 +- .../com/sunyard/chsm/sdf/model/EccPriKey.java | 2 +- .../sunyard/chsm/sdf/SingleSdfApiService.java | 166 ++++++++ .../chsm/pool/LoadBalancedSdfApiService.java | 16 +- 8 files changed, 503 insertions(+), 194 deletions(-) create mode 100644 chsm-web-manage/src/main/java/com/sunyard/chsm/sdf/SingleSdfApiService.java diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/BCSdfApiService.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/BCSdfApiService.java index 31075e1..1cc37c7 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/BCSdfApiService.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/BCSdfApiService.java @@ -1,186 +1,186 @@ -package com.sunyard.chsm.sdf; - - -import com.sunyard.chsm.enums.AlgMode; -import com.sunyard.chsm.enums.KeyAlg; -import com.sunyard.chsm.enums.KeyCategory; -import com.sunyard.chsm.enums.Padding; -import com.sunyard.chsm.sdf.context.AlgId; -import com.sunyard.chsm.sdf.model.EccKey; -import com.sunyard.chsm.sdf.util.LangUtils; -import com.sunyard.chsm.utils.gm.BCSM2Utils; -import com.sunyard.chsm.utils.gm.BCSM3Utils; -import com.sunyard.chsm.utils.gm.BCSM4Utils; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; -import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; -import org.bouncycastle.util.BigIntegers; -import org.springframework.stereotype.Service; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import java.security.InvalidKeyException; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SecureRandom; - - -/** - * 基于 BC 库的国密软算法实现 - * 当前实现类的接口返回的对称密钥和私钥认为是明文,在上层 Service 进行使用和存储时的加密和解密运算。 - *

- * 主密钥: - * - 生成。 软随机数。项目启动时不存在则自动生成。 - * - 存储。 存储在 SC_PARAM_CONF 表, KEY 为 mk 的字段,值为固定的 48 字节,以 HEX 格式 96 字节存储。 - * 前 16 字节为主密钥值,后 32 字节为主密钥值使用 SM3 计算的校验值。 - * - 同步。基于数据库进行导入、导出、和备份、恢复。多台应用服务器连接同一个数据库,无需同步。 - * - 使用。顶层密钥,用于保护其他存于数据的密钥。 - * - * @author liulu 、Cheney - * @since 2024/10/23 - */ -@Slf4j -@Service -public class BCSdfApiService extends AbstractSdfApiService { - - public BCSdfApiService() { - super(); - } - - @Override - public byte[] generateRandom(int len) { - byte[] res = new byte[len]; - new SecureRandom().nextBytes(res); - return res; - } - - - /** - * 生成对称算法密钥 - * - * @param alg 算法,只支持对称算法 - * @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。 - * 禁止传 null - * @return - */ - @Override - public byte[] genSymKey(KeyAlg alg, Integer keyLen) { - switch (alg) { - case SM4: { - if (null == keyLen || keyLen != BCSM4Utils.DEFAULT_KEY_SIZE) { - throw new IllegalArgumentException("Invalid key length: " + keyLen); - } - try { - return BCSM4Utils.generateKey(); - } catch (NoSuchAlgorithmException | NoSuchProviderException e) { - throw new RuntimeException("算法实现错误", e); - } - } - default: { - throw new IllegalArgumentException("Unsupported algorithm: " + alg); - } - } - } - - @Override - public byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { - return symCalc(Cipher.ENCRYPT_MODE, alg, mode, padding, key, data); - } - - @Override - public byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { - return new byte[0]; - } - - - @Override - public byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { - return symCalc(Cipher.DECRYPT_MODE, alg, mode, padding, key, data); - } - - @Override - public byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { - return new byte[0]; - } - - - /** - * 对称加解密的统一实现 - * - * @param alg 算法,只支持对称算法 - * @param key 密钥值,明文 - * @param data 加密时明文数据,解密时为密文数据 - */ - private byte[] symCalc(int cipherMode, KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { - if (alg.getCategory() != KeyCategory.SYM_KEY) { - throw new IllegalArgumentException("Must SYM_KEY, unsupported algorithm: " + alg); - } - - // 算法 - String algName = null; - if (alg == KeyAlg.SM4) { - algName = "SM4/"; - } else { - throw new IllegalArgumentException("Unsupported algorithm: " + alg); - } - - // 算法轮模式 - algName += mode.getCode() + "/"; - - // 填充模式 - algName += padding.getCode(); - - - Cipher cipher = null; - try { - cipher = BCSM4Utils.generateECBCipher(algName, cipherMode, key); - return cipher.doFinal(data); - } catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException e) { - throw new RuntimeException("算法执行错误", e); - } - } - - @SneakyThrows - @Override - public EccKey genKeyPairEcc() { - // 生成密钥对 - KeyPair keyPair = BCSM2Utils.generateKeyPair(); - BCECPublicKey pubKey = (BCECPublicKey) keyPair.getPublic(); - BCECPrivateKey priKey = (BCECPrivateKey) keyPair.getPrivate(); - byte[] x = pubKey.getQ().getXCoord().getEncoded(); - byte[] y = pubKey.getQ().getYCoord().getEncoded(); - byte[] d = BigIntegers.asUnsignedByteArray(32, priKey.getD()); - return new EccKey(LangUtils.merge(x, y), d); - } - - - @Override - public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) { - return new byte[0]; - } - - @Override - public byte[] hmac(byte[] key, byte[] srcData) { - return BCSM3Utils.hmac(key, srcData); - } - - @Override - public byte[] hash(byte[] pucData) { - return BCSM3Utils.hash(pucData); - } - - @Override - public byte[] encryptByTMK(byte[] data) { - return data; - } - - @Override - public byte[] decryptByTMK(byte[] data) { - return data; - } - -} +//package com.sunyard.chsm.sdf; +// +// +//import com.sunyard.chsm.enums.AlgMode; +//import com.sunyard.chsm.enums.KeyAlg; +//import com.sunyard.chsm.enums.KeyCategory; +//import com.sunyard.chsm.enums.Padding; +//import com.sunyard.chsm.sdf.context.AlgId; +//import com.sunyard.chsm.sdf.model.EccKey; +//import com.sunyard.chsm.sdf.util.LangUtils; +//import com.sunyard.chsm.utils.gm.BCSM2Utils; +//import com.sunyard.chsm.utils.gm.BCSM3Utils; +//import com.sunyard.chsm.utils.gm.BCSM4Utils; +//import lombok.SneakyThrows; +//import lombok.extern.slf4j.Slf4j; +//import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; +//import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; +//import org.bouncycastle.util.BigIntegers; +//import org.springframework.stereotype.Service; +// +//import javax.crypto.BadPaddingException; +//import javax.crypto.Cipher; +//import javax.crypto.IllegalBlockSizeException; +//import javax.crypto.NoSuchPaddingException; +//import java.security.InvalidKeyException; +//import java.security.KeyPair; +//import java.security.NoSuchAlgorithmException; +//import java.security.NoSuchProviderException; +//import java.security.SecureRandom; +// +// +///** +// * 基于 BC 库的国密软算法实现 +// * 当前实现类的接口返回的对称密钥和私钥认为是明文,在上层 Service 进行使用和存储时的加密和解密运算。 +// *

+// * 主密钥: +// * - 生成。 软随机数。项目启动时不存在则自动生成。 +// * - 存储。 存储在 SC_PARAM_CONF 表, KEY 为 mk 的字段,值为固定的 48 字节,以 HEX 格式 96 字节存储。 +// * 前 16 字节为主密钥值,后 32 字节为主密钥值使用 SM3 计算的校验值。 +// * - 同步。基于数据库进行导入、导出、和备份、恢复。多台应用服务器连接同一个数据库,无需同步。 +// * - 使用。顶层密钥,用于保护其他存于数据的密钥。 +// * +// * @author liulu 、Cheney +// * @since 2024/10/23 +// */ +//@Slf4j +//@Service +//public class BCSdfApiService extends AbstractSdfApiService { +// +// public BCSdfApiService() { +// super(); +// } +// +// @Override +// public byte[] generateRandom(int len) { +// byte[] res = new byte[len]; +// new SecureRandom().nextBytes(res); +// return res; +// } +// +// +// /** +// * 生成对称算法密钥 +// * +// * @param alg 算法,只支持对称算法 +// * @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。 +// * 禁止传 null +// * @return +// */ +// @Override +// public byte[] genSymKey(KeyAlg alg, Integer keyLen) { +// switch (alg) { +// case SM4: { +// if (null == keyLen || keyLen != BCSM4Utils.DEFAULT_KEY_SIZE) { +// throw new IllegalArgumentException("Invalid key length: " + keyLen); +// } +// try { +// return BCSM4Utils.generateKey(); +// } catch (NoSuchAlgorithmException | NoSuchProviderException e) { +// throw new RuntimeException("算法实现错误", e); +// } +// } +// default: { +// throw new IllegalArgumentException("Unsupported algorithm: " + alg); +// } +// } +// } +// +// @Override +// public byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { +// return symCalc(Cipher.ENCRYPT_MODE, alg, mode, padding, key, data); +// } +// +// @Override +// public byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { +// return new byte[0]; +// } +// +// +// @Override +// public byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { +// return symCalc(Cipher.DECRYPT_MODE, alg, mode, padding, key, data); +// } +// +// @Override +// public byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { +// return new byte[0]; +// } +// +// +// /** +// * 对称加解密的统一实现 +// * +// * @param alg 算法,只支持对称算法 +// * @param key 密钥值,明文 +// * @param data 加密时明文数据,解密时为密文数据 +// */ +// private byte[] symCalc(int cipherMode, KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { +// if (alg.getCategory() != KeyCategory.SYM_KEY) { +// throw new IllegalArgumentException("Must SYM_KEY, unsupported algorithm: " + alg); +// } +// +// // 算法 +// String algName = null; +// if (alg == KeyAlg.SM4) { +// algName = "SM4/"; +// } else { +// throw new IllegalArgumentException("Unsupported algorithm: " + alg); +// } +// +// // 算法轮模式 +// algName += mode.getCode() + "/"; +// +// // 填充模式 +// algName += padding.getCode(); +// +// +// Cipher cipher = null; +// try { +// cipher = BCSM4Utils.generateECBCipher(algName, cipherMode, key); +// return cipher.doFinal(data); +// } catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException e) { +// throw new RuntimeException("算法执行错误", e); +// } +// } +// +// @SneakyThrows +// @Override +// public EccKey genKeyPairEcc() { +// // 生成密钥对 +// KeyPair keyPair = BCSM2Utils.generateKeyPair(); +// BCECPublicKey pubKey = (BCECPublicKey) keyPair.getPublic(); +// BCECPrivateKey priKey = (BCECPrivateKey) keyPair.getPrivate(); +// byte[] x = pubKey.getQ().getXCoord().getEncoded(); +// byte[] y = pubKey.getQ().getYCoord().getEncoded(); +// byte[] d = BigIntegers.asUnsignedByteArray(32, priKey.getD()); +// return new EccKey(LangUtils.merge(x, y), d); +// } +// +// +// @Override +// public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) { +// return new byte[0]; +// } +// +// @Override +// public byte[] hmac(byte[] key, byte[] srcData) { +// return BCSM3Utils.hmac(key, srcData); +// } +// +// @Override +// public byte[] hash(byte[] pucData) { +// return BCSM3Utils.hash(pucData); +// } +// +// @Override +// public byte[] encryptByTMK(byte[] data) { +// return data; +// } +// +// @Override +// public byte[] decryptByTMK(byte[] data) { +// return data; +// } +// +//} diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java index ea7e90d..c2f4058 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java @@ -213,4 +213,34 @@ public class BcSdfApiAdaptor implements SdfApiAdapter { Assert.notNull(key, "密钥句柄不存在"); return key; } + + @Override + public byte[] calculateMAC(String sessionHandle, String keyHandle, AlgId uiAlg, byte[] pucIv, byte[] pucData) { + return new byte[0]; + } + + @Override + public byte[] calculateMAC(String sessionHandle, byte[] symKey, AlgId uiAlg, byte[] pucIv, byte[] pucData) { + return new byte[0]; + } + + @Override + public int hashInit(String sessionHandle, AlgId alg, EccPubKey pucPublicKey, byte[] pucID) { + return 0; + } + + @Override + public int hashUpdate(String sessionHandle, byte[] pucData) { + return 0; + } + + @Override + public byte[] hashFinish(String sessionHandle) { + return new byte[0]; + } + + @Override + public byte[] hashOperation(String sessionHandle, AlgId alg, EccPubKey pucPublicKey, byte[] pucID, byte[] pucData) { + return new byte[0]; + } } 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 f21e761..bd1ea49 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 @@ -257,4 +257,70 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter { sdfLibrary.SDF_DestroyKey(hSessionHandle, hKeyHandle); return pucData; } + + @Override + public byte[] calculateMAC(String sessionHandle, String keyHandle, AlgId uiAlg, byte[] pucIv, byte[] pucData) { + Pointer hSessionHandle = getSessionHandle(sessionHandle); + Pointer hKeyHandle = getKeyHandle(keyHandle); + + int uiMacLength = pucData.length; + byte[] pucMac = new byte[uiMacLength]; + + IntByReference puiLength = new IntByReference(); + sdfLibrary.SDF_CalculateMAC(hSessionHandle, hKeyHandle, getAlgId(uiAlg), pucIv, pucData, uiMacLength, pucMac, puiLength); + + return pucMac; + } + + @Override + public byte[] calculateMAC(String sessionHandle, byte[] symKey, AlgId uiAlg, byte[] pucIv, byte[] pucData) { + PointerByReference phKeyHandle = new PointerByReference(); + Pointer hSessionHandle = getSessionHandle(sessionHandle); + int length = symKey.length; + // 导入会话密钥 + sdfLibrary.SDF_ImportKey(hSessionHandle, symKey, length, phKeyHandle); + + int uiMacLength = pucData.length; + byte[] pucMac = new byte[uiMacLength]; + Pointer hKeyHandle = phKeyHandle.getValue(); + IntByReference puiLength = new IntByReference(); + sdfLibrary.SDF_CalculateMAC(hSessionHandle, hKeyHandle, getAlgId(uiAlg), pucIv, pucData, uiMacLength, pucMac, puiLength); + // 销毁会话密钥 + sdfLibrary.SDF_DestroyKey(hSessionHandle, hKeyHandle); + return pucMac; + } + + @Override + public int hashInit(String sessionHandle, AlgId alg, EccPubKey pucPublicKey, byte[] pucID) { + Pointer hSessionHandle = getSessionHandle(sessionHandle); + byte[] pubPub = pucPublicKey == null ? null : pucPublicKey.toSdfData(); + return sdfLibrary.SDF_HashInit(hSessionHandle, getAlgId(AlgId.SGD_SM3), pubPub, pucID, pucID.length); + } + + @Override + public int hashUpdate(String sessionHandle, byte[] pucData) { + Pointer hSessionHandle = getSessionHandle(sessionHandle); + return sdfLibrary.SDF_HashUpdate(hSessionHandle, pucData, pucData.length); + } + + @Override + public byte[] hashFinish(String sessionHandle) { + Pointer hSessionHandle = getSessionHandle(sessionHandle); + byte[] pucHash = new byte[32]; + IntByReference puiLength = new IntByReference(); + sdfLibrary.SDF_HashFinal(hSessionHandle, pucHash, puiLength); + return pucHash; + } + + @Override + public byte[] hashOperation(String sessionHandle, AlgId alg, EccPubKey pucPublicKey, byte[] pucID, byte[] pucData) { + Pointer hSessionHandle = getSessionHandle(sessionHandle); + byte[] pubPub = pucPublicKey == null ? null : pucPublicKey.toSdfData(); + sdfLibrary.SDF_HashInit(hSessionHandle, getAlgId(AlgId.SGD_SM3), pubPub, pucID, pucID.length); + sdfLibrary.SDF_HashUpdate(hSessionHandle, pucData, pucData.length); + byte[] pucHash = new byte[32]; + IntByReference puiLength = new IntByReference(); + sdfLibrary.SDF_HashFinal(hSessionHandle, pucHash, puiLength); + return pucHash; + } } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java index c17c2f0..2f49faf 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java @@ -135,4 +135,47 @@ public interface SdfApiAdapter { byte[] symDecrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucEncData); byte[] externalSymDecrypt(String sessionHandle, byte[] symKey, AlgId alg, byte[] pucIv, byte[] pucEncData); + + /** + * @param sessionHandle 与设备建立的会话句柄 + * @param keyHandle 指定的密钥句柄 + * @param uiAlg 算法标识,指定MAC算法 SGD_SMS4_MAC + * @param pucIv IV数据 + * @param pucData 数据明文 + * @return MAC值 + */ + byte[] calculateMAC(String sessionHandle, String keyHandle, AlgId uiAlg, byte[] pucIv, byte[] pucData); + byte[] calculateMAC(String sessionHandle, byte[] symKey, AlgId uiAlg, byte[] pucIv, byte[] pucData); + + /** + * 杂凑运算初始化 + * + * @param sessionHandle 与设备建立的会话句柄 + * @param alg 当前杂凑算法标识 SGD_SM3 + * @param pucPublicKey 签名者公钥,当uiAlgID为SGD_SM3时有效 + * @param pucID 签名者的ID值,当uiAlgID为SGD_SM3时有效 + * @return 0 成功; 非0 失败,返回错误代码 + */ + int hashInit(String sessionHandle, AlgId alg, EccPubKey pucPublicKey, byte[] pucID); + + /** + * 多包杂凑运算 + * + * @param sessionHandle sessionHandle + * @param pucData 数据明文 + * @return 0 成功; 非0 失败,返回错误代码 + */ + int hashUpdate(String sessionHandle, byte[] pucData); + + /** + * 杂凑运算结束 + * + * @param sessionHandle 与设备建立的会话句柄 + * @return 杂凑数据 + */ + byte[] hashFinish(String sessionHandle); + + + byte[] hashOperation(String sessionHandle, AlgId alg, EccPubKey pucPublicKey, byte[] pucID, byte[] pucData); + } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/lib/SdfLibrary.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/lib/SdfLibrary.java index 88d1a05..c3c33ff 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/lib/SdfLibrary.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/lib/SdfLibrary.java @@ -283,7 +283,7 @@ public interface SdfLibrary extends Library { * @param pucIDlength 签名者ID的长度 * @return int 响应码 */ - int SDF_HashInit(Pointer phSessionHandle, int uiAlgID, byte[] pucPublicKey, String pucID, int pucIDlength); + int SDF_HashInit(Pointer phSessionHandle, int uiAlgID, byte[] pucPublicKey, byte[] pucID, int pucIDlength); /** * 多包杂凑运算 diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccPriKey.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccPriKey.java index 78c94b3..8614e4e 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccPriKey.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccPriKey.java @@ -24,7 +24,7 @@ public class EccPriKey { public static EccPriKey fromBytes(byte[] priKey) { Assert.notNull(priKey, "公钥数据不能为null"); - if (Objects.equals(priKey.length, 132)) { + if (Objects.equals(priKey.length, 68)) { // 00010000 priKey = Arrays.copyOfRange(priKey, 4, priKey.length); } diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/sdf/SingleSdfApiService.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/sdf/SingleSdfApiService.java new file mode 100644 index 0000000..c40f1da --- /dev/null +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/sdf/SingleSdfApiService.java @@ -0,0 +1,166 @@ +package com.sunyard.chsm.sdf; + +import com.sunyard.chsm.enums.AlgMode; +import com.sunyard.chsm.enums.DeviceTmkStatus; +import com.sunyard.chsm.enums.KeyAlg; +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.BcSdfApiAdaptor; +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.service.TmkService; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Service; + +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * @author liulu + * @since 2024/12/11 + */ +@Service +@RequiredArgsConstructor +public class SingleSdfApiService implements SdfApiService, InitializingBean { + + private String tmkHandle; + private String sessionHandle; + private SdfApiAdapter sdfApiAdapter; + private final TmkService tmkService; + private final SpDeviceMapper spDeviceMapper; + + @Override + public byte[] generateRandom(int len) { + return new byte[0]; + } + + @Override + public byte[] genSymKey(KeyAlg alg, Integer keyLen) { + return new byte[0]; + } + + @Override + public byte[] genSymKey(KeyAlg alg) { + return new byte[0]; + } + + @Override + public byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { + return new byte[0]; + } + + @Override + public byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data) { + return new byte[0]; + } + + @Override + public byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { + return new byte[0]; + } + + @Override + public byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { + return new byte[0]; + } + + @Override + public byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data) { + return new byte[0]; + } + + @Override + public byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { + return new byte[0]; + } + + @Override + public EccKey genKeyPairEcc() { + return null; + } + + @Override + public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) { + return new byte[0]; + } + + @Override + public byte[] hmac(byte[] key, byte[] srcData) { + return new byte[0]; + } + + @Override + public byte[] hash(byte[] pucData) { + return new byte[0]; + } + + @Override + public byte[] encryptByTMK(byte[] data) { + return new byte[0]; + } + + @Override + public byte[] decryptByTMK(byte[] data) { + return new byte[0]; + } + + 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(); + String hd = sdfApiAdapter.openDevice(); + this.sessionHandle = sdfApiAdapter.openSession(hd); + 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) { + if (sdfApiAdapter instanceof BcSdfApiAdaptor) { + changeDevice(tmkInit); + return; + } + if (tmkInit && StringUtils.isEmpty(tmkHandle)) { + changeDevice(tmkInit); + return; + } + try { + DeviceInfo deviceInfo = sdfApiAdapter.getDeviceInfo(sessionHandle); + } catch (Exception ex) { + changeDevice(tmkInit); + } + } else { + changeDevice(tmkInit); + } + }, 0L, 5L, TimeUnit.MINUTES); + } +} diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java index 272730f..1807c31 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java @@ -7,7 +7,9 @@ import com.sunyard.chsm.sdf.SdfApiService; import com.sunyard.chsm.sdf.context.AlgId; import com.sunyard.chsm.sdf.model.EccKey; import com.sunyard.chsm.sdf.util.PaddingUtil; +import com.sunyard.chsm.utils.gm.BCSM3Utils; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.function.Function; @@ -17,9 +19,9 @@ import java.util.function.Function; * @since 2024/12/10 */ @Slf4j +@Service public class LoadBalancedSdfApiService implements SdfApiService { - @Resource private DeviceManager deviceManager; @@ -100,26 +102,28 @@ public class LoadBalancedSdfApiService implements SdfApiService { @Override public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) { - return new byte[0]; + return apply(s -> s.getSdfApiAdapter().calculateMAC(s.getSessionHandle(), symKey, AlgId.SGD_SM4_MAC, pucIv, pucData)); } @Override public byte[] hmac(byte[] key, byte[] srcData) { - return new byte[0]; + return BCSM3Utils.hmac(key, srcData); } @Override public byte[] hash(byte[] pucData) { - return new byte[0]; + return apply(s -> s.getSdfApiAdapter().hashOperation(s.getSessionHandle(), AlgId.SGD_SM3, null, null, pucData)); } @Override public byte[] encryptByTMK(byte[] data) { - return new byte[0]; + byte[] pad = PaddingUtil.PKCS7Unpadding(data); + return apply(s -> s.getSdfApiAdapter().symEncrypt(s.getSessionHandle(), s.getKeyHandle(), AlgId.SGD_SM4_CBC, new byte[8], pad)); } @Override public byte[] decryptByTMK(byte[] data) { - return new byte[0]; + byte[] decrypt = apply(s -> s.getSdfApiAdapter().symDecrypt(s.getSessionHandle(), s.getKeyHandle(), AlgId.SGD_SM4_CBC, new byte[8], data)); + return PaddingUtil.PKCS7Unpadding(decrypt); } }