diff --git a/chsm-common/pom.xml b/chsm-common/pom.xml
index 62d71f0..748f20d 100644
--- a/chsm-common/pom.xml
+++ b/chsm-common/pom.xml
@@ -20,6 +20,11 @@
+
+ com.sunyard.chsm
+ chsm-params
+ ${project.version}
+
org.springframework.boot
spring-boot-starter-web
@@ -66,5 +71,4 @@
-
\ No newline at end of file
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/SdfApiService.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/SdfApiService.java
index f859b45..0ae4b07 100644
--- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/SdfApiService.java
+++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/SdfApiService.java
@@ -1,6 +1,7 @@
package com.sunyard.chsm.sdf;
+import com.sunyard.chsm.enums.Padding;
import com.sunyard.chsm.sdf.context.AlgId;
import com.sunyard.chsm.sdf.model.EccCipher;
import com.sunyard.chsm.sdf.model.EccKey;
@@ -40,6 +41,7 @@ public interface SdfApiService {
* 对称加密
*
* @param alg 算法,只支持对称算法
+ * @param padding
* @param key 密钥值,明文
* @param data 原始数据
*/
@@ -47,22 +49,22 @@ public interface SdfApiService {
//
// byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data);
- byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data);
+ byte[] symEncrypt(AlgId alg, Padding padding, byte[] key, byte[] iv, byte[] data);
/**
* 对称解密
*
- * @param alg 算法,只支持对称算法
- * @param key 密钥值,明文
* @param mode 轮模式
+ * @param alg 算法,只支持对称算法
* @param padding 填充模式
+ * @param key 密钥值,明文
* @param data 密文数据
*/
// byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data);
//
// byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data);
- byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data);
+ byte[] symDecrypt(AlgId alg, Padding padding, byte[] key, byte[] iv, byte[] data);
/**
@@ -119,12 +121,14 @@ public interface SdfApiService {
/**
* 计算MAC
*
+ * @param algId algId
+ * @param padding padding
* @param symKey 用户指定的密钥
* @param pucIv 缓冲区指针,用于存放输入和返回的IV数据
* @param pucData 缓冲区指针,用于存放输入的数据明文
* @return pucEncData 返回MAC值 | puiLength 返回MAC值长度
*/
- byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData);
+ byte[] calculateMAC(AlgId algId, Padding padding, byte[] symKey, byte[] pucIv, byte[] pucData);
byte[] hmac(byte[] key, byte[] srcData);
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/util/PaddingUtil.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/util/PaddingUtil.java
index 7a71309..e8da295 100644
--- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/util/PaddingUtil.java
+++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/util/PaddingUtil.java
@@ -1,10 +1,38 @@
package com.sunyard.chsm.sdf.util;
+import com.sunyard.chsm.enums.Padding;
+
/**
* @author liulu
*/
public abstract class PaddingUtil {
+
+ public static byte[] padding(Padding padding, byte[] data) {
+ switch (padding) {
+ case NOPadding:
+ return data;
+ case PCKS5Padding:
+ return PKCS5Padding(data);
+ case PCKS7Padding:
+ return PKCS7Padding(data);
+ }
+ return null;
+ }
+
+ public static byte[] unpadding(Padding padding, byte[] data) {
+ switch (padding) {
+ case NOPadding:
+ return data;
+ case PCKS5Padding:
+ return PKCS5Unpadding(data);
+ case PCKS7Padding:
+ return PKCS7Unpadding(data);
+ }
+ return null;
+ }
+
+
public static byte[] PKCS7Padding(byte[] content, int blockSize) {
if (content == null || blockSize < 8)
throw new IllegalStateException("parameter error");
@@ -22,7 +50,7 @@ public abstract class PaddingUtil {
return padded;
}
- public static byte[] PKCS7Padding(byte[] content) {
+ public static byte[] PKCS7Padding(byte[] content) {
try {
return PKCS7Padding(content, 16);
} catch (Exception e) {
@@ -34,10 +62,9 @@ public abstract class PaddingUtil {
return PKCS7Padding(content, 8);
}
- public static byte[] PKCS7Unpadding(byte[] content, int blockSize)
- throws Exception {
+ public static byte[] PKCS7Unpadding(byte[] content, int blockSize) {
if (blockSize < 8 || content == null || content.length % blockSize != 0)
- throw new Exception("parameter error");
+ throw new IllegalStateException("parameter error");
return PKCS7Unpadding(content);
}
@@ -57,9 +84,8 @@ public abstract class PaddingUtil {
return unpadded;
}
- public static byte[] PKCS5Unpadding(byte[] content) throws Exception {
+ public static byte[] PKCS5Unpadding(byte[] content) {
return PKCS7Unpadding(content, 8);
}
-
}
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/enums/AlgMode.java b/chsm-params/src/main/java/com/sunyard/chsm/enums/AlgMode.java
similarity index 94%
rename from chsm-common/src/main/java/com/sunyard/chsm/enums/AlgMode.java
rename to chsm-params/src/main/java/com/sunyard/chsm/enums/AlgMode.java
index e0bda2e..0a88630 100644
--- a/chsm-common/src/main/java/com/sunyard/chsm/enums/AlgMode.java
+++ b/chsm-params/src/main/java/com/sunyard/chsm/enums/AlgMode.java
@@ -1,36 +1,36 @@
-package com.sunyard.chsm.enums;
-
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-import java.util.Objects;
-
-
-/**
- * 算法的轮模式
- * @author Cheney
- */
-@Getter
-@AllArgsConstructor
-public enum AlgMode {
- ECB("ECB", "ECB"),
- CBC( "CBC", "CBC"),
- ;
-
- private final String code;
- private final String desc;
-
-
- public static AlgMode of(String code) {
- if (code == null || code.trim().isEmpty()) {
- return null;
- }
-
- return Arrays.stream(AlgMode.values())
- .filter(it -> Objects.equals(it.getCode(), code))
- .findFirst()
- .orElse(null);
- }
-}
+package com.sunyard.chsm.enums;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+
+/**
+ * 算法的轮模式
+ * @author Cheney
+ */
+@Getter
+@AllArgsConstructor
+public enum AlgMode {
+ ECB("ECB", "ECB"),
+ CBC( "CBC", "CBC"),
+ ;
+
+ private final String code;
+ private final String desc;
+
+
+ public static AlgMode of(String code) {
+ if (code == null || code.trim().isEmpty()) {
+ return null;
+ }
+
+ return Arrays.stream(AlgMode.values())
+ .filter(it -> Objects.equals(it.getCode(), code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/enums/HashAlg.java b/chsm-params/src/main/java/com/sunyard/chsm/enums/HashAlg.java
new file mode 100644
index 0000000..720b80f
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/enums/HashAlg.java
@@ -0,0 +1,10 @@
+package com.sunyard.chsm.enums;
+
+/**
+ * @author liulu
+ * @since 2024/10/22
+ */
+public enum HashAlg {
+ SM3,
+ ;
+}
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/enums/KeyAlg.java b/chsm-params/src/main/java/com/sunyard/chsm/enums/KeyAlg.java
similarity index 100%
rename from chsm-common/src/main/java/com/sunyard/chsm/enums/KeyAlg.java
rename to chsm-params/src/main/java/com/sunyard/chsm/enums/KeyAlg.java
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/enums/KeyCategory.java b/chsm-params/src/main/java/com/sunyard/chsm/enums/KeyCategory.java
similarity index 100%
rename from chsm-common/src/main/java/com/sunyard/chsm/enums/KeyCategory.java
rename to chsm-params/src/main/java/com/sunyard/chsm/enums/KeyCategory.java
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/enums/KeyStatus.java b/chsm-params/src/main/java/com/sunyard/chsm/enums/KeyStatus.java
similarity index 100%
rename from chsm-common/src/main/java/com/sunyard/chsm/enums/KeyStatus.java
rename to chsm-params/src/main/java/com/sunyard/chsm/enums/KeyStatus.java
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/enums/Padding.java b/chsm-params/src/main/java/com/sunyard/chsm/enums/Padding.java
similarity index 95%
rename from chsm-common/src/main/java/com/sunyard/chsm/enums/Padding.java
rename to chsm-params/src/main/java/com/sunyard/chsm/enums/Padding.java
index d699421..87fbbae 100644
--- a/chsm-common/src/main/java/com/sunyard/chsm/enums/Padding.java
+++ b/chsm-params/src/main/java/com/sunyard/chsm/enums/Padding.java
@@ -1,36 +1,36 @@
-package com.sunyard.chsm.enums;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * 数据的填充模式
- *
- * @author Cheney
- */
-@Getter
-@AllArgsConstructor
-public enum Padding {
- NOPadding("NoPadding", "NoPadding"),
- PCKS5Padding("PKCS5Padding", "PKCS5Padding"),
- PCKS7Padding("PKCS7Padding", "PKCS7Padding"),
- ;
-
- private final String code;
- private final String desc;
-
-
- public static Padding of(String code) {
- if (code == null || code.trim().isEmpty()) {
- return null;
- }
-
- return Arrays.stream(Padding.values())
- .filter(it -> Objects.equals(it.getCode(), code))
- .findFirst()
- .orElse(null);
- }
-}
+package com.sunyard.chsm.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * 数据的填充模式
+ *
+ * @author Cheney
+ */
+@Getter
+@AllArgsConstructor
+public enum Padding {
+ NOPadding("NoPadding", "NoPadding"),
+ PCKS5Padding("PKCS5Padding", "PKCS5Padding"),
+ PCKS7Padding("PKCS7Padding", "PKCS7Padding"),
+ ;
+
+ private final String code;
+ private final String desc;
+
+
+ public static Padding of(String code) {
+ if (code == null || code.trim().isEmpty()) {
+ return null;
+ }
+
+ return Arrays.stream(Padding.values())
+ .filter(it -> Objects.equals(it.getCode(), code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/param/AppTokenReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/AppTokenReq.java
similarity index 100%
rename from chsm-web-server/src/main/java/com/sunyard/chsm/param/AppTokenReq.java
rename to chsm-params/src/main/java/com/sunyard/chsm/param/AppTokenReq.java
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/param/AppTokenResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/AppTokenResp.java
similarity index 100%
rename from chsm-web-server/src/main/java/com/sunyard/chsm/param/AppTokenResp.java
rename to chsm-params/src/main/java/com/sunyard/chsm/param/AppTokenResp.java
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyCreateReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/KeyCreateReq.java
similarity index 100%
rename from chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyCreateReq.java
rename to chsm-params/src/main/java/com/sunyard/chsm/param/KeyCreateReq.java
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyInfoQuery.java b/chsm-params/src/main/java/com/sunyard/chsm/param/KeyInfoQuery.java
similarity index 100%
rename from chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyInfoQuery.java
rename to chsm-params/src/main/java/com/sunyard/chsm/param/KeyInfoQuery.java
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyInfoResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/KeyInfoResp.java
similarity index 97%
rename from chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyInfoResp.java
rename to chsm-params/src/main/java/com/sunyard/chsm/param/KeyInfoResp.java
index c33f54d..69f820d 100644
--- a/chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyInfoResp.java
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/KeyInfoResp.java
@@ -15,7 +15,7 @@ public class KeyInfoResp {
/**
* 密钥ID
*/
- private String KeyId;
+ private Long KeyId;
/**
* 密钥算法
*/
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyManageReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/KeyManageReq.java
similarity index 100%
rename from chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyManageReq.java
rename to chsm-params/src/main/java/com/sunyard/chsm/param/KeyManageReq.java
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyUpdateReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/KeyUpdateReq.java
similarity index 100%
rename from chsm-web-server/src/main/java/com/sunyard/chsm/param/KeyUpdateReq.java
rename to chsm-params/src/main/java/com/sunyard/chsm/param/KeyUpdateReq.java
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymDecryptReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymDecryptReq.java
new file mode 100644
index 0000000..c3a9cfb
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymDecryptReq.java
@@ -0,0 +1,37 @@
+package com.sunyard.chsm.param;
+
+import com.sunyard.chsm.enums.AlgMode;
+import com.sunyard.chsm.enums.Padding;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+@Data
+public class SymDecryptReq {
+ // 密钥ID
+ @NotNull(message = "密钥ID不能为空")
+ private Long keyId;
+
+ // 密钥索引
+ @NotEmpty(message = "密钥索引不能为空")
+ @Size(min = 15, max = 24, message = "密钥索引长度在15-24")
+ private String keyIndex;
+
+ // 密文,使用Base64编码
+ @NotBlank(message = "密文不能为空")
+ private String cipherData;
+
+ // 填充方式, 默认PCKS7
+ @NotNull(message = "填充方式不能为空")
+ private Padding padding = Padding.PCKS7Padding;
+
+ // 加密模式, 默认ECB
+ @NotNull(message = "加密模式不能为空")
+ private AlgMode mode = AlgMode.ECB;
+
+ // iv,CBC模式下不能为空,Base64编码
+ private String iv;
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymDecryptResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymDecryptResp.java
new file mode 100644
index 0000000..e033f1b
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymDecryptResp.java
@@ -0,0 +1,13 @@
+package com.sunyard.chsm.param;
+
+import lombok.Data;
+
+@Data
+public class SymDecryptResp {
+ // 密钥ID
+ private Long keyId;
+ // 密钥索引
+ private String keyIndex;
+ // 明文,使用Base64编码
+ private String plainData;
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymEncryptReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymEncryptReq.java
new file mode 100644
index 0000000..1614834
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymEncryptReq.java
@@ -0,0 +1,30 @@
+package com.sunyard.chsm.param;
+
+import com.sunyard.chsm.enums.AlgMode;
+import com.sunyard.chsm.enums.Padding;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class SymEncryptReq {
+
+ // 密钥ID
+ @NotNull(message = "密钥ID不能为空")
+ private Long keyId;
+
+ // 待加密明文,使用Base64编码
+ @NotBlank(message = "明文不能为空")
+ private String plainData;
+
+ // 填充方式, 默认PCKS7
+ private Padding padding = Padding.PCKS7Padding;
+
+ // 加密模式, 默认ECB
+ @NotNull(message = "加密模式不能为空")
+ private AlgMode mode = AlgMode.ECB;
+
+ // iv, CBC模式下不能为空,Base64编码
+ private String iv;
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymEncryptResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymEncryptResp.java
new file mode 100644
index 0000000..0e1c30d
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymEncryptResp.java
@@ -0,0 +1,14 @@
+package com.sunyard.chsm.param;
+
+import lombok.Data;
+
+@Data
+public class SymEncryptResp {
+ // 密钥ID
+ private Long keyId;
+ // 密钥索引
+ private String keyIndex;
+
+ // 密文,使用Base64编码
+ private String cipherData;
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacCheckReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacCheckReq.java
new file mode 100644
index 0000000..d1ff680
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacCheckReq.java
@@ -0,0 +1,33 @@
+package com.sunyard.chsm.param;
+
+import com.sunyard.chsm.enums.HashAlg;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+@Data
+public class SymHmacCheckReq {
+ // 密钥ID
+ @NotNull(message = "密钥ID不能为空")
+ private Long keyId;
+
+ // 密钥索引
+ @NotEmpty(message = "密钥索引不能为空")
+ @Size(min = 15, max = 24, message = "密钥索引长度在15-24")
+ private String keyIndex;
+
+ // Hash算法,默认SM3
+ private HashAlg hashAlg = HashAlg.SM3;
+
+ // 明文,使用Base64编码
+ @NotBlank(message = "明文不能为空")
+ private String plainData;
+
+ // hmac值,使用Base64编码
+ @NotBlank(message = "hmac不能为空")
+ private String hmac;
+
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacCheckResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacCheckResp.java
new file mode 100644
index 0000000..37b89b0
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacCheckResp.java
@@ -0,0 +1,10 @@
+package com.sunyard.chsm.param;
+
+import lombok.Data;
+
+@Data
+public class SymHmacCheckResp {
+
+ private Boolean valid;
+
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacReq.java
new file mode 100644
index 0000000..c9644f4
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacReq.java
@@ -0,0 +1,22 @@
+package com.sunyard.chsm.param;
+
+import com.sunyard.chsm.enums.HashAlg;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class SymHmacReq {
+ // 密钥ID
+ @NotNull(message = "密钥ID不能为空")
+ private Long keyId;
+
+ // 明文,使用Base64编码
+ @NotBlank(message = "明文不能为空")
+ private String plainData;
+
+ // Hash算法,默认SM3
+ private HashAlg hashAlg = HashAlg.SM3;
+
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacResp.java
new file mode 100644
index 0000000..ee0f9ba
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymHmacResp.java
@@ -0,0 +1,15 @@
+package com.sunyard.chsm.param;
+
+import lombok.Data;
+
+@Data
+public class SymHmacResp {
+ // 密钥ID
+ private Long keyId;
+ // 密钥索引
+ private String keyIndex;
+
+ // hmac值,使用Base64编码
+ private String hmac;
+
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacCheckReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacCheckReq.java
new file mode 100644
index 0000000..e2b28d0
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacCheckReq.java
@@ -0,0 +1,37 @@
+package com.sunyard.chsm.param;
+
+import com.sunyard.chsm.enums.Padding;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+@Data
+public class SymMacCheckReq {
+ // 密钥ID
+ @NotNull(message = "密钥ID不能为空")
+ private Long keyId;
+
+ // 密钥索引
+ @NotEmpty(message = "密钥索引不能为空")
+ @Size(min = 15, max = 24, message = "密钥索引长度在15-24")
+ private String keyIndex;
+
+ // 填充方式, 默认PCKS7
+ private Padding padding = Padding.PCKS7Padding;
+
+ // iv,Base64编码
+ @NotBlank(message = "iv不能为空")
+ private String iv;
+
+ // 明文,使用Base64编码
+ @NotBlank(message = "明文不能为空")
+ private String plainData;
+
+ // mac值,使用Base64编码
+ @NotBlank(message = "mac不能为空")
+ private String mac;
+
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacCheckResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacCheckResp.java
new file mode 100644
index 0000000..3a2a3c1
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacCheckResp.java
@@ -0,0 +1,10 @@
+package com.sunyard.chsm.param;
+
+import lombok.Data;
+
+@Data
+public class SymMacCheckResp {
+
+ private Boolean valid;
+
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacReq.java
new file mode 100644
index 0000000..c4fa7a0
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacReq.java
@@ -0,0 +1,26 @@
+package com.sunyard.chsm.param;
+
+import com.sunyard.chsm.enums.Padding;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class SymMacReq {
+ // 密钥ID
+ @NotNull(message = "密钥ID不能为空")
+ private Long keyId;
+
+ // 明文,使用Base64编码
+ @NotBlank(message = "明文不能为空")
+ private String plainData;
+
+ // 填充方式, 默认PCKS7
+ private Padding padding = Padding.PCKS7Padding;
+
+ // iv,Base64编码
+ @NotBlank(message = "iv不能为空")
+ private String iv;
+
+}
diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacResp.java
new file mode 100644
index 0000000..45d0dc1
--- /dev/null
+++ b/chsm-params/src/main/java/com/sunyard/chsm/param/SymMacResp.java
@@ -0,0 +1,15 @@
+package com.sunyard.chsm.param;
+
+import lombok.Data;
+
+@Data
+public class SymMacResp {
+ // 密钥ID
+ private Long keyId;
+ // 密钥索引
+ private String keyIndex;
+
+ // mac值,使用Base64编码
+ private String mac;
+
+}
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
index 91df4ff..80cdbf5 100644
--- 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
@@ -1,6 +1,7 @@
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;
@@ -62,9 +63,9 @@ public class SingleSdfApiService implements SdfApiService, InitializingBean {
}
@Override
- public byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) {
+ public byte[] symEncrypt(AlgId alg, Padding padding, byte[] key, byte[] iv, byte[] data) {
checkStatus();
- byte[] pad = PaddingUtil.PKCS7Padding(data);
+ 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);
@@ -72,12 +73,12 @@ public class SingleSdfApiService implements SdfApiService, InitializingBean {
}
@Override
- public byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) {
+ 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.PKCS7Unpadding(decrypt);
+ return PaddingUtil.unpadding(padding, decrypt);
}
@Override
@@ -138,10 +139,11 @@ public class SingleSdfApiService implements SdfApiService, InitializingBean {
}
@Override
- public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) {
+ 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.SGD_SM4_MAC, pucIv, PaddingUtil.PKCS7Padding(pucData));
+ byte[] mac = sdfApiAdapter.calculateMAC(sessionHandle, hk, algId, pucIv, pad);
sdfApiAdapter.destroyKey(sessionHandle, hk);
return mac;
}
diff --git a/chsm-web-manage/src/test/java/sdf/SdfApiServiceTest.java b/chsm-web-manage/src/test/java/sdf/SdfApiServiceTest.java
index 7702b8b..87c8537 100644
--- a/chsm-web-manage/src/test/java/sdf/SdfApiServiceTest.java
+++ b/chsm-web-manage/src/test/java/sdf/SdfApiServiceTest.java
@@ -1,6 +1,7 @@
package sdf;
import com.sunyard.chsm.enums.ManufacturerModelEnum;
+import com.sunyard.chsm.enums.Padding;
import com.sunyard.chsm.sdf.SdfApiService;
import com.sunyard.chsm.sdf.SingleSdfApiService;
import com.sunyard.chsm.sdf.adapter.SdfApiAdapterFactory;
@@ -92,35 +93,35 @@ public class SdfApiServiceTest {
@Test
public void testSymEncAndDec() {
- byte[] ecbCipher = sdfService.symEncrypt(AlgId.SGD_SM4_ECB, symKey, null, plain.getBytes());
- byte[] ecbPlain = sdfService.symDecrypt(AlgId.SGD_SM4_ECB, symKey, null, ecbCipher);
+ byte[] ecbCipher = sdfService.symEncrypt(AlgId.SGD_SM4_ECB, Padding.PCKS7Padding, symKey, null, plain.getBytes());
+ byte[] ecbPlain = sdfService.symDecrypt(AlgId.SGD_SM4_ECB, Padding.PCKS7Padding, symKey, null, ecbCipher);
log.info("ecb_cipher: {}", CodecUtils.encodeHex(ecbCipher));
Assertions.assertEquals(plain, new String(ecbPlain));
- byte[] cbcCipher = sdfService.symEncrypt(AlgId.SGD_SM4_CBC, symKey, iv, plain.getBytes());
+ byte[] cbcCipher = sdfService.symEncrypt(AlgId.SGD_SM4_CBC, Padding.PCKS7Padding, symKey, iv, plain.getBytes());
log.info("cbc_cipher: {}", CodecUtils.encodeHex(cbcCipher));
- byte[] cbcPlain = sdfService.symDecrypt(AlgId.SGD_SM4_CBC, symKey, iv, cbcCipher);
+ byte[] cbcPlain = sdfService.symDecrypt(AlgId.SGD_SM4_CBC, Padding.PCKS7Padding, symKey, iv, cbcCipher);
Assertions.assertEquals(plain, new String(cbcPlain));
Assertions.assertArrayEquals(ecbPlain, cbcPlain);
Assertions.assertNotEquals(CodecUtils.encodeHex(ecbCipher), CodecUtils.encodeHex(cbcCipher));
- byte[] bcEcbCipher = bcService.symEncrypt(AlgId.SGD_SM4_ECB, symKey, null, plain.getBytes());
+ byte[] bcEcbCipher = bcService.symEncrypt(AlgId.SGD_SM4_ECB, Padding.PCKS7Padding, symKey, null, plain.getBytes());
log.info("bc_ecb_cipher: {}", CodecUtils.encodeHex(bcEcbCipher));
Assertions.assertArrayEquals(ecbCipher, bcEcbCipher);
- byte[] bcCbcCipher = bcService.symEncrypt(AlgId.SGD_SM4_CBC, symKey, iv, plain.getBytes());
+ byte[] bcCbcCipher = bcService.symEncrypt(AlgId.SGD_SM4_CBC, Padding.PCKS7Padding, symKey, iv, plain.getBytes());
log.info("bc_cbc_cipher: {}", CodecUtils.encodeHex(bcCbcCipher));
Assertions.assertArrayEquals(cbcCipher, bcCbcCipher);
}
@Test
public void testSm4Mac() {
- byte[] sdfMac = sdfService.calculateMAC(symKey, iv, plain.getBytes());
+ byte[] sdfMac = sdfService.calculateMAC(AlgId.SGD_SM4_MAC, Padding.PCKS7Padding, symKey, iv, plain.getBytes());
log.info("sdf mac: {}", CodecUtils.encodeHex(sdfMac));
Assertions.assertEquals(16, sdfMac.length);
- byte[] bcMac = bcService.calculateMAC(symKey, iv, plain.getBytes());
+ byte[] bcMac = bcService.calculateMAC(AlgId.SGD_SM4_MAC, Padding.PCKS7Padding, symKey, iv, plain.getBytes());
log.info("bc mac: {}", CodecUtils.encodeHex(bcMac));
Assertions.assertEquals(16, bcMac.length);
diff --git a/chsm-web-server/pom.xml b/chsm-web-server/pom.xml
index cf45222..69c9382 100644
--- a/chsm-web-server/pom.xml
+++ b/chsm-web-server/pom.xml
@@ -24,11 +24,6 @@
chsm-common
${project.version}
-
- com.sunyard.chsm
- chsm-params
- ${project.version}
-
com.dm
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/AppLoginController.java b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/AppLoginController.java
index 3751c89..054c6c1 100644
--- a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/AppLoginController.java
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/AppLoginController.java
@@ -1,5 +1,6 @@
package com.sunyard.chsm.controller;
+import com.sunyard.chsm.model.R;
import com.sunyard.chsm.param.AppTokenReq;
import com.sunyard.chsm.param.AppTokenResp;
import com.sunyard.chsm.service.AppLoginService;
@@ -35,15 +36,16 @@ public class AppLoginController {
* @return
*/
@PostMapping("/appUser/getAppToken")
- public AppTokenResp getAppToken(@Valid @RequestBody AppTokenReq appTokenReq) {
- return appLoginService.getAppToken(appTokenReq);
+ public R getAppToken(@Valid @RequestBody AppTokenReq appTokenReq) {
+ AppTokenResp appToken = appLoginService.getAppToken(appTokenReq);
+ return R.data(appToken);
}
@PostMapping("/appUser/getAppTokenTest")
- public AppTokenResp getAppTokenForTest(@Valid @RequestBody AppTokenReq appTokenReq) {
- return appLoginService.getAppTokenForTest(appTokenReq);
+ public R getAppTokenForTest(@Valid @RequestBody AppTokenReq appTokenReq) {
+ AppTokenResp appToken = appLoginService.getAppTokenForTest(appTokenReq);
+ return R.data(appToken);
}
-
}
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/KeyManageController.java b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/KeyManageController.java
index dbc44ea..775985c 100644
--- a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/KeyManageController.java
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/KeyManageController.java
@@ -51,7 +51,7 @@ public class KeyManageController {
* @return 分页列表
*/
@PostMapping("/info")
- public R queryInfo(Long id) {
+ public R queryInfo(@RequestBody Long id) {
Assert.notNull(id, "密钥id不能为空");
KeyInfoResp resp = keyManageService.queryInfo(id);
return R.data(resp);
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/SymKeyController.java b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/SymKeyController.java
new file mode 100644
index 0000000..ce68555
--- /dev/null
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/SymKeyController.java
@@ -0,0 +1,110 @@
+package com.sunyard.chsm.controller;
+
+import com.sunyard.chsm.model.R;
+import com.sunyard.chsm.param.SymDecryptReq;
+import com.sunyard.chsm.param.SymDecryptResp;
+import com.sunyard.chsm.param.SymEncryptReq;
+import com.sunyard.chsm.param.SymEncryptResp;
+import com.sunyard.chsm.param.SymHmacCheckReq;
+import com.sunyard.chsm.param.SymHmacCheckResp;
+import com.sunyard.chsm.param.SymHmacReq;
+import com.sunyard.chsm.param.SymHmacResp;
+import com.sunyard.chsm.param.SymMacCheckReq;
+import com.sunyard.chsm.param.SymMacCheckResp;
+import com.sunyard.chsm.param.SymMacReq;
+import com.sunyard.chsm.param.SymMacResp;
+import com.sunyard.chsm.service.SymKeyService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+import javax.validation.Valid;
+
+/**
+ * 对称运算类接口
+ *
+ * @author liulu
+ * @since 2024/12/17
+ */
+@RestController
+@RequestMapping("/sym")
+public class SymKeyController {
+
+ @Autowired
+ private SymKeyService symKeyService;
+
+ /**
+ * 对称加密
+ *
+ * @param req
+ * @return
+ */
+ @PostMapping("/encrypt")
+ public R encrypt(@Valid @RequestBody SymEncryptReq req) {
+ SymEncryptResp resp = symKeyService.encrypt(req);
+ return R.data(resp);
+ }
+
+ /**
+ * 对称解密
+ *
+ * @param req
+ * @return
+ */
+ @PostMapping("/decrypt")
+ public R decrypt(@Valid @RequestBody SymDecryptReq req) {
+ SymDecryptResp resp = symKeyService.decrypt(req);
+ return R.data(resp);
+ }
+
+ /**
+ * 计算Hmac
+ *
+ * @param req
+ * @return
+ */
+ @PostMapping("/hmac")
+ public R hmac(@Valid @RequestBody SymHmacReq req) {
+ SymHmacResp resp = symKeyService.hmac(req);
+ return R.data(resp);
+ }
+
+ /**
+ * 验证Hmac
+ *
+ * @param req
+ * @return
+ */
+ @PostMapping("/hmac/check")
+ public R macCheck(@Valid @RequestBody SymHmacCheckReq req) {
+ SymHmacCheckResp resp = symKeyService.hmacCheck(req);
+ return R.data(resp);
+ }
+
+ /**
+ * 计算Hmac
+ *
+ * @param req
+ * @return
+ */
+ @PostMapping("/mac")
+ public R mac(@Valid @RequestBody SymMacReq req) {
+ SymMacResp resp = symKeyService.mac(req);
+ return R.data(resp);
+ }
+
+ /**
+ * 验证Hmac
+ *
+ * @param req
+ * @return
+ */
+ @PostMapping("/mac/check")
+ public R macCheck(@Valid @RequestBody SymMacCheckReq req) {
+ SymMacCheckResp resp = symKeyService.macCheck(req);
+ return R.data(resp);
+ }
+
+}
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 b5aab50..5bb23a7 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
@@ -1,5 +1,6 @@
package com.sunyard.chsm.pool;
+import com.sunyard.chsm.enums.Padding;
import com.sunyard.chsm.sdf.SdfApiService;
import com.sunyard.chsm.sdf.context.AlgId;
import com.sunyard.chsm.sdf.model.EccCipher;
@@ -46,24 +47,25 @@ public class LoadBalancedSdfApiService implements SdfApiService {
}
@Override
- public byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) {
+ public byte[] symEncrypt(AlgId alg, Padding padding, byte[] key, byte[] iv, byte[] data) {
+ byte[] paddingData = PaddingUtil.padding(padding, data);
return apply(s -> {
String keyHandle = s.getSdfApiAdapter().importKey(s.getSessionHandle(), key);
- byte[] encrypt = s.getSdfApiAdapter().symEncrypt(s.getSessionHandle(), keyHandle, alg, iv, PaddingUtil.PKCS7Padding(data));
+ byte[] encrypt = s.getSdfApiAdapter().symEncrypt(s.getSessionHandle(), keyHandle, alg, iv, paddingData);
s.getSdfApiAdapter().destroyKey(s.getSessionHandle(), keyHandle);
return encrypt;
});
}
@Override
- public byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) {
+ public byte[] symDecrypt(AlgId alg, Padding padding, byte[] key, byte[] iv, byte[] data) {
byte[] decrypt = apply(s -> {
String keyHandle = s.getSdfApiAdapter().importKey(s.getSessionHandle(), key);
byte[] d = s.getSdfApiAdapter().symDecrypt(s.getSessionHandle(), keyHandle, alg, iv, data);
s.getSdfApiAdapter().destroyKey(s.getSessionHandle(), keyHandle);
return d;
});
- return PaddingUtil.PKCS7Unpadding(decrypt);
+ return PaddingUtil.unpadding(padding, decrypt);
}
@Override
@@ -125,10 +127,11 @@ public class LoadBalancedSdfApiService implements SdfApiService {
}
@Override
- public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) {
+ public byte[] calculateMAC(AlgId algId, Padding padding, byte[] symKey, byte[] pucIv, byte[] pucData) {
+ byte[] pad = PaddingUtil.padding(padding, pucData);
return apply(s -> {
String keyHandle = s.getSdfApiAdapter().importKey(s.getSessionHandle(), symKey);
- byte[] mac = s.getSdfApiAdapter().calculateMAC(s.getSessionHandle(), keyHandle, AlgId.SGD_SM4_MAC, pucIv, PaddingUtil.PKCS7Padding(pucData));
+ byte[] mac = s.getSdfApiAdapter().calculateMAC(s.getSessionHandle(), keyHandle, algId, pucIv, pad);
s.getSdfApiAdapter().destroyKey(s.getSessionHandle(), keyHandle);
return mac;
});
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/service/KeyManageService.java b/chsm-web-server/src/main/java/com/sunyard/chsm/service/KeyManageService.java
index 4373756..0d77c92 100644
--- a/chsm-web-server/src/main/java/com/sunyard/chsm/service/KeyManageService.java
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/service/KeyManageService.java
@@ -3,6 +3,8 @@ package com.sunyard.chsm.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sunyard.chsm.auth.AppUser;
import com.sunyard.chsm.auth.UserContext;
+import com.sunyard.chsm.enums.KeyCategory;
+import com.sunyard.chsm.enums.KeyStatus;
import com.sunyard.chsm.mapper.KeyInfoMapper;
import com.sunyard.chsm.model.dto.KeyInfoDTO;
import com.sunyard.chsm.model.entity.KeyInfo;
@@ -22,6 +24,7 @@ import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.stream.Collectors;
/**
@@ -40,7 +43,8 @@ public class KeyManageService {
public Page queryPageList(KeyInfoQuery query) {
KeyInfoDTO.Query nq = new KeyInfoDTO.Query();
- BeanUtils.copyProperties(query, nq);
+ nq.setKeyType(Optional.ofNullable(query.getKeyType()).map(KeyCategory::getCode).orElse(null));
+ nq.setStatus(Optional.ofNullable(query.getStatus()).map(KeyStatus::getCode).orElse(null));
nq.setAppId(UserContext.getCurrentAppId());
Page page = keyInfoService.selectPageList(nq);
List records = page.getRecords();
@@ -51,7 +55,7 @@ public class KeyManageService {
.map(it -> {
KeyInfoResp resp = new KeyInfoResp();
BeanUtils.copyProperties(it, resp);
- resp.setKeyId(it.getCode());
+ resp.setKeyId(it.getId());
return resp;
})
.collect(Collectors.toList());
@@ -64,7 +68,7 @@ public class KeyManageService {
KeyInfoDTO.KeyView view = keyInfoService.selectById(id);
KeyInfoResp resp = new KeyInfoResp();
BeanUtils.copyProperties(view, resp);
- resp.setKeyId(view.getCode());
+ resp.setKeyId(view.getId());
return resp;
}
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/service/SymKeyService.java b/chsm-web-server/src/main/java/com/sunyard/chsm/service/SymKeyService.java
new file mode 100644
index 0000000..a5f3598
--- /dev/null
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/service/SymKeyService.java
@@ -0,0 +1,231 @@
+package com.sunyard.chsm.service;
+
+import com.sunyard.chsm.auth.UserContext;
+import com.sunyard.chsm.enums.AlgMode;
+import com.sunyard.chsm.enums.KeyAlg;
+import com.sunyard.chsm.enums.KeyCategory;
+import com.sunyard.chsm.enums.KeyStatus;
+import com.sunyard.chsm.enums.KeyUsage;
+import com.sunyard.chsm.enums.Padding;
+import com.sunyard.chsm.mapper.KeyInfoMapper;
+import com.sunyard.chsm.mapper.SpKeyRecordMapper;
+import com.sunyard.chsm.model.entity.KeyInfo;
+import com.sunyard.chsm.model.entity.KeyRecord;
+import com.sunyard.chsm.param.SymDecryptReq;
+import com.sunyard.chsm.param.SymDecryptResp;
+import com.sunyard.chsm.param.SymEncryptReq;
+import com.sunyard.chsm.param.SymEncryptResp;
+import com.sunyard.chsm.param.SymHmacCheckReq;
+import com.sunyard.chsm.param.SymHmacCheckResp;
+import com.sunyard.chsm.param.SymHmacReq;
+import com.sunyard.chsm.param.SymHmacResp;
+import com.sunyard.chsm.param.SymMacCheckReq;
+import com.sunyard.chsm.param.SymMacCheckResp;
+import com.sunyard.chsm.param.SymMacReq;
+import com.sunyard.chsm.param.SymMacResp;
+import com.sunyard.chsm.sdf.SdfApiService;
+import com.sunyard.chsm.sdf.context.AlgId;
+import com.sunyard.chsm.utils.CodecUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * @author liulu
+ * @since 2024/12/17
+ */
+@Service
+@RequiredArgsConstructor
+public class SymKeyService {
+
+ private final KeyInfoMapper keyInfoMapper;
+ private final SpKeyRecordMapper spKeyRecordMapper;
+ private final SdfApiService sdfApiService;
+
+
+ public SymEncryptResp encrypt(SymEncryptReq req) {
+ byte[] iv = new byte[0];
+ if (AlgMode.CBC == req.getMode()) {
+ Assert.hasText(req.getIv(), "CBC模式iv不能为空");
+ byte[] bytes = CodecUtils.decodeBase64(req.getIv());
+ Assert.isTrue(bytes.length >= 16, "iv长度至少为16");
+ iv = bytes;
+ }
+ byte[] plain = CodecUtils.decodeBase64(req.getPlainData());
+ KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.ENCRYPT_DECRYPT);
+ KeyAlg keyAlg = KeyAlg.of(keyInfo.getKeyAlg());
+ Assert.notNull(keyAlg, "数据异常");
+ AlgId algId = null;
+ switch (keyAlg) {
+ case SM4:
+ if (Padding.PCKS5Padding == req.getPadding()) {
+ req.setPadding(Padding.PCKS7Padding);
+ }
+ switch (req.getMode()) {
+ case ECB:
+ algId = AlgId.SGD_SM4_ECB;
+ break;
+ case CBC:
+ algId = AlgId.SGD_SM4_CBC;
+ break;
+ }
+ break;
+ default:
+ throw new UnsupportedOperationException("不支持的密钥算法:" + keyAlg.getCode());
+ }
+ KeyRecord keyRecord = spKeyRecordMapper.selectUsedByKeyId(keyInfo.getId());
+ Assert.notNull(keyRecord, "数据异常");
+ byte[] symKey = sdfApiService.decryptByTMK(CodecUtils.decodeHex(keyRecord.getKeyData()));
+ byte[] cipherData = sdfApiService.symEncrypt(algId, req.getPadding(), symKey, iv, plain);
+
+ SymEncryptResp resp = new SymEncryptResp();
+ resp.setKeyId(keyInfo.getId());
+ resp.setKeyIndex(keyRecord.getKeyIndex());
+ resp.setCipherData(CodecUtils.encodeBase64(cipherData));
+ return resp;
+ }
+
+
+ public SymDecryptResp decrypt(SymDecryptReq req) {
+ byte[] iv = new byte[0];
+ if (AlgMode.CBC == req.getMode()) {
+ Assert.hasText(req.getIv(), "CBC模式iv不能为空");
+ byte[] bytes = CodecUtils.decodeBase64(req.getIv());
+ Assert.isTrue(bytes.length >= 16, "iv长度至少为16");
+ iv = bytes;
+ }
+ byte[] cipher = CodecUtils.decodeBase64(req.getCipherData());
+ KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.ENCRYPT_DECRYPT);
+ KeyAlg keyAlg = KeyAlg.of(keyInfo.getKeyAlg());
+ Assert.notNull(keyAlg, "数据异常");
+ AlgId algId = null;
+ switch (keyAlg) {
+ case SM4:
+ if (Padding.PCKS5Padding == req.getPadding()) {
+ req.setPadding(Padding.PCKS7Padding);
+ }
+ switch (req.getMode()) {
+ case ECB:
+ algId = AlgId.SGD_SM4_ECB;
+ break;
+ case CBC:
+ algId = AlgId.SGD_SM4_CBC;
+ break;
+ }
+ break;
+ default:
+ throw new UnsupportedOperationException("不支持的密钥算法:" + keyAlg.getCode());
+ }
+ KeyRecord keyRecord = spKeyRecordMapper.selectById(Long.valueOf(req.getKeyIndex()));
+ Assert.notNull(keyRecord, "数据异常");
+ Assert.isTrue(Objects.equals(keyRecord.getKeyId(), keyInfo.getId()), "密钥Id和密钥索引不匹配");
+ byte[] symKey = sdfApiService.decryptByTMK(CodecUtils.decodeHex(keyRecord.getKeyData()));
+ byte[] plain = sdfApiService.symDecrypt(algId, req.getPadding(), symKey, iv, cipher);
+
+ SymDecryptResp resp = new SymDecryptResp();
+ resp.setKeyId(keyInfo.getId());
+ resp.setKeyIndex(keyRecord.getKeyIndex());
+ resp.setPlainData(CodecUtils.encodeBase64(plain));
+ return resp;
+ }
+
+
+ public SymHmacResp hmac(SymHmacReq req) {
+
+ byte[] plain = CodecUtils.decodeBase64(req.getPlainData());
+ KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.HMAC);
+ KeyRecord keyRecord = spKeyRecordMapper.selectUsedByKeyId(keyInfo.getId());
+ byte[] symKey = sdfApiService.decryptByTMK(CodecUtils.decodeHex(keyRecord.getKeyData()));
+ byte[] hmac = sdfApiService.hmac(symKey, plain);
+
+ SymHmacResp resp = new SymHmacResp();
+ resp.setKeyId(keyInfo.getId());
+ resp.setKeyIndex(keyRecord.getKeyIndex());
+ resp.setHmac(CodecUtils.encodeBase64(hmac));
+ return resp;
+ }
+
+ public SymHmacCheckResp hmacCheck(SymHmacCheckReq req) {
+
+ byte[] plain = CodecUtils.decodeBase64(req.getPlainData());
+ byte[] originHmac = CodecUtils.decodeBase64(req.getHmac());
+ KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.HMAC);
+
+ KeyRecord keyRecord = spKeyRecordMapper.selectById(Long.valueOf(req.getKeyIndex()));
+ Assert.notNull(keyRecord, "数据异常");
+ Assert.isTrue(Objects.equals(keyRecord.getKeyId(), keyInfo.getId()), "密钥Id和密钥索引不匹配");
+ byte[] symKey = sdfApiService.decryptByTMK(CodecUtils.decodeHex(keyRecord.getKeyData()));
+ byte[] hmac = sdfApiService.hmac(symKey, plain);
+
+ SymHmacCheckResp resp = new SymHmacCheckResp();
+ resp.setValid(Arrays.equals(hmac, originHmac));
+ return resp;
+ }
+
+
+ public SymMacResp mac(SymMacReq req) {
+ byte[] plain = CodecUtils.decodeBase64(req.getPlainData());
+ byte[] iv = CodecUtils.decodeBase64(req.getIv());
+ Assert.isTrue(iv.length >= 16, "iv长度至少为16");
+ KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.MAC);
+ KeyRecord keyRecord = spKeyRecordMapper.selectUsedByKeyId(keyInfo.getId());
+ Assert.notNull(keyRecord, "数据异常");
+ if (Padding.PCKS5Padding == req.getPadding()) {
+ req.setPadding(Padding.PCKS7Padding);
+ }
+ byte[] symKey = sdfApiService.decryptByTMK(CodecUtils.decodeHex(keyRecord.getKeyData()));
+ byte[] mac = sdfApiService.calculateMAC(AlgId.SGD_SM4_MAC, req.getPadding(), symKey, iv, plain);
+
+ SymMacResp resp = new SymMacResp();
+ resp.setKeyId(keyInfo.getId());
+ resp.setKeyIndex(keyRecord.getKeyIndex());
+ resp.setMac(CodecUtils.encodeBase64(mac));
+ return resp;
+ }
+
+
+ public SymMacCheckResp macCheck(SymMacCheckReq req) {
+
+ byte[] plain = CodecUtils.decodeBase64(req.getPlainData());
+ byte[] iv = CodecUtils.decodeBase64(req.getIv());
+ byte[] originMac = CodecUtils.decodeBase64(req.getMac());
+ KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.MAC);
+
+ KeyRecord keyRecord = spKeyRecordMapper.selectById(Long.valueOf(req.getKeyIndex()));
+ Assert.notNull(keyRecord, "数据异常");
+ Assert.isTrue(Objects.equals(keyRecord.getKeyId(), keyInfo.getId()), "密钥Id和密钥索引不匹配");
+ if (Padding.PCKS5Padding == req.getPadding()) {
+ req.setPadding(Padding.PCKS7Padding);
+ }
+ byte[] symKey = sdfApiService.decryptByTMK(CodecUtils.decodeHex(keyRecord.getKeyData()));
+ byte[] mac = sdfApiService.calculateMAC(AlgId.SGD_SM4_MAC, req.getPadding(), symKey, iv, plain);
+
+ SymMacCheckResp resp = new SymMacCheckResp();
+ resp.setValid(Arrays.equals(mac, originMac));
+ return resp;
+
+ }
+
+
+ private KeyInfo checkKey(Long keyId, KeyUsage usage) {
+
+ KeyInfo keyInfo = keyInfoMapper.selectById(keyId);
+ Assert.notNull(keyInfo, "密钥ID不存在");
+ Assert.isTrue(Objects.equals(keyInfo.getApplicationId(), UserContext.getCurrentAppId()), "您无权使用此密钥ID");
+ Assert.isTrue(KeyCategory.SYM_KEY.getCode().equals(keyInfo.getKeyType()), "此密钥不是对称密钥");
+
+ KeyStatus status = KeyStatus.of(keyInfo.getCode());
+ LocalDateTime now = LocalDateTime.now();
+ Assert.isTrue(KeyStatus.ENABLED == status, "此密钥不是启用状态, 无法操作");
+ Assert.isTrue(now.isAfter(keyInfo.getEffectiveTime()) && now.isBefore(keyInfo.getExpiredTime()), "此密钥不是启用状态, 无法操作");
+ Assert.isTrue(KeyUsage.hasUsage(keyInfo.getKeyUsage(), usage), "此密钥无权进行" + usage.getDesc() + "操作");
+
+ return keyInfo;
+ }
+
+
+}
diff --git a/chsm-web-server/src/test/java/api/BaseTest.java b/chsm-web-server/src/test/java/api/BaseTest.java
new file mode 100644
index 0000000..9245973
--- /dev/null
+++ b/chsm-web-server/src/test/java/api/BaseTest.java
@@ -0,0 +1,70 @@
+package api;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.sunyard.chsm.model.R;
+import com.sunyard.chsm.param.AppTokenReq;
+import com.sunyard.chsm.param.AppTokenResp;
+import com.sunyard.chsm.utils.JsonUtils;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.http.MediaType;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.IOException;
+
+/**
+ * @author liulu
+ * @since 2024/12/17
+ */
+public abstract class BaseTest {
+
+ protected static final String ak = "216205d408130d83d13c5072305b8b65";
+ protected static final String sk = "ae64515d1d5adec2cc6ae8726d0c1bbc";
+ protected static final String server = "http://127.0.0.1:8900";
+ protected static final RestTemplate restTemplate;
+ protected static final String token;
+
+ static {
+ AppTokenReq req = new AppTokenReq();
+ req.setAppKey(ak);
+ req.setHmac(sk);
+ req.setRandom(System.currentTimeMillis());
+
+ RequestEntity request = RequestEntity.post(server + "/appUser/getAppTokenTest")
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(JsonUtils.toJsonBytes(req));
+ ResponseEntity response = new RestTemplate().exchange(request, String.class);
+ try {
+ R r = JsonUtils.objectMapper()
+ .readValue(response.getBody(), new TypeReference>() {
+ });
+ token = r.getResult().getToken();
+ restTemplate = new RestTemplateBuilder()
+ .rootUri(server)
+ .defaultHeader("Authorization", "Bearer " + token)
+ .defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE)
+ .build();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected static T execute(String url, Object req, Class tClass) {
+ try {
+ RequestEntity request = RequestEntity.post("/appUser/getAppTokenTest")
+ .contentType(MediaType.APPLICATION_JSON)
+ .header("Authorization", "Bearer " + token)
+ .body(JsonUtils.toJsonBytes(req));
+
+ byte[] res = restTemplate.postForObject(url, JsonUtils.toJsonBytes(req), byte[].class);
+ R r = JsonUtils.objectMapper()
+ .readValue(res, new TypeReference>() {
+ });
+ return r.getResult();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/chsm-web-server/src/test/java/api/KeyManageTest.java b/chsm-web-server/src/test/java/api/KeyManageTest.java
new file mode 100644
index 0000000..a0c5657
--- /dev/null
+++ b/chsm-web-server/src/test/java/api/KeyManageTest.java
@@ -0,0 +1,48 @@
+package api;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.sunyard.chsm.model.R;
+import com.sunyard.chsm.model.entity.KeyInfo;
+import com.sunyard.chsm.param.KeyInfoQuery;
+import com.sunyard.chsm.param.KeyInfoResp;
+import com.sunyard.chsm.utils.JsonUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+
+/**
+ * @author liulu
+ * @since 2024/12/17
+ */
+@Slf4j
+public class KeyManageTest extends BaseTest {
+
+ private static Long keyId;
+
+ @BeforeAll
+ public static void before() throws Exception {
+ KeyInfoQuery query = new KeyInfoQuery();
+ byte[] res = restTemplate.postForObject("/key/pageList", JsonUtils.toJsonBytes(query), byte[].class);
+ R> r = JsonUtils.objectMapper()
+ .readValue(res, new TypeReference>>() {
+ });
+ Assertions.assertTrue(r.isSuccess());
+
+ List records = r.getResult().getRecords();
+ Assertions.assertFalse(CollectionUtils.isEmpty(records));
+ keyId = records.iterator().next().getKeyId();
+ }
+
+ @Test
+ public void keyInfoTest(){
+ KeyInfo res = execute("/key/info", keyId, KeyInfo.class);
+ log.info("keyInfoTest: {}", JsonUtils.toJsonString(res));
+ }
+
+
+}