Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e16420c2c5 | ||
|
|
385a2a6ecc |
+7
-12
@@ -20,11 +20,14 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sunyard.chsm</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>chsm-params</artifactId>
|
<artifactId>hutool-all</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>5.8.33</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
@@ -54,21 +57,13 @@
|
|||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
|
||||||
<artifactId>caffeine</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.java.dev.jna</groupId>
|
<groupId>net.java.dev.jna</groupId>
|
||||||
<artifactId>jna</artifactId>
|
<artifactId>jna</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.briandilley.jsonrpc4j</groupId>
|
|
||||||
<artifactId>jsonrpc4j</artifactId>
|
|
||||||
<version>1.6</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
package com.sunyard.chsm.config;
|
|
||||||
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
||||||
import com.sunyard.chsm.constant.ParamConfKeyConstant;
|
|
||||||
import com.sunyard.chsm.enums.EnableStatus;
|
|
||||||
import com.sunyard.chsm.mapper.IpWhitelisttMapper;
|
|
||||||
import com.sunyard.chsm.mapper.ParamConfMapper;
|
|
||||||
import com.sunyard.chsm.model.entity.IpWhitelist;
|
|
||||||
import com.sunyard.chsm.model.entity.ParamConf;
|
|
||||||
import com.sunyard.chsm.utils.IpUtils;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.ApplicationArguments;
|
|
||||||
import org.springframework.boot.ApplicationRunner;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/2
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class IpFilter extends OncePerRequestFilter implements ApplicationRunner {
|
|
||||||
|
|
||||||
public static List<String> whiteIps = new ArrayList<>();
|
|
||||||
public static Boolean enableWhiteIp = false;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IpWhitelisttMapper ipWhitelisttMapper;
|
|
||||||
@Resource
|
|
||||||
private ParamConfMapper paramConfMapper;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
|
||||||
if (enableWhiteIp && CollectionUtils.isEmpty(whiteIps)) {
|
|
||||||
syncWhiteIps();
|
|
||||||
}
|
|
||||||
String ip = IpUtils.getIpAddress(request);
|
|
||||||
if (!enableWhiteIp || CollectionUtils.isEmpty(whiteIps) || whiteIps.contains(ip)) {
|
|
||||||
chain.doFilter(request, response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
logger.warn("forbidden for ip: " + ip);
|
|
||||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
|
||||||
response.setContentType(MediaType.TEXT_PLAIN_VALUE);
|
|
||||||
response.getWriter().println("this ip is forbidden");
|
|
||||||
response.getWriter().flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
|
||||||
Executors.newSingleThreadScheduledExecutor()
|
|
||||||
.scheduleWithFixedDelay(() -> {
|
|
||||||
|
|
||||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.IP_WHITELIST_SWITCH);
|
|
||||||
if (conf != null) {
|
|
||||||
enableWhiteIp = Objects.equals("true", conf.getValue());
|
|
||||||
}
|
|
||||||
if (enableWhiteIp) {
|
|
||||||
syncWhiteIps();
|
|
||||||
}
|
|
||||||
}, 1L, 5L, TimeUnit.MINUTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void syncWhiteIps() {
|
|
||||||
List<IpWhitelist> list = ipWhitelisttMapper.selectList(
|
|
||||||
new LambdaQueryWrapper<IpWhitelist>()
|
|
||||||
.eq(IpWhitelist::getScope, "global")
|
|
||||||
.eq(IpWhitelist::getStatus, EnableStatus.ENABLED.getCode())
|
|
||||||
);
|
|
||||||
whiteIps = list.stream().map(IpWhitelist::getIp).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package com.sunyard.chsm.constant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/16
|
|
||||||
*/
|
|
||||||
public interface AuthCodeConst {
|
|
||||||
|
|
||||||
// 密钥管理
|
|
||||||
String key_info = "key_info";
|
|
||||||
String key_list = "key_list";
|
|
||||||
String key_create = "key_create";
|
|
||||||
String key_update = "key_update";
|
|
||||||
String key_enable = "key_enable";
|
|
||||||
String key_disable = "key_disable";
|
|
||||||
String key_archive = "key_archive";
|
|
||||||
String key_destroy = "key_destroy";
|
|
||||||
|
|
||||||
// 对称运算
|
|
||||||
String sym_enc = "sym_enc";
|
|
||||||
String sym_dec = "sym_dec";
|
|
||||||
String cal_hmac = "cal_hmac";
|
|
||||||
String check_hmac = "check_hmac";
|
|
||||||
String cal_mac = "cal_mac";
|
|
||||||
String check_mac = "check_mac";
|
|
||||||
String gen_random = "gen_random";
|
|
||||||
|
|
||||||
// 非对称运算
|
|
||||||
String asym_enc = "asym_enc";
|
|
||||||
String asym_dec = "asym_dec";
|
|
||||||
String sign_raw = "sign_raw";
|
|
||||||
String verify_raw = "verify_raw";
|
|
||||||
String sign_p1 = "sign_p1";
|
|
||||||
String verify_p1 = "verify_p1";
|
|
||||||
String sign_P7Attach = "sign_P7Attach";
|
|
||||||
String verify_P7Attach = "verify_P7Attach";
|
|
||||||
String sign_P7Detach = "sign_P7Detach";
|
|
||||||
String verify_P7Detach = "verify_P7Detach";
|
|
||||||
String envelope_seal = "envelope_enc";
|
|
||||||
String envelope_unseal = "envelope_dec";
|
|
||||||
String signed_envelope_seal = "signed_envelope_enc";
|
|
||||||
String signed_envelope_unseal = "signed_envelope_dec";
|
|
||||||
|
|
||||||
String cal_hash = "cal_hash";
|
|
||||||
|
|
||||||
// 证书
|
|
||||||
String cert_info = "cert_info";
|
|
||||||
String cert_exinfo = "cert_exinfo";
|
|
||||||
String cert_check = "cert_check";
|
|
||||||
String cert_upload = "cert_upload";
|
|
||||||
String cert_remove = "cert_remove";
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.sunyard.chsm.constant;
|
|
||||||
|
|
||||||
import com.sunyard.chsm.utils.CodecUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/19
|
|
||||||
*/
|
|
||||||
public interface CryptoConst {
|
|
||||||
|
|
||||||
byte[] USER_ID = CodecUtils.decodeHex("31323334353637383132333435363738");
|
|
||||||
|
|
||||||
static byte[] iv() {
|
|
||||||
return CodecUtils.decodeHex("30303030303030303030303030303030");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.sunyard.chsm.enums;
|
package com.sunyard.chsm.enums;
|
||||||
|
|
||||||
import com.sunyard.chsm.constant.AuthCodeConst;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -12,46 +11,24 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum ApiFunEnum {
|
public enum ApiFunEnum {
|
||||||
|
|
||||||
key_info(ApiGroupEnum.KEY_MANAGE_API, AuthCodeConst.key_info, "查询密钥详情"),
|
sym_enc(ApiGroupEnum.SYM_API,"sym_enc", "对称加密"),
|
||||||
key_list(ApiGroupEnum.KEY_MANAGE_API, AuthCodeConst.key_list, "查询密钥列表"),
|
sym_dec(ApiGroupEnum.ASYM_API,"sym_dec", "对称解密"),
|
||||||
key_create(ApiGroupEnum.KEY_MANAGE_API, AuthCodeConst.key_create, "创建密钥"),
|
cal_hmac(ApiGroupEnum.SYM_API,"cal_hmac", "计算Hmac"),
|
||||||
key_update(ApiGroupEnum.KEY_MANAGE_API, AuthCodeConst.key_update, "更新密钥"),
|
check_hmac(ApiGroupEnum.ASYM_API,"check_hmac", "验证Hmac"),
|
||||||
key_enable(ApiGroupEnum.KEY_MANAGE_API, AuthCodeConst.key_enable, "启用密钥"),
|
cal_mac(ApiGroupEnum.SYM_API,"cal_mac", "计算mac"),
|
||||||
key_disable(ApiGroupEnum.KEY_MANAGE_API, AuthCodeConst.key_disable, "停用密钥"),
|
check_mac(ApiGroupEnum.ASYM_API,"check_mac", "验证mac"),
|
||||||
key_archive(ApiGroupEnum.KEY_MANAGE_API, AuthCodeConst.key_archive, "归档密钥"),
|
gen_random(ApiGroupEnum.SYM_API,"gen_random", "生成随机数"),
|
||||||
key_destroy(ApiGroupEnum.KEY_MANAGE_API, AuthCodeConst.key_destroy, "销毁密钥"),
|
|
||||||
|
|
||||||
sym_enc(ApiGroupEnum.SYM_API, AuthCodeConst.sym_enc, "对称加密"),
|
|
||||||
sym_dec(ApiGroupEnum.SYM_API, AuthCodeConst.sym_dec, "对称解密"),
|
|
||||||
cal_hmac(ApiGroupEnum.SYM_API, AuthCodeConst.cal_hmac, "计算Hmac"),
|
|
||||||
check_hmac(ApiGroupEnum.SYM_API, AuthCodeConst.check_hmac, "验证Hmac"),
|
|
||||||
cal_mac(ApiGroupEnum.SYM_API, AuthCodeConst.cal_mac, "计算mac"),
|
|
||||||
check_mac(ApiGroupEnum.SYM_API, AuthCodeConst.check_mac, "验证mac"),
|
|
||||||
gen_random(ApiGroupEnum.SYM_API, AuthCodeConst.gen_random, "生成随机数"),
|
|
||||||
|
|
||||||
asym_enc(ApiGroupEnum.ASYM_API, AuthCodeConst.asym_enc, "非对称加密"),
|
|
||||||
asym_dec(ApiGroupEnum.ASYM_API, AuthCodeConst.asym_dec, "非对称解密"),
|
|
||||||
sign_raw(ApiGroupEnum.ASYM_API, AuthCodeConst.sign_raw, "RAW签名"),
|
|
||||||
verify_raw(ApiGroupEnum.ASYM_API, AuthCodeConst.verify_raw, "RAW验签"),
|
|
||||||
sign_p1(ApiGroupEnum.ASYM_API, AuthCodeConst.sign_p1, "P1签名"),
|
|
||||||
verify_p1(ApiGroupEnum.ASYM_API, AuthCodeConst.verify_p1, "P1验签"),
|
|
||||||
sign_P7Attach(ApiGroupEnum.ASYM_API, AuthCodeConst.sign_P7Attach, "P7 Attach签名"),
|
|
||||||
verify_P7Attach(ApiGroupEnum.ASYM_API, AuthCodeConst.verify_P7Attach, "P7 Attach验签"),
|
|
||||||
sign_P7Detach(ApiGroupEnum.ASYM_API, AuthCodeConst.sign_P7Detach, "P7 Detach签名"),
|
|
||||||
verify_P7Detach(ApiGroupEnum.ASYM_API, AuthCodeConst.verify_P7Detach, "P7 Detach验签"),
|
|
||||||
envelope_seal(ApiGroupEnum.ASYM_API, AuthCodeConst.envelope_seal, "P7数字信封加封"),
|
|
||||||
envelope_unseal(ApiGroupEnum.ASYM_API, AuthCodeConst.envelope_unseal, "P7数字信封解封"),
|
|
||||||
signed_envelope_seal(ApiGroupEnum.ASYM_API, AuthCodeConst.signed_envelope_seal, "带签名的数字信封加封"),
|
|
||||||
signed_envelope_unseal(ApiGroupEnum.ASYM_API, AuthCodeConst.signed_envelope_unseal, "带签名的数字信封解封"),
|
|
||||||
|
|
||||||
cal_hash(ApiGroupEnum.HASH_API, AuthCodeConst.cal_hash, "计算Hash"),
|
|
||||||
|
|
||||||
cert_info(ApiGroupEnum.CERT_API, AuthCodeConst.cert_info, "获取证书信息"),
|
|
||||||
cert_exinfo(ApiGroupEnum.CERT_API, AuthCodeConst.cert_exinfo, "获取证书拓展信"),
|
|
||||||
cert_check(ApiGroupEnum.CERT_API, AuthCodeConst.cert_check, "验证证书"),
|
|
||||||
cert_upload(ApiGroupEnum.CERT_API, AuthCodeConst.cert_upload, "上传用户证书"),
|
|
||||||
cert_remove(ApiGroupEnum.CERT_API, AuthCodeConst.cert_remove, "删除用户证书"),
|
|
||||||
|
|
||||||
|
asym_enc(ApiGroupEnum.ASYM_API,"asym_enc", "非对称加密"),
|
||||||
|
asym_dec(ApiGroupEnum.ASYM_API,"asym_dec", "非对称解密"),
|
||||||
|
sign_raw(ApiGroupEnum.ASYM_API,"sign_raw", "RAW签名"),
|
||||||
|
verify_raw(ApiGroupEnum.ASYM_API,"verify_raw", "RAW验签"),
|
||||||
|
sign_p1(ApiGroupEnum.ASYM_API,"sign_p1", "P1签名"),
|
||||||
|
verify_p1(ApiGroupEnum.ASYM_API,"verify_p1", "P1验签"),
|
||||||
|
sign_P7Attach(ApiGroupEnum.ASYM_API,"sign_P7Attach", "P7 Attach签名"),
|
||||||
|
verify_P7Attach(ApiGroupEnum.ASYM_API,"verify_P7Attach", "P7 Attach验签"),
|
||||||
|
sign_P7Detach(ApiGroupEnum.ASYM_API,"sign_P7Detach", "P7 Detach签名"),
|
||||||
|
verify_P7Detach(ApiGroupEnum.ASYM_API,"verify_P7Detach", "P7 Detach验签"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final ApiGroupEnum group;
|
private final ApiGroupEnum group;
|
||||||
|
|||||||
@@ -14,11 +14,8 @@ import java.util.Objects;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum ApiGroupEnum {
|
public enum ApiGroupEnum {
|
||||||
|
|
||||||
KEY_MANAGE_API("key_manage_api", "密钥管理接口"),
|
|
||||||
SYM_API("sym_api", "对称密钥计算接口"),
|
SYM_API("sym_api", "对称密钥计算接口"),
|
||||||
ASYM_API("asym_api", "非对称密钥计算接口"),
|
ASYM_API("asym_api", "非对称密钥计算接口"),
|
||||||
HASH_API("hash_api", "杂凑计算接口"),
|
|
||||||
CERT_API("cert_api", "证书接口"),
|
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String code;
|
private final String code;
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
package com.sunyard.chsm.enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/7
|
|
||||||
*/
|
|
||||||
public enum DeviceTmkStatus {
|
|
||||||
|
|
||||||
device_error,
|
|
||||||
key_error,
|
|
||||||
available,
|
|
||||||
finished,
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@ import java.util.Objects;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum ManufacturerModelEnum {
|
public enum ManufacturerModelEnum {
|
||||||
|
|
||||||
enc001(ManufacturerEnum.SUNYARD, "SYD-001", "服务器密码机"),
|
enc001(ManufacturerEnum.SUNYARD, "enc001", "服务器密码机enc001"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final ManufacturerEnum manufacturer;
|
private final ManufacturerEnum manufacturer;
|
||||||
|
|||||||
+1
-3
@@ -8,15 +8,13 @@ import java.util.Objects;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据的填充模式
|
* 数据的填充模式
|
||||||
*
|
|
||||||
* @author Cheney
|
* @author Cheney
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum Padding {
|
public enum Padding {
|
||||||
NOPadding("NoPadding", "NoPadding"),
|
NOPadding("NoPadding", "NoPadding"),
|
||||||
PCKS5Padding("PKCS5Padding", "PKCS5Padding"),
|
PCKS5Padding( "PKCS5Padding", "PKCS5Padding"),
|
||||||
PCKS7Padding("PKCS7Padding", "PKCS7Padding"),
|
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String code;
|
private final String code;
|
||||||
@@ -2,8 +2,6 @@ package com.sunyard.chsm.mapper;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.sunyard.chsm.enums.KeyUsage;
|
|
||||||
import com.sunyard.chsm.model.Subject;
|
|
||||||
import com.sunyard.chsm.model.entity.AppCert;
|
import com.sunyard.chsm.model.entity.AppCert;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
@@ -30,31 +28,5 @@ public interface AppCertMapper extends BaseMapper<AppCert> {
|
|||||||
return certs.iterator().next();
|
return certs.iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
default AppCert selectSignBySubject(String dn) {
|
|
||||||
Assert.hasText(dn, "证书序列号不能为空");
|
|
||||||
String subject = Subject.fromDN(dn).getDN();
|
|
||||||
List<AppCert> certs = selectList(new LambdaQueryWrapper<AppCert>()
|
|
||||||
.eq(AppCert::getSubject, subject)
|
|
||||||
.eq(AppCert::getCertType, KeyUsage.SIGN_VERIFY.getCode())
|
|
||||||
);
|
|
||||||
if (CollectionUtils.isEmpty(certs)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return certs.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
default AppCert selectByTypeAndDn(String type,String dn) {
|
|
||||||
Assert.hasText(dn, "证书序列号不能为空");
|
|
||||||
String subject = Subject.fromDN(dn).getDN();
|
|
||||||
List<AppCert> certs = selectList(new LambdaQueryWrapper<AppCert>()
|
|
||||||
.eq(AppCert::getSubject, subject)
|
|
||||||
.eq(AppCert::getCertType, type)
|
|
||||||
);
|
|
||||||
if (CollectionUtils.isEmpty(certs)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return certs.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
package com.sunyard.chsm.mapper;
|
package com.sunyard.chsm.mapper;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.sunyard.chsm.model.entity.Application;
|
import com.sunyard.chsm.model.entity.Application;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@@ -15,15 +10,4 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface ApplicationMapper extends BaseMapper<Application> {
|
public interface ApplicationMapper extends BaseMapper<Application> {
|
||||||
|
|
||||||
|
|
||||||
default Application selectByAppKey(String appKey) {
|
|
||||||
List<Application> apps = selectList(new QueryWrapper<Application>().eq("app_key", appKey));
|
|
||||||
if (CollectionUtils.isEmpty(apps)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Assert.isTrue(apps.size() == 1, "app 数据异常");
|
|
||||||
return apps.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
package com.sunyard.chsm.mapper;
|
package com.sunyard.chsm.mapper;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.sunyard.chsm.model.entity.CryptoServiceApi;
|
import com.sunyard.chsm.model.entity.CryptoServiceApi;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@@ -15,17 +10,4 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface CryptoServiceApiMapper extends BaseMapper<CryptoServiceApi> {
|
public interface CryptoServiceApiMapper extends BaseMapper<CryptoServiceApi> {
|
||||||
|
|
||||||
default List<CryptoServiceApi> selectByServiceIds(List<Long> serviceIds) {
|
|
||||||
if (CollectionUtils.isEmpty(serviceIds)) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return selectList(
|
|
||||||
new LambdaQueryWrapper<CryptoServiceApi>()
|
|
||||||
.in(CryptoServiceApi::getCryptoServiceId, serviceIds)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
package com.sunyard.chsm.mapper;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|
||||||
import com.sunyard.chsm.model.entity.IpWhitelist;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/11/6
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface IpWhitelisttMapper extends BaseMapper<IpWhitelist> {
|
|
||||||
|
|
||||||
default List<IpWhitelist> selectByAppIds(List<Long> appIds) {
|
|
||||||
if (CollectionUtils.isEmpty(appIds)) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return selectList(
|
|
||||||
new LambdaQueryWrapper<IpWhitelist>()
|
|
||||||
.in(IpWhitelist::getAppId, appIds)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
default void deleteByAppId(Long appId) {
|
|
||||||
delete(
|
|
||||||
new LambdaQueryWrapper<IpWhitelist>()
|
|
||||||
.eq(IpWhitelist::getAppId, appId)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.sunyard.chsm.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.sunyard.chsm.model.entity.KeyInfo;
|
||||||
|
import com.sunyard.chsm.model.entity.KeyRecord;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liulu
|
||||||
|
* @since 2024/10/22
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface KeyRecordMapper extends BaseMapper<KeyRecord> {
|
||||||
|
}
|
||||||
@@ -2,8 +2,6 @@ package com.sunyard.chsm.mapper;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.sunyard.chsm.enums.DeviceTmkStatus;
|
|
||||||
import com.sunyard.chsm.model.entity.Device;
|
import com.sunyard.chsm.model.entity.Device;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@@ -16,20 +14,12 @@ import java.util.List;
|
|||||||
@Mapper
|
@Mapper
|
||||||
public interface SpDeviceMapper extends BaseMapper<Device> {
|
public interface SpDeviceMapper extends BaseMapper<Device> {
|
||||||
|
|
||||||
default Device selectOneByStatus(DeviceTmkStatus status) {
|
default List<Device> selectConnedList() {
|
||||||
Page<Device> devicePage = selectPage(
|
return selectList(
|
||||||
Page.of(1L, 1L),
|
new LambdaQueryWrapper<Device>()
|
||||||
new LambdaQueryWrapper<Device>().eq(Device::getTmkStatus, status.name())
|
.eq(Device::getConnected, true)
|
||||||
);
|
);
|
||||||
List<Device> records = devicePage.getRecords();
|
|
||||||
if (records.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return records.iterator().next();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public class R<T> {
|
|||||||
R<T> r = new R<>();
|
R<T> r = new R<>();
|
||||||
r.setSuccess(false);
|
r.setSuccess(false);
|
||||||
r.setMessage(msg);
|
r.setMessage(msg);
|
||||||
r.setCode(400);
|
r.setCode(500);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ public abstract class CertDTO {
|
|||||||
private Long id;
|
private Long id;
|
||||||
private Long applicationId;
|
private Long applicationId;
|
||||||
private String appName;
|
private String appName;
|
||||||
private Boolean single;
|
|
||||||
/**
|
/**
|
||||||
* 密钥算法
|
* 密钥算法
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.sunyard.chsm.model.dto;
|
|
||||||
|
|
||||||
import com.sunyard.chsm.enums.DeviceTmkStatus;
|
|
||||||
import com.sunyard.chsm.sdf.adapter.SdfApiAdapter;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/10
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class DeviceCheckRes {
|
|
||||||
|
|
||||||
private DeviceTmkStatus status;
|
|
||||||
private String deviceSerial;
|
|
||||||
private String pubKey;
|
|
||||||
private String encTmk;
|
|
||||||
private boolean hasError = false;
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
private SdfApiAdapter sdfApiAdapter;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ package com.sunyard.chsm.model.dto;
|
|||||||
|
|
||||||
import com.sunyard.chsm.model.PageQuery;
|
import com.sunyard.chsm.model.PageQuery;
|
||||||
import com.sunyard.chsm.model.Subject;
|
import com.sunyard.chsm.model.Subject;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@@ -20,8 +21,10 @@ public abstract class KeyInfoDTO {
|
|||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
|
@Builder
|
||||||
public static class Query extends PageQuery {
|
public static class Query extends PageQuery {
|
||||||
private Long appId;
|
private Long appId;
|
||||||
|
private Long keyId;
|
||||||
private String status;
|
private String status;
|
||||||
private String keyType;
|
private String keyType;
|
||||||
}
|
}
|
||||||
@@ -44,6 +47,10 @@ public abstract class KeyInfoDTO {
|
|||||||
private Integer genNumber;
|
private Integer genNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class KeyView {
|
public static class KeyView {
|
||||||
private Long id;
|
private Long id;
|
||||||
@@ -80,6 +87,13 @@ public abstract class KeyInfoDTO {
|
|||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public static class KeyValue extends KeyView {
|
||||||
|
private String keyData;
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class IDs {
|
public static class IDs {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ public class CryptoService {
|
|||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private String name;
|
||||||
// private Long deviceGroupId;
|
private Long deviceGroupId;
|
||||||
// private String deviceGroupName;
|
private String deviceGroupName;
|
||||||
private String status;
|
private String status;
|
||||||
private Long creatorId;
|
private Long creatorId;
|
||||||
|
|
||||||
|
|||||||
@@ -21,20 +21,16 @@ public class Device {
|
|||||||
private Integer managePort;
|
private Integer managePort;
|
||||||
private String manufacturer;
|
private String manufacturer;
|
||||||
private String manufacturerModel;
|
private String manufacturerModel;
|
||||||
private Integer encKeyIdx;
|
|
||||||
private String accessCredentials;
|
private String accessCredentials;
|
||||||
private Long groupId;
|
|
||||||
private String groupName;
|
|
||||||
private Integer weight;
|
|
||||||
|
|
||||||
private String tmkStatus;
|
|
||||||
private String deviceSerial;
|
|
||||||
private String pubKey;
|
|
||||||
private String encTmk;
|
|
||||||
private Boolean connected;
|
private Boolean connected;
|
||||||
private LocalDateTime lastCheckTime;
|
private LocalDateTime lastCheckTime;
|
||||||
private LocalDateTime lastConnectedTime;
|
private LocalDateTime lastConnectedTime;
|
||||||
|
|
||||||
|
private Long groupId;
|
||||||
|
private String groupName;
|
||||||
|
private Integer weight;
|
||||||
|
|
||||||
private String remark;
|
private String remark;
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
private LocalDateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
package com.sunyard.chsm.model.entity;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/11/22
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@TableName("sp_ip_whitelist")
|
|
||||||
public class IpWhitelist {
|
|
||||||
|
|
||||||
private Long id;
|
|
||||||
private Long appId;
|
|
||||||
private String ip;
|
|
||||||
private String scope;
|
|
||||||
private String status;
|
|
||||||
|
|
||||||
private String creator;
|
|
||||||
private String remark;
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
private LocalDateTime updateTime;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.sunyard.chsm.sdf;
|
package com.sunyard.chsm.sdf;
|
||||||
|
|
||||||
|
import com.sunyard.chsm.enums.AlgMode;
|
||||||
import com.sunyard.chsm.enums.KeyAlg;
|
import com.sunyard.chsm.enums.KeyAlg;
|
||||||
|
import com.sunyard.chsm.enums.Padding;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -14,7 +16,7 @@ import static com.sunyard.chsm.utils.gm.BCSM4Utils.DEFAULT_KEY_SIZE;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractSdfApiService implements SdfApiService {
|
public abstract class AbstractSdfApiService implements SdfApiService {
|
||||||
|
|
||||||
private static final Map<KeyAlg, Integer> algKeyLen = new HashMap<>();
|
protected static final Map<KeyAlg, Integer> algKeyLen = new HashMap<>();
|
||||||
static {
|
static {
|
||||||
algKeyLen.put( KeyAlg.SM4, DEFAULT_KEY_SIZE );
|
algKeyLen.put( KeyAlg.SM4, DEFAULT_KEY_SIZE );
|
||||||
}
|
}
|
||||||
@@ -25,10 +27,10 @@ public abstract class AbstractSdfApiService implements SdfApiService {
|
|||||||
* 密钥长度根据 alg 指定的算法自动选择。
|
* 密钥长度根据 alg 指定的算法自动选择。
|
||||||
* @return 密钥
|
* @return 密钥
|
||||||
*/
|
*/
|
||||||
// @Override
|
@Override
|
||||||
// public byte[] genSymKey(KeyAlg alg) {
|
public byte[] genSymKey(KeyAlg alg) {
|
||||||
// return genSymKey( alg, algKeyLen.get( alg ) );
|
return genSymKey( alg, algKeyLen.get( alg ) );
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,11 +40,15 @@ public abstract class AbstractSdfApiService implements SdfApiService {
|
|||||||
* @param key 密钥值,明文
|
* @param key 密钥值,明文
|
||||||
* @param data 原始数据
|
* @param data 原始数据
|
||||||
*/
|
*/
|
||||||
// @Override
|
@Override
|
||||||
// public byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data){
|
public byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data){
|
||||||
// return symEncrypt( alg, AlgMode.ECB, Padding.PCKS5Padding, key, data );
|
return symEncrypt( alg, AlgMode.ECB, Padding.PCKS5Padding, key, null, data );
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] symEncrypt(KeyAlg alg, AlgMode mode, byte[] key, byte[] iv, byte[] data) {
|
||||||
|
return symEncrypt( alg, mode, Padding.PCKS5Padding, key, iv, data );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对称解密
|
* 对称解密
|
||||||
@@ -51,9 +57,13 @@ public abstract class AbstractSdfApiService implements SdfApiService {
|
|||||||
* @param key 密钥值,明文
|
* @param key 密钥值,明文
|
||||||
* @param data 密文数据
|
* @param data 密文数据
|
||||||
*/
|
*/
|
||||||
// @Override
|
@Override
|
||||||
// public byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data) {
|
public byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data) {
|
||||||
// return symDecrypt( alg, AlgMode.ECB, Padding.PCKS5Padding, key, data );
|
return symDecrypt( alg, AlgMode.ECB, Padding.PCKS5Padding, key,null, data );
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] symDecrypt(KeyAlg alg, AlgMode mode, byte[] key, byte[] iv, byte[] data) {
|
||||||
|
return symDecrypt( alg, mode, Padding.PCKS5Padding, key, iv, data );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,186 +1,187 @@
|
|||||||
//package com.sunyard.chsm.sdf;
|
package com.sunyard.chsm.sdf;
|
||||||
//
|
|
||||||
//
|
|
||||||
//import com.sunyard.chsm.enums.AlgMode;
|
import com.sunyard.chsm.enums.AlgMode;
|
||||||
//import com.sunyard.chsm.enums.KeyAlg;
|
import com.sunyard.chsm.enums.KeyAlg;
|
||||||
//import com.sunyard.chsm.enums.KeyCategory;
|
import com.sunyard.chsm.enums.KeyCategory;
|
||||||
//import com.sunyard.chsm.enums.Padding;
|
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.model.EccKey;
|
import com.sunyard.chsm.sdf.util.LangUtils;
|
||||||
//import com.sunyard.chsm.sdf.util.LangUtils;
|
import com.sunyard.chsm.utils.gm.BCSM2Utils;
|
||||||
//import com.sunyard.chsm.utils.gm.BCSM2Utils;
|
import com.sunyard.chsm.utils.gm.BCSM3Utils;
|
||||||
//import com.sunyard.chsm.utils.gm.BCSM3Utils;
|
import com.sunyard.chsm.utils.gm.BCSM4Utils;
|
||||||
//import com.sunyard.chsm.utils.gm.BCSM4Utils;
|
import lombok.SneakyThrows;
|
||||||
//import lombok.SneakyThrows;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
//import lombok.extern.slf4j.Slf4j;
|
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
||||||
//import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
||||||
//import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
import org.bouncycastle.util.BigIntegers;
|
||||||
//import org.bouncycastle.util.BigIntegers;
|
import org.springframework.stereotype.Service;
|
||||||
//import org.springframework.stereotype.Service;
|
|
||||||
//
|
import javax.crypto.BadPaddingException;
|
||||||
//import javax.crypto.BadPaddingException;
|
import javax.crypto.Cipher;
|
||||||
//import javax.crypto.Cipher;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
//import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.NoSuchPaddingException;
|
||||||
//import javax.crypto.NoSuchPaddingException;
|
import java.security.*;
|
||||||
//import java.security.InvalidKeyException;
|
|
||||||
//import java.security.KeyPair;
|
|
||||||
//import java.security.NoSuchAlgorithmException;
|
/**
|
||||||
//import java.security.NoSuchProviderException;
|
* 基于 BC 库的国密软算法实现
|
||||||
//import java.security.SecureRandom;
|
* 当前实现类的接口返回的对称密钥和私钥认为是明文,在上层 Service 进行使用和存储时的加密和解密运算。
|
||||||
//
|
* <p>
|
||||||
//
|
* 主密钥:
|
||||||
///**
|
* - 生成。 软随机数。项目启动时不存在则自动生成。
|
||||||
// * 基于 BC 库的国密软算法实现
|
* - 存储。 存储在 SC_PARAM_CONF 表, KEY 为 mk 的字段,值为固定的 48 字节,以 HEX 格式 96 字节存储。
|
||||||
// * 当前实现类的接口返回的对称密钥和私钥认为是明文,在上层 Service 进行使用和存储时的加密和解密运算。
|
* 前 16 字节为主密钥值,后 32 字节为主密钥值使用 SM3 计算的校验值。
|
||||||
// * <p>
|
* - 同步。基于数据库进行导入、导出、和备份、恢复。多台应用服务器连接同一个数据库,无需同步。
|
||||||
// * 主密钥:
|
* - 使用。顶层密钥,用于保护其他存于数据的密钥。
|
||||||
// * - 生成。 软随机数。项目启动时不存在则自动生成。
|
*
|
||||||
// * - 存储。 存储在 SC_PARAM_CONF 表, KEY 为 mk 的字段,值为固定的 48 字节,以 HEX 格式 96 字节存储。
|
* @author liulu 、Cheney
|
||||||
// * 前 16 字节为主密钥值,后 32 字节为主密钥值使用 SM3 计算的校验值。
|
* @since 2024/10/23
|
||||||
// * - 同步。基于数据库进行导入、导出、和备份、恢复。多台应用服务器连接同一个数据库,无需同步。
|
*/
|
||||||
// * - 使用。顶层密钥,用于保护其他存于数据的密钥。
|
@Slf4j
|
||||||
// *
|
@Service
|
||||||
// * @author liulu 、Cheney
|
public class BCSdfApiService extends AbstractSdfApiService {
|
||||||
// * @since 2024/10/23
|
|
||||||
// */
|
public BCSdfApiService() {
|
||||||
//@Slf4j
|
super();
|
||||||
//@Service
|
}
|
||||||
//public class BCSdfApiService extends AbstractSdfApiService {
|
|
||||||
//
|
@Override
|
||||||
// public BCSdfApiService() {
|
public byte[] generateRandom(int len) {
|
||||||
// super();
|
byte[] res = new byte[len];
|
||||||
// }
|
new SecureRandom().nextBytes(res);
|
||||||
//
|
return res;
|
||||||
// @Override
|
}
|
||||||
// public byte[] generateRandom(int len) {
|
|
||||||
// byte[] res = new byte[len];
|
|
||||||
// new SecureRandom().nextBytes(res);
|
/**
|
||||||
// return res;
|
* 生成对称算法密钥
|
||||||
// }
|
*
|
||||||
//
|
* @param alg 算法,只支持对称算法
|
||||||
//
|
* @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。
|
||||||
// /**
|
* 禁止传 null
|
||||||
// * 生成对称算法密钥
|
* @return
|
||||||
// *
|
*/
|
||||||
// * @param alg 算法,只支持对称算法
|
@Override
|
||||||
// * @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。
|
public byte[] genSymKey(KeyAlg alg, Integer keyLen) {
|
||||||
// * 禁止传 null
|
switch (alg) {
|
||||||
// * @return
|
case SM4: {
|
||||||
// */
|
if (null == keyLen || keyLen != BCSM4Utils.DEFAULT_KEY_SIZE) {
|
||||||
// @Override
|
throw new IllegalArgumentException("Invalid key length: " + keyLen);
|
||||||
// public byte[] genSymKey(KeyAlg alg, Integer keyLen) {
|
}
|
||||||
// switch (alg) {
|
try {
|
||||||
// case SM4: {
|
return BCSM4Utils.generateKey();
|
||||||
// if (null == keyLen || keyLen != BCSM4Utils.DEFAULT_KEY_SIZE) {
|
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||||
// throw new IllegalArgumentException("Invalid key length: " + keyLen);
|
throw new RuntimeException("算法实现错误", e);
|
||||||
// }
|
}
|
||||||
// try {
|
}
|
||||||
// return BCSM4Utils.generateKey();
|
default: {
|
||||||
// } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
throw new IllegalArgumentException("Unsupported algorithm: " + alg);
|
||||||
// throw new RuntimeException("算法实现错误", e);
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// default: {
|
|
||||||
// throw new IllegalArgumentException("Unsupported algorithm: " + alg);
|
|
||||||
// }
|
@Override
|
||||||
// }
|
public byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] iv, byte[] data) {
|
||||||
// }
|
return symCalc(Cipher.ENCRYPT_MODE, alg, mode, padding, key, iv, data);
|
||||||
//
|
}
|
||||||
// @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[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] iv, byte[] data) {
|
||||||
//
|
return symCalc(Cipher.DECRYPT_MODE, alg, mode, padding, key, iv, data);
|
||||||
// @Override
|
}
|
||||||
// public byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) {
|
|
||||||
// return new byte[0];
|
|
||||||
// }
|
/**
|
||||||
//
|
* 对称加解密的统一实现
|
||||||
//
|
*
|
||||||
// @Override
|
* @param alg 算法,只支持对称算法
|
||||||
// public byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
|
* @param key 密钥值,明文
|
||||||
// return symCalc(Cipher.DECRYPT_MODE, alg, mode, padding, key, data);
|
* @param data 加密时明文数据,解密时为密文数据
|
||||||
// }
|
*/
|
||||||
//
|
private byte[] symCalc(int cipherMode, KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] iv, byte[] data) {
|
||||||
// @Override
|
// 只支持对称算法
|
||||||
// public byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) {
|
if (alg.getCategory() != KeyCategory.SYM_KEY) {
|
||||||
// return new byte[0];
|
throw new IllegalArgumentException("Must SYM_KEY, unsupported algorithm: " + alg);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
//
|
// 算法
|
||||||
// /**
|
String algName = null;
|
||||||
// * 对称加解密的统一实现
|
if (alg == KeyAlg.SM4) {
|
||||||
// *
|
algName = "SM4/";
|
||||||
// * @param alg 算法,只支持对称算法
|
} else {
|
||||||
// * @param key 密钥值,明文
|
throw new IllegalArgumentException("Unsupported algorithm: " + alg);
|
||||||
// * @param data 加密时明文数据,解密时为密文数据
|
}
|
||||||
// */
|
|
||||||
// private byte[] symCalc(int cipherMode, KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
|
// 算法轮模式
|
||||||
// if (alg.getCategory() != KeyCategory.SYM_KEY) {
|
algName += mode.getCode() + "/";
|
||||||
// throw new IllegalArgumentException("Must SYM_KEY, unsupported algorithm: " + alg);
|
|
||||||
// }
|
// 填充模式
|
||||||
//
|
algName += padding.getCode();
|
||||||
// // 算法
|
|
||||||
// String algName = null;
|
|
||||||
// if (alg == KeyAlg.SM4) {
|
Cipher cipher = null;
|
||||||
// algName = "SM4/";
|
try {
|
||||||
// } else {
|
if ( mode == AlgMode.ECB ) {
|
||||||
// throw new IllegalArgumentException("Unsupported algorithm: " + alg);
|
cipher = BCSM4Utils.generateECBCipher(algName, cipherMode, key);
|
||||||
// }
|
} else {
|
||||||
//
|
// iv 检查
|
||||||
// // 算法轮模式
|
if ( null == iv ) {
|
||||||
// algName += mode.getCode() + "/";
|
throw new IllegalArgumentException("Current Mode "+ mode.getCode() + " Unsupported IV is null");
|
||||||
//
|
}
|
||||||
// // 填充模式
|
if ( iv.length * 8 != algKeyLen.get(alg) ) {
|
||||||
// algName += padding.getCode();
|
throw new IllegalArgumentException("Current Alg "+ alg.getCode() + " Unsupported IV length: " + iv.length);
|
||||||
//
|
}
|
||||||
//
|
cipher = BCSM4Utils.generateCipher(algName, cipherMode, key, iv);
|
||||||
// Cipher cipher = null;
|
}
|
||||||
// try {
|
|
||||||
// cipher = BCSM4Utils.generateECBCipher(algName, cipherMode, key);
|
return cipher.doFinal(data);
|
||||||
// return cipher.doFinal(data);
|
} catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchProviderException |
|
||||||
// } catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException e) {
|
NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||||
// throw new RuntimeException("算法执行错误", e);
|
throw new RuntimeException("算法执行错误", e);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @SneakyThrows
|
|
||||||
// @Override
|
@SneakyThrows
|
||||||
// public EccKey genKeyPairEcc() {
|
@Override
|
||||||
// // 生成密钥对
|
public EccKey genKeyPairEcc() {
|
||||||
// KeyPair keyPair = BCSM2Utils.generateKeyPair();
|
// 生成密钥对
|
||||||
// BCECPublicKey pubKey = (BCECPublicKey) keyPair.getPublic();
|
KeyPair keyPair = BCSM2Utils.generateKeyPair();
|
||||||
// BCECPrivateKey priKey = (BCECPrivateKey) keyPair.getPrivate();
|
BCECPublicKey pubKey = (BCECPublicKey) keyPair.getPublic();
|
||||||
// byte[] x = pubKey.getQ().getXCoord().getEncoded();
|
BCECPrivateKey priKey = (BCECPrivateKey) keyPair.getPrivate();
|
||||||
// byte[] y = pubKey.getQ().getYCoord().getEncoded();
|
byte[] x = pubKey.getQ().getXCoord().getEncoded();
|
||||||
// byte[] d = BigIntegers.asUnsignedByteArray(32, priKey.getD());
|
byte[] y = pubKey.getQ().getYCoord().getEncoded();
|
||||||
// return new EccKey(LangUtils.merge(x, y), d);
|
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) {
|
@Override
|
||||||
// return new byte[0];
|
public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) {
|
||||||
// }
|
return new byte[0];
|
||||||
//
|
}
|
||||||
// @Override
|
|
||||||
// public byte[] hmac(byte[] key, byte[] srcData) {
|
@Override
|
||||||
// return BCSM3Utils.hmac(key, srcData);
|
public byte[] hmac(byte[] key, byte[] srcData) {
|
||||||
// }
|
return BCSM3Utils.hmac(key, srcData);
|
||||||
//
|
}
|
||||||
// @Override
|
|
||||||
// public byte[] hash(byte[] pucData) {
|
@Override
|
||||||
// return BCSM3Utils.hash(pucData);
|
public byte[] hash(byte[] pucData) {
|
||||||
// }
|
return BCSM3Utils.hash(pucData);
|
||||||
//
|
}
|
||||||
// @Override
|
|
||||||
// public byte[] encryptByTMK(byte[] data) {
|
@Override
|
||||||
// return data;
|
public byte[] encryptByTMK(byte[] data) {
|
||||||
// }
|
return data;
|
||||||
//
|
}
|
||||||
// @Override
|
|
||||||
// public byte[] decryptByTMK(byte[] data) {
|
@Override
|
||||||
// return data;
|
public byte[] decryptByTMK(byte[] data) {
|
||||||
// }
|
return data;
|
||||||
//
|
}
|
||||||
//}
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package com.sunyard.chsm.sdf;
|
package com.sunyard.chsm.sdf;
|
||||||
|
|
||||||
|
|
||||||
|
import com.sunyard.chsm.enums.AlgMode;
|
||||||
|
import com.sunyard.chsm.enums.KeyAlg;
|
||||||
import com.sunyard.chsm.enums.Padding;
|
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;
|
import com.sunyard.chsm.sdf.model.EccKey;
|
||||||
import com.sunyard.chsm.sdf.model.EccSignature;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,47 +23,44 @@ public interface SdfApiService {
|
|||||||
byte[] generateRandom(int len);
|
byte[] generateRandom(int len);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成对称密钥
|
* 生成对称密钥
|
||||||
*
|
|
||||||
* @param alg 算法,只支持对称算法
|
* @param alg 算法,只支持对称算法
|
||||||
* @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。
|
* @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。
|
||||||
* 禁止传 null
|
* 禁止传 null
|
||||||
* @return 对称密钥
|
* @return 对称密钥
|
||||||
*/
|
*/
|
||||||
// byte[] genSymKey(KeyAlg alg, Integer keyLen);
|
byte[] genSymKey(KeyAlg alg, Integer keyLen);
|
||||||
//
|
byte[] genSymKey(KeyAlg alg);
|
||||||
// byte[] genSymKey(KeyAlg alg);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对称加密
|
* 对称加密
|
||||||
*
|
|
||||||
* @param alg 算法,只支持对称算法
|
* @param alg 算法,只支持对称算法
|
||||||
* @param padding
|
* @param mode 轮模式
|
||||||
|
* @param padding 填充模式
|
||||||
* @param key 密钥值,明文
|
* @param key 密钥值,明文
|
||||||
* @param data 原始数据
|
* @param data 原始数据
|
||||||
*/
|
*/
|
||||||
// byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data);
|
byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] iv, byte[] data);
|
||||||
//
|
byte[] symEncrypt(KeyAlg alg, AlgMode mode, byte[] key, byte[] iv, byte[] data);
|
||||||
// byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data);
|
byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data);
|
||||||
|
|
||||||
byte[] symEncrypt(AlgId alg, Padding padding, byte[] key, byte[] iv, byte[] data);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对称解密
|
* 对称解密
|
||||||
*
|
|
||||||
* @param mode 轮模式
|
|
||||||
* @param alg 算法,只支持对称算法
|
* @param alg 算法,只支持对称算法
|
||||||
* @param padding 填充模式
|
|
||||||
* @param key 密钥值,明文
|
* @param key 密钥值,明文
|
||||||
|
* @param mode 轮模式
|
||||||
|
* @param padding 填充模式
|
||||||
* @param data 密文数据
|
* @param data 密文数据
|
||||||
*/
|
*/
|
||||||
// byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data);
|
byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] iv, byte[] data);
|
||||||
//
|
byte[] symDecrypt(KeyAlg alg, AlgMode mode, byte[] key, byte[] iv, byte[] data);
|
||||||
// byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data);
|
byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data);
|
||||||
|
|
||||||
|
|
||||||
byte[] symDecrypt(AlgId alg, Padding padding, byte[] key, byte[] iv, byte[] data);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,61 +70,15 @@ public interface SdfApiService {
|
|||||||
*/
|
*/
|
||||||
EccKey genKeyPairEcc();
|
EccKey genKeyPairEcc();
|
||||||
|
|
||||||
/**
|
|
||||||
* 外部密钥ECC签名
|
|
||||||
*
|
|
||||||
* @param privateKey ECC私钥
|
|
||||||
* @param pucData 缓冲区指针,用于存放外部输入的数据
|
|
||||||
* @param userId 签名者id
|
|
||||||
* @return pucSignature 返回签名值数据
|
|
||||||
*/
|
|
||||||
EccSignature externalSignWithIdECC(byte[] privateKey, byte[] pucData, byte[] userId);
|
|
||||||
|
|
||||||
EccSignature externalSignECC(byte[] privateKey, byte[] pucData);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 外部密钥ECC验证
|
|
||||||
*
|
|
||||||
* @param publicKey ECC公钥
|
|
||||||
* @param pubData 原文
|
|
||||||
* @param userId 签名者id
|
|
||||||
* @param signData 外部签名数据
|
|
||||||
* @return 0 成功; 非0 失败,返回错误代码
|
|
||||||
*/
|
|
||||||
boolean externalVerifyWithIdECC(byte[] publicKey, byte[] pubData, byte[] signData, byte[] userId);
|
|
||||||
|
|
||||||
boolean externalVerifyECC(byte[] publicKey, byte[] pubData, byte[] signData);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 外部密钥ECC公钥加密
|
|
||||||
*
|
|
||||||
* @param publicKey 外部ECC公钥结构
|
|
||||||
* @param pucData 缓冲区指针,用于存放外部输入的数据
|
|
||||||
* @return pucEncData 返回数据密文
|
|
||||||
*/
|
|
||||||
EccCipher externalEncryptECC(byte[] publicKey, byte[] pucData);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 外部密钥ECC私钥解密
|
|
||||||
*
|
|
||||||
* @param privateKey 外部ECC私钥结构
|
|
||||||
* @param encData 缓冲区指针,用于存放输入的数据密文
|
|
||||||
* @return pucData 返回数据明文
|
|
||||||
*/
|
|
||||||
byte[] externalDecryptECC(byte[] privateKey, byte[] encData);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算MAC
|
* 计算MAC
|
||||||
*
|
*
|
||||||
* @param algId algId
|
|
||||||
* @param padding padding
|
|
||||||
* @param symKey 用户指定的密钥
|
* @param symKey 用户指定的密钥
|
||||||
* @param pucIv 缓冲区指针,用于存放输入和返回的IV数据
|
* @param pucIv 缓冲区指针,用于存放输入和返回的IV数据
|
||||||
* @param pucData 缓冲区指针,用于存放输入的数据明文
|
* @param pucData 缓冲区指针,用于存放输入的数据明文
|
||||||
* @return pucEncData 返回MAC值 | puiLength 返回MAC值长度
|
* @return pucEncData 返回MAC值 | puiLength 返回MAC值长度
|
||||||
*/
|
*/
|
||||||
byte[] calculateMAC(AlgId algId, Padding padding, byte[] symKey, byte[] pucIv, byte[] pucData);
|
byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData);
|
||||||
|
|
||||||
byte[] hmac(byte[] key, byte[] srcData);
|
byte[] hmac(byte[] key, byte[] srcData);
|
||||||
|
|
||||||
@@ -136,12 +86,8 @@ public interface SdfApiService {
|
|||||||
* 杂凑运算
|
* 杂凑运算
|
||||||
*
|
*
|
||||||
* @param pucData 缓冲区指针,用于存放输入的数据明文
|
* @param pucData 缓冲区指针,用于存放输入的数据明文
|
||||||
* @param pubKey 执行预处理的公钥
|
|
||||||
* @param userId 执行预处理的userId
|
|
||||||
* @return hash值
|
* @return hash值
|
||||||
*/
|
*/
|
||||||
byte[] hash(byte[] pucData, byte[] pubKey, byte[] userId);
|
|
||||||
|
|
||||||
byte[] hash(byte[] pucData);
|
byte[] hash(byte[] pucData);
|
||||||
|
|
||||||
byte[] encryptByTMK(byte[] data);
|
byte[] encryptByTMK(byte[] data);
|
||||||
|
|||||||
@@ -1,36 +1,22 @@
|
|||||||
package com.sunyard.chsm.sdf.adapter;
|
package com.sunyard.chsm.sdf.adapter;
|
||||||
|
|
||||||
import com.sunyard.chsm.sdf.context.AlgId;
|
|
||||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
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.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.LangUtils;
|
import com.sunyard.chsm.sdf.util.LangUtils;
|
||||||
import com.sunyard.chsm.utils.gm.BCECUtils;
|
import com.sunyard.chsm.utils.gm.BCECUtils;
|
||||||
import com.sunyard.chsm.utils.gm.BCSM2Utils;
|
import com.sunyard.chsm.utils.gm.BCSM2Utils;
|
||||||
import com.sunyard.chsm.utils.gm.BCSM4Utils;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.bouncycastle.crypto.InvalidCipherTextException;
|
import org.bouncycastle.crypto.InvalidCipherTextException;
|
||||||
import org.bouncycastle.crypto.digests.SM3Digest;
|
|
||||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
|
||||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
|
||||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
||||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
||||||
import org.bouncycastle.math.ec.ECPoint;
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
|
import org.bouncycastle.util.Arrays;
|
||||||
import org.bouncycastle.util.BigIntegers;
|
import org.bouncycastle.util.BigIntegers;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@@ -38,7 +24,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
*/
|
*/
|
||||||
public class BcSdfApiAdaptor implements SdfApiAdapter {
|
public class BcSdfApiAdaptor implements SdfApiAdapter {
|
||||||
|
|
||||||
protected static final Map<String, byte[]> KEY_HANDLE_CONTEXT = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private static final DeviceInfo deviceInfo;
|
private static final DeviceInfo deviceInfo;
|
||||||
|
|
||||||
@@ -54,8 +39,6 @@ public class BcSdfApiAdaptor implements SdfApiAdapter {
|
|||||||
deviceInfo.setHashAlgAbility(7010608454676760881L);
|
deviceInfo.setHashAlgAbility(7010608454676760881L);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final BcSdfApiAdaptor INSTANCE = new BcSdfApiAdaptor();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String openDevice() {
|
public String openDevice() {
|
||||||
return "c95a78d9c04a557b7b46dbcb5f36cc66";
|
return "c95a78d9c04a557b7b46dbcb5f36cc66";
|
||||||
@@ -68,7 +51,7 @@ public class BcSdfApiAdaptor implements SdfApiAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String openSession(String deviceHandle) {
|
public String openSession(String deviceHandle) {
|
||||||
return UUID.randomUUID().toString();
|
return "6975feaffaa35b31b6d4e4555ac403a1";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -89,10 +72,10 @@ public class BcSdfApiAdaptor implements SdfApiAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) {
|
public byte[] exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) {
|
||||||
BigInteger d = new BigInteger(1, getD());
|
BigInteger d = new BigInteger(1, getD());
|
||||||
ECPoint q = BCSM2Utils.G_POINT.multiply(d).normalize();
|
ECPoint q = BCSM2Utils.G_POINT.multiply(d).normalize();
|
||||||
return new EccPubKey(256, q.getXCoord().getEncoded(), q.getYCoord().getEncoded());
|
return LangUtils.merge(q.getXCoord().getEncoded(), q.getYCoord().getEncoded());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getD() {
|
private byte[] getD() {
|
||||||
@@ -104,7 +87,7 @@ public class BcSdfApiAdaptor implements SdfApiAdapter {
|
|||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@Override
|
@Override
|
||||||
public EccKey generateKeyPairECC(String sessionHandle, AlgId alg) {
|
public EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits) {
|
||||||
// 生成密钥对
|
// 生成密钥对
|
||||||
KeyPair keyPair = BCSM2Utils.generateKeyPair();
|
KeyPair keyPair = BCSM2Utils.generateKeyPair();
|
||||||
BCECPublicKey pubKey = (BCECPublicKey) keyPair.getPublic();
|
BCECPublicKey pubKey = (BCECPublicKey) keyPair.getPublic();
|
||||||
@@ -116,203 +99,26 @@ public class BcSdfApiAdaptor implements SdfApiAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getPrivateKeyAccessRight(String hSessionHandle, int uiKeyIndex, byte[] pucPassword) {
|
public byte[] exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, byte[] pubKey, byte[] pucEncDateIn) {
|
||||||
return true;
|
return new byte[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EccCipher exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, EccPubKey pubKey, EccCipher pucEncDateIn) {
|
public byte[] externalEncryptECC(String sessionHandle, byte[] pubKey, byte[] pucData) {
|
||||||
|
if (pubKey[0] == 4) {
|
||||||
ECPublicKeyParameters pub = BCECUtils.createECPublicKeyParameters(pubKey.getX(), pubKey.getY());
|
pubKey = Arrays.copyOfRange(pubKey, 1, 65);
|
||||||
ECPrivateKeyParameters pri = BCECUtils.createECPrivateKeyParameters(getD());
|
}
|
||||||
|
ECPublicKeyParameters parameters = BCECUtils.createECPublicKeyParameters(
|
||||||
|
Arrays.copyOfRange(pubKey, 0, 32),
|
||||||
|
Arrays.copyOfRange(pubKey, 32, 64)
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
byte[] k = BCSM2Utils.decrypt(pri, LangUtils.merge(new byte[]{0x04}, pucEncDateIn.getC1C3C2Bytes()));
|
byte[] encrypt = BCSM2Utils.encrypt(parameters, pucData);
|
||||||
byte[] encrypt = BCSM2Utils.encrypt(pub, k);
|
return Arrays.copyOfRange(encrypt, 1, encrypt.length);
|
||||||
return EccCipher.fromBytes(encrypt);
|
|
||||||
} catch (InvalidCipherTextException e) {
|
} catch (InvalidCipherTextException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final SecureRandom RANDOM = new SecureRandom();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EccSignature externalSignECC(String sessionHandle, EccPriKey privateKey, byte[] pucData) {
|
|
||||||
ECPrivateKeyParameters pri = BCECUtils.createECPrivateKeyParameters(privateKey.getD());
|
|
||||||
|
|
||||||
BigInteger n = pri.getParameters().getN();
|
|
||||||
BigInteger d = pri.getD();
|
|
||||||
|
|
||||||
BigInteger e = new BigInteger(1, pucData);
|
|
||||||
BigInteger r, s = null;
|
|
||||||
|
|
||||||
do {
|
|
||||||
BigInteger k;
|
|
||||||
do {
|
|
||||||
k = new BigInteger(n.bitLength(), RANDOM);
|
|
||||||
} while (k.compareTo(BigInteger.ONE) < 0 || k.compareTo(n) >= 0);
|
|
||||||
|
|
||||||
ECPoint kG = pri.getParameters().getG().multiply(k).normalize();
|
|
||||||
BigInteger x1 = kG.getAffineXCoord().toBigInteger();
|
|
||||||
|
|
||||||
r = e.add(x1).mod(n);
|
|
||||||
|
|
||||||
if (r.equals(BigInteger.ZERO) || r.add(k).equals(n)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BigInteger dPlus1Inv = d.add(BigInteger.ONE).modInverse(n);
|
|
||||||
s = dPlus1Inv.multiply(k.subtract(r.multiply(d))).mod(n);
|
|
||||||
|
|
||||||
} while (Objects.equals(s, BigInteger.ZERO));
|
|
||||||
return new EccSignature(BigIntegers.asUnsignedByteArray(32, r),
|
|
||||||
BigIntegers.asUnsignedByteArray(32, s));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean externalVerifyECC(String sessionHandle, EccPubKey publicKey, byte[] pucData, EccSignature pucSignature) {
|
|
||||||
ECPublicKeyParameters pub = BCECUtils.createECPublicKeyParameters(publicKey.getX(), publicKey.getY());
|
|
||||||
if (pucData.length != 32) {
|
|
||||||
throw new IllegalArgumentException("Hash length must be 32 bytes");
|
|
||||||
}
|
|
||||||
ECDomainParameters domainParams = pub.getParameters();
|
|
||||||
ECPoint G = domainParams.getG();
|
|
||||||
BigInteger n = domainParams.getN();
|
|
||||||
ECPoint Q = pub.getQ();
|
|
||||||
BigInteger e = new BigInteger(1, pucData);
|
|
||||||
|
|
||||||
BigInteger r = new BigInteger(1, pucSignature.getR());
|
|
||||||
BigInteger s = new BigInteger(1, pucSignature.getS());
|
|
||||||
if (r.compareTo(BigIntegers.ONE) < 0 || r.compareTo(n) >= 0 || s.compareTo(BigIntegers.ONE) < 0 || s.compareTo(n) >= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BigInteger t = r.add(s).mod(n);
|
|
||||||
if (t.equals(BigInteger.ZERO)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ECPoint point = G.multiply(s).add(Q.multiply(t)).normalize();
|
|
||||||
|
|
||||||
BigInteger R = e.add(point.getAffineXCoord().toBigInteger()).mod(n);
|
|
||||||
|
|
||||||
return R.equals(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EccCipher externalEncryptECC(String sessionHandle, EccPubKey pubKey, byte[] pucData) {
|
|
||||||
ECPublicKeyParameters pub = BCECUtils.createECPublicKeyParameters(pubKey.getX(), pubKey.getY());
|
|
||||||
try {
|
|
||||||
byte[] encrypt = BCSM2Utils.encrypt(pub, pucData);
|
|
||||||
return EccCipher.fromBytes(encrypt);
|
|
||||||
} catch (InvalidCipherTextException e) {
|
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] externalDecryptECC(String sessionHandle, EccPriKey pucPrivateKeyEcc, EccCipher pucEncData) {
|
|
||||||
ECPrivateKeyParameters pri = BCECUtils.createECPrivateKeyParameters(pucPrivateKeyEcc.getD());
|
|
||||||
try {
|
|
||||||
return BCSM2Utils.decrypt(pri, LangUtils.merge(new byte[]{0x04}, pucEncData.getC1C3C2Bytes()));
|
|
||||||
} catch (InvalidCipherTextException e) {
|
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String importKeyWithISKECC(String sessionHandle, int uiIskIndex, EccCipher eccCipher) {
|
|
||||||
ECPrivateKeyParameters pri = BCECUtils.createECPrivateKeyParameters(getD());
|
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] pucKey = BCSM2Utils.decrypt(pri, LangUtils.merge(new byte[]{0x04}, eccCipher.getC1C3C2Bytes()));
|
|
||||||
Assert.isTrue(pucKey.length == 16, "密钥长度错误");
|
|
||||||
String key = UUID.randomUUID().toString();
|
|
||||||
KEY_HANDLE_CONTEXT.put(key, pucKey);
|
|
||||||
return key;
|
|
||||||
} catch (InvalidCipherTextException e) {
|
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String importKey(String sessionHandle, byte[] pucKey) {
|
|
||||||
Assert.isTrue(pucKey.length == 16, "密钥长度错误");
|
|
||||||
String key = UUID.randomUUID().toString();
|
|
||||||
KEY_HANDLE_CONTEXT.put(key, pucKey);
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int destroyKey(String sessionHandle, String hKeyHandle) {
|
|
||||||
KEY_HANDLE_CONTEXT.remove(hKeyHandle);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public byte[] symEncrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucData) {
|
|
||||||
byte[] symKey = getSymKey(keyHandle);
|
|
||||||
switch (alg) {
|
|
||||||
case SGD_SM4_ECB:
|
|
||||||
return BCSM4Utils.encrypt_ECB_NoPadding(symKey, pucData);
|
|
||||||
case SGD_SM4_CBC:
|
|
||||||
return BCSM4Utils.encrypt_CBC_NoPadding(symKey, pucIv, pucData);
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("不支持的算法:" + alg.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public byte[] symDecrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucEncData) {
|
|
||||||
byte[] symKey = getSymKey(keyHandle);
|
|
||||||
switch (alg) {
|
|
||||||
case SGD_SM4_ECB:
|
|
||||||
return BCSM4Utils.decrypt_ECB_NoPadding(symKey, pucEncData);
|
|
||||||
case SGD_SM4_CBC:
|
|
||||||
return BCSM4Utils.decrypt_CBC_NoPadding(symKey, pucIv, pucEncData);
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("不支持的算法:" + alg.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected byte[] getSymKey(String keyHandle) {
|
|
||||||
byte[] key = KEY_HANDLE_CONTEXT.get(keyHandle);
|
|
||||||
Assert.notNull(key, "密钥句柄不存在");
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public byte[] calculateMAC(String sessionHandle, String keyHandle, AlgId uiAlg, byte[] pucIv, byte[] pucData) {
|
|
||||||
byte[] symKey = getSymKey(keyHandle);
|
|
||||||
return BCSM4Utils.doCBCMac(symKey, pucIv, null, pucData);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static final Map<String, SM3Digest> HASH_CONTEXT = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashInit(String sessionHandle, AlgId alg, EccPubKey pucPublicKey, byte[] pucID) {
|
|
||||||
HASH_CONTEXT.put(sessionHandle, new SM3Digest());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashUpdate(String sessionHandle, byte[] pucData) {
|
|
||||||
Optional.ofNullable(HASH_CONTEXT.get(sessionHandle))
|
|
||||||
.ifPresent(it -> it.update(pucData, 0, pucData.length));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] hashFinish(String sessionHandle) {
|
|
||||||
SM3Digest digest = HASH_CONTEXT.remove(sessionHandle);
|
|
||||||
Assert.notNull(digest, "session异常");
|
|
||||||
byte[] hash = new byte[digest.getDigestSize()];
|
|
||||||
digest.doFinal(hash, 0);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,19 @@
|
|||||||
package com.sunyard.chsm.sdf.adapter;
|
package com.sunyard.chsm.sdf.adapter;
|
||||||
|
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
import com.sun.jna.ptr.IntByReference;
|
|
||||||
import com.sun.jna.ptr.PointerByReference;
|
import com.sun.jna.ptr.PointerByReference;
|
||||||
import com.sunyard.chsm.sdf.context.AlgId;
|
import com.sunyard.chsm.sdf.context.AlgId;
|
||||||
import com.sunyard.chsm.sdf.context.SdrCode;
|
|
||||||
import com.sunyard.chsm.sdf.lib.SdfLibrary;
|
import com.sunyard.chsm.sdf.lib.SdfLibrary;
|
||||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
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.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.model.SDF_DeviceInfo;
|
import com.sunyard.chsm.sdf.model.SDF_DeviceInfo;
|
||||||
import com.sunyard.chsm.sdf.util.LangUtils;
|
import com.sunyard.chsm.sdf.util.LangUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@@ -37,7 +31,7 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
|
|||||||
|
|
||||||
protected final SdfLibrary sdfLibrary;
|
protected final SdfLibrary sdfLibrary;
|
||||||
|
|
||||||
protected abstract int getAlgId(AlgId alg);
|
protected abstract int getAlgId(String alg);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String openDevice() {
|
public String openDevice() {
|
||||||
@@ -64,7 +58,6 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
|
|||||||
|
|
||||||
PointerByReference phSessionHandle = new PointerByReference();
|
PointerByReference phSessionHandle = new PointerByReference();
|
||||||
sdfLibrary.SDF_OpenSession(device, phSessionHandle);
|
sdfLibrary.SDF_OpenSession(device, phSessionHandle);
|
||||||
Assert.notNull(phSessionHandle.getValue(), "SDF_OpenSession failed");
|
|
||||||
|
|
||||||
String key = UUID.randomUUID().toString();
|
String key = UUID.randomUUID().toString();
|
||||||
SESSION_HANDLE_CONTEXT.put(key, phSessionHandle.getValue());
|
SESSION_HANDLE_CONTEXT.put(key, phSessionHandle.getValue());
|
||||||
@@ -104,9 +97,9 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
|
|||||||
sdfLibrary.SDF_GetDeviceInfo(getSessionHandle(sessionHandle), sdfInfo);
|
sdfLibrary.SDF_GetDeviceInfo(getSessionHandle(sessionHandle), sdfInfo);
|
||||||
|
|
||||||
DeviceInfo deviceInfo = new DeviceInfo();
|
DeviceInfo deviceInfo = new DeviceInfo();
|
||||||
deviceInfo.setIssuerName(new String(LangUtils.removeLastZero(sdfInfo.IssuerName)));
|
deviceInfo.setIssuerName(new String(sdfInfo.IssuerName));
|
||||||
deviceInfo.setDeviceName(new String(LangUtils.removeLastZero(sdfInfo.DeviceName)));
|
deviceInfo.setDeviceName(new String(sdfInfo.DeviceName));
|
||||||
deviceInfo.setDeviceSerial(new String(LangUtils.removeLastZero(sdfInfo.DeviceSerial)));
|
deviceInfo.setDeviceSerial(new String(sdfInfo.DeviceSerial));
|
||||||
deviceInfo.setDeviceVersion(sdfInfo.DeviceVersion);
|
deviceInfo.setDeviceVersion(sdfInfo.DeviceVersion);
|
||||||
deviceInfo.setStandardVersion(sdfInfo.StandardVersion);
|
deviceInfo.setStandardVersion(sdfInfo.StandardVersion);
|
||||||
deviceInfo.setAsymAlgAbility(new long[]{sdfInfo.AsymAlgAbility[0], sdfInfo.AsymAlgAbility[1]});
|
deviceInfo.setAsymAlgAbility(new long[]{sdfInfo.AsymAlgAbility[0], sdfInfo.AsymAlgAbility[1]});
|
||||||
@@ -125,166 +118,28 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) {
|
public byte[] exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) {
|
||||||
byte[] pubKey = new byte[132];
|
byte[] pubKey = new byte[132];
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
||||||
sdfLibrary.SDF_ExportEncPublicKey_ECC(hSessionHandle, uiKeyIndex, pubKey);
|
sdfLibrary.SDF_ExportEncPublicKey_ECC(hSessionHandle, uiKeyIndex, pubKey);
|
||||||
return EccPubKey.fromBytes(pubKey);
|
return LangUtils.merge(Arrays.copyOfRange(pubKey, 36, 68), Arrays.copyOfRange(pubKey, 100, 132));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EccKey generateKeyPairECC(String sessionHandle, AlgId alg) {
|
public EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits) {
|
||||||
byte[] sdfPubKey = new byte[132];
|
return null;
|
||||||
byte[] sdfPriKey = new byte[68];
|
|
||||||
|
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
sdfLibrary.SDF_GenerateKeyPair_ECC(hSessionHandle, getAlgId(alg), 256, sdfPubKey, sdfPriKey);
|
|
||||||
return new EccKey(EccPubKey.fromBytes(sdfPubKey).getPubKeyBytes(), EccPriKey.fromBytes(sdfPriKey).getD());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getPrivateKeyAccessRight(String sessionHandle, int uiKeyIndex, byte[] pucPassword) {
|
public byte[] exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, byte[] pubKey, byte[] pucEncDateIn) {
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
return new byte[0];
|
||||||
int res = sdfLibrary.SDF_GetPrivateKeyAccessRight(hSessionHandle, uiKeyIndex, pucPassword, pucPassword.length);
|
|
||||||
return res == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String importKeyWithISKECC(String sessionHandle, int uiIskIndex, EccCipher eccCipher) {
|
public byte[] externalEncryptECC(String sessionHandle, byte[] pubKey, byte[] pucData) {
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
PointerByReference phKeyHandle = new PointerByReference();
|
|
||||||
|
|
||||||
sdfLibrary.SDF_ImportKeyWithISK_ECC(hSessionHandle, uiIskIndex, eccCipher.toSdfData(), phKeyHandle);
|
|
||||||
String key = UUID.randomUUID().toString();
|
|
||||||
KEY_HANDLE_CONTEXT.put(key, phKeyHandle.getValue());
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String importKey(String sessionHandle, byte[] pucKey) {
|
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
PointerByReference phKeyHandle = new PointerByReference();
|
|
||||||
sdfLibrary.SDF_ImportKey(hSessionHandle, pucKey, pucKey.length, phKeyHandle);
|
|
||||||
String key = UUID.randomUUID().toString();
|
|
||||||
KEY_HANDLE_CONTEXT.put(key, phKeyHandle.getValue());
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int destroyKey(String sessionHandle, String hKeyHandle) {
|
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
Pointer keyHandle = KEY_HANDLE_CONTEXT.remove(hKeyHandle);
|
|
||||||
return sdfLibrary.SDF_DestroyKey(hSessionHandle, keyHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EccCipher exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, EccPubKey pubKey, EccCipher pucEncDateIn) {
|
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
|
|
||||||
byte[] pucEncDateOut = new byte[164 + pucEncDateIn.getL()];
|
|
||||||
sdfLibrary.SDF_ExchangeDigitEnvelopeBaseOnECC(hSessionHandle, uiKeyIndex, getAlgId(AlgId.SGD_SM2_1),
|
|
||||||
pubKey.toSdfData(), pucEncDateIn.toSdfData(), pucEncDateOut);
|
|
||||||
return EccCipher.fromBytes(pucEncDateOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EccSignature externalSignECC(String sessionHandle, EccPriKey privateKey, byte[] pucData) {
|
|
||||||
byte[] eccSignature = new byte[128];
|
|
||||||
int uiDataLength = pucData.length;
|
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
sdfLibrary.SDF_ExternalSign_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_1), privateKey.toSdfData(),
|
|
||||||
pucData, uiDataLength, eccSignature);
|
|
||||||
return EccSignature.fromBytes(eccSignature);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean externalVerifyECC(String sessionHandle, EccPubKey publicKey, byte[] pucData, EccSignature pucSignature) {
|
|
||||||
int uiDataLength = pucData.length;
|
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
int result = sdfLibrary.SDF_ExternalVerify_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_1), publicKey.toSdfData(),
|
|
||||||
pucData, uiDataLength, pucSignature.toSdfData());
|
|
||||||
return Objects.equals(result, SdrCode.SDR_OK.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EccCipher externalEncryptECC(String sessionHandle, EccPubKey pubKey, byte[] pucData) {
|
|
||||||
byte[] encData = new byte[128 + 32 + 4 + pucData.length];
|
byte[] encData = new byte[128 + 32 + 4 + pucData.length];
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
||||||
sdfLibrary.SDF_ExternalEncrypt_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_3), pubKey.toSdfData(), pucData, pucData.length, encData);
|
sdfLibrary.SDF_ExternalEncrypt_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_3), pubKey, pucData, pucData.length, encData);
|
||||||
return EccCipher.fromBytes(encData);
|
return encData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] externalDecryptECC(String sessionHandle, EccPriKey priKey, EccCipher pucEncData) {
|
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
byte[] pucData = new byte[pucEncData.getL()];
|
|
||||||
IntByReference puiLength = new IntByReference();
|
|
||||||
sdfLibrary.SDF_ExternalDecrypt_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_3), priKey.toSdfData(), pucEncData.toSdfData(), pucData, puiLength);
|
|
||||||
return pucData;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] symEncrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucData) {
|
|
||||||
|
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
Pointer hKeyHandle = getKeyHandle(keyHandle);
|
|
||||||
int uiDataLength = pucData.length;
|
|
||||||
byte[] pucEncData = new byte[uiDataLength];
|
|
||||||
IntByReference puiLength = new IntByReference();
|
|
||||||
//加密
|
|
||||||
sdfLibrary.SDF_Encrypt(hSessionHandle, hKeyHandle, getAlgId(alg),
|
|
||||||
pucIv, pucData, uiDataLength, pucEncData, puiLength);
|
|
||||||
|
|
||||||
return pucEncData;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] symDecrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucEncData) {
|
|
||||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
|
||||||
Pointer hKeyHandle = getKeyHandle(keyHandle);
|
|
||||||
int uiEncDataLength = pucEncData.length;
|
|
||||||
byte[] pucData = new byte[uiEncDataLength];
|
|
||||||
//解密
|
|
||||||
IntByReference puiLength = new IntByReference();
|
|
||||||
sdfLibrary.SDF_Decrypt(hSessionHandle, hKeyHandle, getAlgId(alg),
|
|
||||||
pucIv, pucEncData, uiEncDataLength, pucData, puiLength);
|
|
||||||
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[16];
|
|
||||||
|
|
||||||
IntByReference puiLength = new IntByReference();
|
|
||||||
sdfLibrary.SDF_CalculateMAC(hSessionHandle, hKeyHandle, getAlgId(uiAlg), pucIv, pucData, uiMacLength, pucMac, puiLength);
|
|
||||||
|
|
||||||
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 == null ? 0 : 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.sunyard.chsm.sdf.adapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/12
|
|
||||||
*/
|
|
||||||
public interface RpcSdfAdapter extends SdfApiAdapter {
|
|
||||||
|
|
||||||
String openDevice(String ip, int port, int connTimeout, int dealTimeout, int ipMode);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,7 @@
|
|||||||
package com.sunyard.chsm.sdf.adapter;
|
package com.sunyard.chsm.sdf.adapter;
|
||||||
|
|
||||||
import com.sunyard.chsm.sdf.context.AlgId;
|
|
||||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
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.EccKey;
|
||||||
import com.sunyard.chsm.sdf.model.EccPriKey;
|
|
||||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
|
||||||
import com.sunyard.chsm.sdf.model.EccSignature;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@@ -60,143 +55,22 @@ public interface SdfApiAdapter {
|
|||||||
* @param uiKeyIndex 密码设备存储的ECC密钥对索引值
|
* @param uiKeyIndex 密码设备存储的ECC密钥对索引值
|
||||||
* @return pucPublicKeyEcc 返回ECC加密公钥x+y
|
* @return pucPublicKeyEcc 返回ECC加密公钥x+y
|
||||||
*/
|
*/
|
||||||
EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex);
|
byte[] exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 产生ECC密钥对并输出 密钥模长 256
|
* 产生ECC密钥对并输出
|
||||||
*
|
*
|
||||||
* @param alg 指定算法标识 SGD_SM2_1
|
* @param alg 指定算法标识 SGD_SM2_1
|
||||||
|
* @param uiKeyBits 指定密钥模长
|
||||||
* @return pucPublicKeyEcc 返回公钥 | pucPrivateKeyEcc 返回私钥
|
* @return pucPublicKeyEcc 返回公钥 | pucPrivateKeyEcc 返回私钥
|
||||||
*/
|
*/
|
||||||
EccKey generateKeyPairECC(String sessionHandle, AlgId alg);
|
EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits);
|
||||||
|
|
||||||
boolean getPrivateKeyAccessRight(String hSessionHandle, int uiKeyIndex, byte[] pucPassword);
|
|
||||||
|
|
||||||
/**
|
byte[] exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, byte[] pubKey, byte[] pucEncDateIn);
|
||||||
* 导入会话密钥并用内部ECC私钥解密
|
|
||||||
*
|
|
||||||
* @param uiIskIndex 密码设备内部存储加密私钥的索引值,对应于加密时的公钥
|
|
||||||
* @param eccCipher 缓冲区指针,用于存放返回的密钥密文
|
|
||||||
* @return phKeyHandle 返回密钥句柄
|
|
||||||
*/
|
|
||||||
String importKeyWithISKECC(String sessionHandle, int uiIskIndex, EccCipher eccCipher);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导入明文会话密钥
|
|
||||||
*
|
|
||||||
* @param sessionHandle 与设备建立的会话句柄
|
|
||||||
* @param pucKey 缓冲区指针,用于存放输入的密钥密文
|
|
||||||
* @return phKeyHandle 返回密钥句柄
|
|
||||||
*/
|
|
||||||
String importKey(String sessionHandle, byte[] pucKey);
|
|
||||||
|
|
||||||
/**
|
byte[] externalEncryptECC(String sessionHandle, byte[] pubKey, byte[] pucData);
|
||||||
* 销毁会话密钥
|
|
||||||
*
|
|
||||||
* @param hKeyHandle 密钥句柄
|
|
||||||
* @return 0 成功; 非0 失败,返回错误代码
|
|
||||||
*/
|
|
||||||
int destroyKey(String sessionHandle, String hKeyHandle);
|
|
||||||
|
|
||||||
EccCipher exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, EccPubKey pubKey, EccCipher pucEncDateIn);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 外部密钥ECC签名
|
|
||||||
*
|
|
||||||
* @param privateKey ECC私钥
|
|
||||||
* @param pucData 缓冲区指针,用于存放外部输入的数据
|
|
||||||
* @return pucSignature 返回签名值数据
|
|
||||||
*/
|
|
||||||
EccSignature externalSignECC(String sessionHandle, EccPriKey privateKey, byte[] pucData);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 外部密钥ECC验证
|
|
||||||
*
|
|
||||||
* @param publicKey ECC公钥
|
|
||||||
* @param pucData 缓冲区指针,用于存放外部输入的数据
|
|
||||||
* @param pucSignature 缓冲区指针,用于存放输入的签名值数据
|
|
||||||
* @return 0 成功; 非0 失败,返回错误代码
|
|
||||||
*/
|
|
||||||
boolean externalVerifyECC(String sessionHandle, EccPubKey publicKey, byte[] pucData, EccSignature pucSignature);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 外部密钥ECC公钥加密
|
|
||||||
*
|
|
||||||
* @param pubKey 外部ECC公钥结构
|
|
||||||
* @param pucData 缓冲区指针,用于存放外部输入的数据
|
|
||||||
* @return pucEncData 返回数据密文
|
|
||||||
*/
|
|
||||||
EccCipher externalEncryptECC(String sessionHandle, EccPubKey pubKey, byte[] pucData);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 外部密钥ECC私钥解密
|
|
||||||
*
|
|
||||||
* @param pucPrivateKeyEcc 外部ECC私钥结构
|
|
||||||
* @param pucEncData 缓冲区指针,用于存放输入的数据密文
|
|
||||||
* @return pucData 返回数据明文
|
|
||||||
*/
|
|
||||||
byte[] externalDecryptECC(String sessionHandle, EccPriKey pucPrivateKeyEcc, EccCipher pucEncData);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对称加密
|
|
||||||
*
|
|
||||||
* @param sessionHandle 与设备建立的会话句柄
|
|
||||||
* @param keyHandle 指定的密钥句柄
|
|
||||||
* @param alg 算法标识,指定对称加密算法 SGD_SMS4_ECB
|
|
||||||
* @param pucIv IV数据
|
|
||||||
* @param pucData 数据明文
|
|
||||||
* @return 数据密文
|
|
||||||
*/
|
|
||||||
byte[] symEncrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucData);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对称解密
|
|
||||||
*
|
|
||||||
* @param sessionHandle 与设备建立的会话句柄
|
|
||||||
* @param keyHandle 指定的密钥句柄
|
|
||||||
* @param alg 算法标识,指定对称加密算法 SGD_SMS4_ECB
|
|
||||||
* @param pucIv IV数据
|
|
||||||
* @param pucEncData 数据密文
|
|
||||||
* @return 数据明文
|
|
||||||
*/
|
|
||||||
byte[] symDecrypt(String sessionHandle, String keyHandle, 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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 杂凑运算初始化
|
|
||||||
*
|
|
||||||
* @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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +1,35 @@
|
|||||||
package com.sunyard.chsm.sdf.adapter;
|
package com.sunyard.chsm.sdf.adapter;
|
||||||
|
|
||||||
import com.googlecode.jsonrpc4j.JsonRpcHttpClient;
|
|
||||||
import com.googlecode.jsonrpc4j.ProxyUtil;
|
|
||||||
import com.sun.jna.Platform;
|
|
||||||
import com.sunyard.chsm.enums.ManufacturerModelEnum;
|
import com.sunyard.chsm.enums.ManufacturerModelEnum;
|
||||||
import com.sunyard.chsm.utils.JsonUtils;
|
import com.sunyard.chsm.sdf.context.DeviceContext;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
* @since 2024/11/5
|
* @since 2024/11/5
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
|
||||||
public class SdfApiAdapterFactory {
|
public class SdfApiAdapterFactory {
|
||||||
|
|
||||||
|
|
||||||
public static SdfApiAdapter getBcAdapter() {
|
public static SdfApiAdapter newInstance(DeviceContext device) {
|
||||||
return BcSdfApiAdaptor.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SdfApiAdapter newInstance(String model, String ip, Integer port) {
|
Assert.hasText(device.getManufacturerModel(), "设备型号不能为空");
|
||||||
|
ManufacturerModelEnum model = ManufacturerModelEnum.of(device.getManufacturerModel());
|
||||||
|
|
||||||
Assert.hasText(model, "设备型号不能为空");
|
if (Objects.isNull(model) && Objects.equals(BouncyCastleProvider.PROVIDER_NAME, device.getManufacturerModel())) {
|
||||||
ManufacturerModelEnum modelEnum = ManufacturerModelEnum.of(model);
|
|
||||||
|
|
||||||
if (Objects.isNull(modelEnum) && Objects.equals(BouncyCastleProvider.PROVIDER_NAME, model)) {
|
|
||||||
// bc adaptor
|
// bc adaptor
|
||||||
return BcSdfApiAdaptor.INSTANCE;
|
return new BcSdfApiAdaptor();
|
||||||
}
|
}
|
||||||
switch (modelEnum) {
|
switch (model) {
|
||||||
case enc001:
|
case enc001:
|
||||||
return Platform.isMac() ? getProxyRcpAdapter(ip, port) : new SunyardJnaSdfAdaptor(ip, port);
|
return new SunyardJnaSdfAdaptor(device.getServiceIp(), device.getServicePort());
|
||||||
default:
|
default:
|
||||||
throw new UnsupportedOperationException("不支持的设备型号: " + model);
|
throw new UnsupportedOperationException("不支持的设备型号: " + device.getManufacturerModel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final RpcSdfAdapter rpcSdfAdapter;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
JsonRpcHttpClient client = new JsonRpcHttpClient(JsonUtils.objectMapper(),
|
|
||||||
new URL("http://172.16.18.46:9989/sdf/adapter"), Collections.emptyMap());
|
|
||||||
rpcSdfAdapter = ProxyUtil.createClientProxy(
|
|
||||||
ClassUtils.getDefaultClassLoader(), RpcSdfAdapter.class, client);
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SdfApiAdapter getProxyRcpAdapter(String ip, Integer port) {
|
|
||||||
return (SdfApiAdapter) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(),
|
|
||||||
new Class[]{SdfApiAdapter.class},
|
|
||||||
(proxy, method, args) -> {
|
|
||||||
if (Objects.equals(method.getName(), "openDevice")) {
|
|
||||||
return rpcSdfAdapter.openDevice(ip, port, 3000, 10000, 0);
|
|
||||||
}
|
|
||||||
return method.invoke(rpcSdfAdapter, args);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,10 @@ package com.sunyard.chsm.sdf.adapter;
|
|||||||
|
|
||||||
import com.sun.jna.Native;
|
import com.sun.jna.Native;
|
||||||
import com.sun.jna.ptr.PointerByReference;
|
import com.sun.jna.ptr.PointerByReference;
|
||||||
import com.sunyard.chsm.sdf.context.AlgId;
|
|
||||||
import com.sunyard.chsm.sdf.context.SdrCode;
|
|
||||||
import com.sunyard.chsm.sdf.context.SunyardAlgId;
|
import com.sunyard.chsm.sdf.context.SunyardAlgId;
|
||||||
import com.sunyard.chsm.sdf.lib.SdfLibrary;
|
|
||||||
import com.sunyard.chsm.sdf.lib.SunyardSdfLibrary;
|
import com.sunyard.chsm.sdf.lib.SunyardSdfLibrary;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@@ -22,52 +13,26 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
* @author liulu
|
* @author liulu
|
||||||
* @since 2024/11/4
|
* @since 2024/11/4
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
|
||||||
public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
|
public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
|
||||||
|
|
||||||
private static final Map<String, SunyardSdfLibrary> SDF_LIB_MAP = new ConcurrentHashMap<>();
|
private static final Map<String, SunyardSdfLibrary> SDF_LIB_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
private final String ip;
|
private final String ip;
|
||||||
private final Integer port;
|
private final Integer port;
|
||||||
private final Integer connTimeout;
|
private final Integer connTimeout;
|
||||||
private final Integer dealTimeout;
|
private final Integer dealTimeout;
|
||||||
|
|
||||||
public SunyardJnaSdfAdaptor(String ip, int port) {
|
public SunyardJnaSdfAdaptor(String ip, int port) {
|
||||||
this(ip, port, 3000, 10000);
|
this(ip, port, "sdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
public SunyardJnaSdfAdaptor(String ip, int port, int connTimeout, int dealTimeout) {
|
public SunyardJnaSdfAdaptor(String ip, int port, String libName) {
|
||||||
super((SdfLibrary) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(),
|
this(ip, port, libName, 3000, 3000);
|
||||||
new Class[]{SdfLibrary.class},
|
|
||||||
new InvocationHandler() {
|
|
||||||
private final SunyardSdfLibrary sunyardSdfLibrary;
|
|
||||||
|
|
||||||
{
|
|
||||||
sunyardSdfLibrary = SDF_LIB_MAP.computeIfAbsent("sdf", k -> Native.load(k, SunyardSdfLibrary.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public SunyardJnaSdfAdaptor(String ip, int port, String libName, int connTimeout, int dealTimeout) {
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
super(SDF_LIB_MAP.computeIfAbsent(libName, k -> Native.load(libName, SunyardSdfLibrary.class)));
|
||||||
Object res = method.invoke(sunyardSdfLibrary, args);
|
|
||||||
if (!(res instanceof Integer)) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
int resInt = (Integer) res;
|
|
||||||
if (Objects.equals("SDF_ExternalVerify_ECC", method.getName())) {
|
|
||||||
log.info("SDF_ExternalVerify_ECC: {}, 返回值: {}", method.getName(), Integer.toHexString(resInt));
|
|
||||||
return resInt;
|
|
||||||
}
|
|
||||||
if (method.getName().startsWith("SDF_")) {
|
|
||||||
if (resInt != SdrCode.SDR_OK.getCode()) {
|
|
||||||
log.warn("调用异常: {}, 返回值: {} -{}", method.getName(), Integer.toHexString(resInt), resInt);
|
|
||||||
SdrCode sdrCode = SdrCode.of((Integer) res);
|
|
||||||
throw new IllegalArgumentException(sdrCode != null ? sdrCode.getMsg() : "调用sdf接口异常: " + Integer.toHexString(resInt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.connTimeout = connTimeout;
|
this.connTimeout = connTimeout;
|
||||||
@@ -76,7 +41,7 @@ public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String openDevice() {
|
public String openDevice() {
|
||||||
SunyardSdfLibrary sunyardSdfLibrary = SDF_LIB_MAP.computeIfAbsent("sdf", k -> Native.load(k, SunyardSdfLibrary.class));
|
SunyardSdfLibrary sunyardSdfLibrary = (SunyardSdfLibrary) sdfLibrary;
|
||||||
PointerByReference phDeviceHandle = new PointerByReference();
|
PointerByReference phDeviceHandle = new PointerByReference();
|
||||||
sunyardSdfLibrary.SDF_OpenDevice(phDeviceHandle, safeStringBytes(ip), port, connTimeout, dealTimeout, 0);
|
sunyardSdfLibrary.SDF_OpenDevice(phDeviceHandle, safeStringBytes(ip), port, connTimeout, dealTimeout, 0);
|
||||||
String key = UUID.randomUUID().toString();
|
String key = UUID.randomUUID().toString();
|
||||||
@@ -85,11 +50,10 @@ public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getAlgId(AlgId alg) {
|
protected int getAlgId(String alg) {
|
||||||
return SunyardAlgId.valueOf(alg.name()).getValue();
|
return SunyardAlgId.valueOf(alg).getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static byte[] safeStringBytes(String str) {
|
public static byte[] safeStringBytes(String str) {
|
||||||
if (null == str || str.isEmpty()) {
|
if (null == str || str.isEmpty()) {
|
||||||
return new byte[]{0x30};
|
return new byte[]{0x30};
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ package com.sunyard.chsm.sdf.context;
|
|||||||
* @author liulu
|
* @author liulu
|
||||||
* @since 2024/11/5
|
* @since 2024/11/5
|
||||||
*/
|
*/
|
||||||
public enum AlgId {
|
public interface AlgId {
|
||||||
SGD_SM3,
|
|
||||||
|
|
||||||
SGD_SM4_CBC,
|
String SGD_SM3 = "SGD_SM3";
|
||||||
SGD_SM4_ECB,
|
|
||||||
SGD_SM4_MAC,
|
|
||||||
|
|
||||||
SGD_SM2_1,// 签名验签
|
String SGD_SM4_CBC = "SGD_SMS4_CBC";
|
||||||
SGD_SM2_2,
|
String SGD_SM4_ECB = "SGD_SMS4_ECB";
|
||||||
SGD_SM2_3,// 加密解密
|
String SGD_SM4_MAC = "SGD_SMS4_MAC";
|
||||||
;
|
|
||||||
|
String SGD_SM2_1 = "SGD_SM2_1"; // 签名验签
|
||||||
|
String SGD_SM2_2 = "SGD_SM2_2";
|
||||||
|
String SGD_SM2_3 = "SGD_SM2_3"; // 加密解密
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.sunyard.chsm.sdf.context;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liulu
|
||||||
|
* @since 2024/11/5
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DeviceContext {
|
||||||
|
|
||||||
|
private String serviceIp;
|
||||||
|
private Integer servicePort;
|
||||||
|
private String manufacturer;
|
||||||
|
private String manufacturerModel;
|
||||||
|
private String accessCredentials;
|
||||||
|
private String jnaLibName;
|
||||||
|
|
||||||
|
private Integer weight;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
package com.sunyard.chsm.sdf.context;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/7
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public enum SdrCode {
|
|
||||||
|
|
||||||
SDR_OK(0x0, "操作成功"),
|
|
||||||
SDR_BASE(0x01000000, "错误码基础值"),
|
|
||||||
|
|
||||||
SDR_UNKNOWER(SDR_BASE.code + 0x00000001, "未知错误"),
|
|
||||||
SDR_NOTSUPPORT(SDR_BASE.code + 0x00000002, "不支持的接口调用"),
|
|
||||||
SDR_COMMFAIL(SDR_BASE.code + 0x00000003, "与设备通信失败"),
|
|
||||||
SDR_HARDFAIL(SDR_BASE.code + 0x00000004, "运算模块无响应"),
|
|
||||||
SDR_OPENDEVICE(SDR_BASE.code + 0x00000005, "打开设备失败"),
|
|
||||||
SDR_OPENSESSION(SDR_BASE.code + 0x00000006, "创建会话失败"),
|
|
||||||
SDR_PARDENY(SDR_BASE.code + 0x00000007, "无私钥使用权限"),
|
|
||||||
SDR_KEYNOTEXIST(SDR_BASE.code + 0x00000008, "不存在的密钥调用"),
|
|
||||||
SDR_ALGNOTSUPPORT(SDR_BASE.code + 0x00000009, "不支持的算法调用"),
|
|
||||||
SDR_ALGMODNOTSUPPORT(SDR_BASE.code + 0x0000000A, "不支持的算法模式调用"),
|
|
||||||
SDR_PKOPERR(SDR_BASE.code + 0x0000000B, "公钥运算失败"),
|
|
||||||
SDR_SKOPERR(SDR_BASE.code + 0x0000000C, "私钥运算失败"),
|
|
||||||
SDR_SIGNERR(SDR_BASE.code + 0x0000000D, "签名运算失败"),
|
|
||||||
SDR_VERIFYERR(SDR_BASE.code + 0x0000000E, "验证签名失败"),
|
|
||||||
SDR_SYMOPERR(SDR_BASE.code + 0x0000000F, "对称算法运算失败"),
|
|
||||||
SDR_STEPERR(SDR_BASE.code + 0x00000010, "多步运算步骤错误"),
|
|
||||||
SDR_FILESIZEERR(SDR_BASE.code + 0x00000011, "文件长度超出限制"),
|
|
||||||
SDR_FILENOEXIST(SDR_BASE.code + 0x00000012, "指定的文件不存在"),
|
|
||||||
SDR_FILEOFSERR(SDR_BASE.code + 0x00000013, "文件起始位置错误"),
|
|
||||||
SDR_KEYTYPEERR(SDR_BASE.code + 0x00000014, "密钥类型错误"),
|
|
||||||
SDR_KEYERR(SDR_BASE.code + 0x00000015, "密钥错误"),
|
|
||||||
SDR_ENCDATAERR(SDR_BASE.code + 0x00000016, "ECC加密数据错误"),
|
|
||||||
SDR_RANDERR(SDR_BASE.code + 0x00000017, "随机数产生失败"),
|
|
||||||
SDR_PRKERR(SDR_BASE.code + 0x00000018, "私钥使用权限获取失败"),
|
|
||||||
SDR_MACERR(SDR_BASE.code + 0x00000019, "MAC运算失败"),
|
|
||||||
SDR_FILEEXISTS(SDR_BASE.code + 0x0000001A, "指定文件已存在"),
|
|
||||||
SDR_FILEWERR(SDR_BASE.code + 0x0000001B, "文件写入失败"),
|
|
||||||
SDR_NOBUFFER(SDR_BASE.code + 0x0000001C, "存储空间不足"),
|
|
||||||
SDR_INARGERR(SDR_BASE.code + 0x0000001D, "输入参数错误"),
|
|
||||||
SDR_OUTARGERR(SDR_BASE.code + 0x0000001E, "输出参数错误"),
|
|
||||||
SDR_FILERDERR(SDR_BASE.code + 0x0000001F, "文件读取失败"),
|
|
||||||
SDR_CONSULTERR(SDR_BASE.code + 0x00000020, "密钥协商错误"),
|
|
||||||
SDR_LEVELERR(SDR_BASE.code + 0x00000021, "权限不足"),
|
|
||||||
SDR_INDEXERR(SDR_BASE.code + 0x00000022, "索引错误"),
|
|
||||||
SDR_KEYLENERR(SDR_BASE.code + 0x00000023, "密钥长度错误"),
|
|
||||||
SDR_DATALENERR(SDR_BASE.code + 0x00000024, "数据长度错误"),
|
|
||||||
SDR_RIGHTLENERR(SDR_BASE.code + 0x00000025, "私钥授权码长度错误"),
|
|
||||||
SDR_RIGHTERR(SDR_BASE.code + 0x00000026, "私钥授权码错误"),
|
|
||||||
SDR_FILEEMPTYERR(SDR_BASE.code + 0x00000027, "文件为空"),
|
|
||||||
SDR_ERRSTATE(SDR_BASE.code + 0x00000028, "处于错误状态"),
|
|
||||||
SDR_INITSTATE(SDR_BASE.code + 0x00000029, "处于初始状态"),
|
|
||||||
SDR_RPRKERR(SDR_BASE.code + 0x0000002A, "私钥使用权限释放失败"),
|
|
||||||
SDR_SIGNPRKERR(SDR_BASE.code + 0x0000002B, "签名公钥导出失败"),
|
|
||||||
SDR_ENCPRKERR(SDR_BASE.code + 0x0000002C, "加密公钥导出失败"),
|
|
||||||
SDR_KPERR(SDR_BASE.code + 0x0000002D, "密钥对生成失败"),
|
|
||||||
SDR_GENERATEKEYERR(SDR_BASE.code + 0x0000002E, "会话密钥生成失败"),
|
|
||||||
SDR_IMKEYERR(SDR_BASE.code + 0x0000002F, "导入密钥失败"),
|
|
||||||
SDR_INTOEXERR(SDR_BASE.code + 0x00000030, "数字信封转换失败"),
|
|
||||||
|
|
||||||
/* API新增错误码 */
|
|
||||||
SRD_DEV_FILE_CONFIG_ERR(SDR_BASE.code + 0x00000040, "配置文件信息错误(请检查配置文件的信息是否有误)"),
|
|
||||||
SDR_DEVICEHANDLE_INVAILD(SDR_BASE.code + 0x00000041, "设备句柄错误(请检查句柄是否初始化或已经被释放)"),
|
|
||||||
SDR_SESSIONHANLE_INVAILD(SDR_BASE.code + 0x00000042, "会话句柄错误(请检查句柄是否初始化或已经被释放)"),
|
|
||||||
SDR_KEYHANLE_INVAILD(SDR_BASE.code + 0x00000043, "密钥句柄错误(请检查句柄是否初始化或已经被释放)"),
|
|
||||||
SDR_AGREEMENTHANLE_INVAILD(SDR_BASE.code + 0x00000044, "协商句柄错误(请检查句柄是否初始化或已经被释放)"),
|
|
||||||
SDR_UNKNOWN_HANDLE(SDR_BASE.code + 0x00000045, "未知的句柄"),
|
|
||||||
SDR_NO_AVAILABL_DEVICE(SDR_BASE.code + 0x00000046, "此设备无法连接, 请检查IP和端口是否正确"),
|
|
||||||
|
|
||||||
|
|
||||||
SYD_KEYSCHEMEERR(0x26, "错误密钥方案"),
|
|
||||||
SYD_PRIKEYPWDERR(0x02, "私钥授权码验证错误"),
|
|
||||||
SYD_HASHERR(0x29, "哈希失败(请联系管理员)"),
|
|
||||||
SYD_CARDERR(0x47, "密码卡计算错误(请联系管理员)"),
|
|
||||||
SYD_PACKAGELENERR(0x80, "数据包长度错误(请联系管理员)"),
|
|
||||||
SYD_GETKEYERR(0x21, "获取密钥失败,检查密钥状态"),
|
|
||||||
SYD_LMKCALCERR(0x13, "主密钥计算失败(请联系管理员)"),
|
|
||||||
SYD_PKGPARAMERR(0x15, "输入参数错误(请联系管理员)"),
|
|
||||||
SYD_AGREEMENTERR(0x06, "ECC密钥协商失败(请联系管理员)"),
|
|
||||||
SYD_LMKDECPRIKEYERR(0x18, "主密钥解密私钥错误(请联系管理员)"),
|
|
||||||
SYD_SYMENCDECERR(0x14, "对称加解密错误(请联系管理员)"),
|
|
||||||
SYD_FILEEXISTS(0x71, "文件已存在"),
|
|
||||||
SYD_FILENOEXIST(0x72, "文件不存在"),
|
|
||||||
SYD_FILECREATEERR(0x73, "文件创建失败(请联系管理员)"),
|
|
||||||
SYD_FILERDERR(0x74, "文件读取失败"),
|
|
||||||
SYD_FILEWERR(0x75, "文件写入失败"),
|
|
||||||
SYD_FILEDELEERR(0x76, "文件删除失败(请联系管理员)"),
|
|
||||||
SYD_FILESIZEERR(0x77, "超出文件大小限制"),
|
|
||||||
SYD_FILEOPENEERR(0x78, "文件打开失败(请联系管理员)"),
|
|
||||||
SYD_FILEEMPTYERR(0x79, "文件为空"),
|
|
||||||
SYD_VERIFYERR(0x8002, "验签错误"),
|
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
private final int code;
|
|
||||||
private final String msg;
|
|
||||||
|
|
||||||
public static SdrCode of(int code) {
|
|
||||||
|
|
||||||
return Arrays.stream(SdrCode.values())
|
|
||||||
.filter(it -> Objects.equals(it.code, code))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -179,27 +179,6 @@ public interface SdfLibrary extends Library {
|
|||||||
*/
|
*/
|
||||||
int SDF_ExchangeDigitEnvelopeBaseOnECC(Pointer hSessionHandle, int uiKeyIndex, int uiAlgID, byte[] pucPublicKey, byte[] pucEncDateIn, byte[] pucEncDateOut);
|
int SDF_ExchangeDigitEnvelopeBaseOnECC(Pointer hSessionHandle, int uiKeyIndex, int uiAlgID, byte[] pucPublicKey, byte[] pucEncDateIn, byte[] pucEncDateOut);
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param hSessionHandle 与设备建立的会话句柄
|
|
||||||
* @param pucKey 缓冲区指针,用于存放输入的密钥密文
|
|
||||||
* @param puiKeyLength 返回的密钥明文长度
|
|
||||||
* @param phKeyHandle 返回的密钥句柄
|
|
||||||
* @return 0 成功; 非0 失败,返回错误代码
|
|
||||||
*/
|
|
||||||
int SDF_ImportKey(Pointer hSessionHandle, byte[] pucKey, int puiKeyLength, PointerByReference phKeyHandle);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取私钥使用权限
|
|
||||||
*
|
|
||||||
* @param hSessionHandle 与设备建立的会话句柄
|
|
||||||
* @param uiKeyIndex 密码设备存储私钥的索引值
|
|
||||||
* @param pucPassword 使用私钥权限的标识码
|
|
||||||
* @param uiPwdLength 私钥访问控制码长度,不少于8字节
|
|
||||||
* @return 0 成功; 非0 失败,返回错误代码
|
|
||||||
*/
|
|
||||||
int SDF_GetPrivateKeyAccessRight(Pointer hSessionHandle, int uiKeyIndex, byte[] pucPassword, int uiPwdLength);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入会话密钥并用内部ECC私钥解密
|
* 导入会话密钥并用内部ECC私钥解密
|
||||||
*
|
*
|
||||||
@@ -221,7 +200,7 @@ public interface SdfLibrary extends Library {
|
|||||||
* @param phKeyhandle
|
* @param phKeyhandle
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
int SDF_DestroyKey(Pointer phSessionHandle, Pointer phKeyhandle);
|
int SDF_DestroyKey(Pointer phSessionHandle, PointerByReference phKeyhandle);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -283,7 +262,7 @@ public interface SdfLibrary extends Library {
|
|||||||
* @param pucIDlength 签名者ID的长度
|
* @param pucIDlength 签名者ID的长度
|
||||||
* @return int 响应码
|
* @return int 响应码
|
||||||
*/
|
*/
|
||||||
int SDF_HashInit(Pointer phSessionHandle, int uiAlgID, byte[] pucPublicKey, byte[] pucID, int pucIDlength);
|
int SDF_HashInit(Pointer phSessionHandle, int uiAlgID, byte[] pucPublicKey, String pucID, int pucIDlength);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 多包杂凑运算
|
* 多包杂凑运算
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.sun.jna.ptr.PointerByReference;
|
|||||||
*/
|
*/
|
||||||
public interface SunyardSdfLibrary extends SdfLibrary {
|
public interface SunyardSdfLibrary extends SdfLibrary {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开设备
|
* 打开设备
|
||||||
* @param phDeviceHandle 设备句柄
|
* @param phDeviceHandle 设备句柄
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
package com.sunyard.chsm.sdf.model;
|
package com.sunyard.chsm.sdf.model;
|
||||||
|
|
||||||
import com.sunyard.chsm.utils.CodecUtils;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@@ -31,9 +25,6 @@ public class EccCipher {
|
|||||||
// 密文数据
|
// 密文数据
|
||||||
private byte[] C;
|
private byte[] C;
|
||||||
|
|
||||||
public String getC1C3C2Hex() {
|
|
||||||
return CodecUtils.encodeHex(getC1C3C2Bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getC1C3C2Bytes() {
|
public byte[] getC1C3C2Bytes() {
|
||||||
int xLen = x.length;
|
int xLen = x.length;
|
||||||
@@ -50,44 +41,4 @@ public class EccCipher {
|
|||||||
return rawData;
|
return rawData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toSdfData() {
|
|
||||||
byte[] d = new byte[164 + L];
|
|
||||||
byte[] l = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(L).array();
|
|
||||||
System.arraycopy(x, 0, d, 32, 32);
|
|
||||||
System.arraycopy(y, 0, d, 96, 32);
|
|
||||||
System.arraycopy(M, 0, d, 128, 32);
|
|
||||||
System.arraycopy(l, 0, d, 160, 4);
|
|
||||||
System.arraycopy(C, 0, d, 164, L);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EccCipher fromHex(String hex) {
|
|
||||||
return fromBytes(CodecUtils.decodeHex(hex));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EccCipher fromBytes(byte[] cipher) {
|
|
||||||
Assert.notNull(cipher, "Ecc密文数据不能为null");
|
|
||||||
if (cipher[0] == 0x04) {
|
|
||||||
cipher = Arrays.copyOfRange(cipher, 1, cipher.length);
|
|
||||||
}
|
|
||||||
Assert.isTrue(cipher.length > 96, "Ecc加密数据格式错误");
|
|
||||||
if (cipher.length > 164
|
|
||||||
&& Arrays.equals(Arrays.copyOf(cipher, 32), new byte[32])
|
|
||||||
&& Arrays.equals(Arrays.copyOfRange(cipher, 64, 96), new byte[32])) {
|
|
||||||
int L = cipher.length - 164;
|
|
||||||
byte[] x = Arrays.copyOfRange(cipher, 32, 64);
|
|
||||||
byte[] y = Arrays.copyOfRange(cipher, 96, 128);
|
|
||||||
byte[] m = Arrays.copyOfRange(cipher, 128, 160);
|
|
||||||
byte[] c = Arrays.copyOfRange(cipher, 164, cipher.length);
|
|
||||||
return new EccCipher(x, y, m, L, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
int L = cipher.length - 96;
|
|
||||||
byte[] x = Arrays.copyOfRange(cipher, 0, 32);
|
|
||||||
byte[] y = Arrays.copyOfRange(cipher, 32, 64);
|
|
||||||
byte[] m = Arrays.copyOfRange(cipher, 64, 96);
|
|
||||||
byte[] c = Arrays.copyOfRange(cipher, 96, cipher.length);
|
|
||||||
return new EccCipher(x, y, m, L, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ package com.sunyard.chsm.sdf.model;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@@ -23,24 +18,5 @@ public class EccPriKey {
|
|||||||
// 私 钥
|
// 私 钥
|
||||||
private byte[] D;
|
private byte[] D;
|
||||||
|
|
||||||
public byte[] toSdfData() {
|
|
||||||
byte[] sdf = new byte[68];
|
|
||||||
System.arraycopy(Hex.decode("00010000"), 0, sdf, 0, 4);
|
|
||||||
System.arraycopy(D, 0, sdf, 36, 32);
|
|
||||||
return sdf;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EccPriKey fromBytes(byte[] priKey) {
|
|
||||||
Assert.notNull(priKey, "私钥数据不能为null");
|
|
||||||
if (Objects.equals(priKey.length, 68)) {
|
|
||||||
// 00010000
|
|
||||||
priKey = Arrays.copyOfRange(priKey, 4, priKey.length);
|
|
||||||
}
|
|
||||||
Assert.isTrue(Objects.equals(priKey.length, 32) || Objects.equals(priKey.length, 64), "Ecc私钥数据格式错误");
|
|
||||||
if (Objects.equals(priKey.length, 32)) {
|
|
||||||
return new EccPriKey(256, priKey);
|
|
||||||
}
|
|
||||||
return new EccPriKey(256, Arrays.copyOfRange(priKey, 32, 64));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ package com.sunyard.chsm.sdf.model;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@@ -25,9 +20,6 @@ public class EccPubKey {
|
|||||||
// 公 钥 y 坐 标
|
// 公 钥 y 坐 标
|
||||||
private byte[] y;
|
private byte[] y;
|
||||||
|
|
||||||
public String getPubKeyHex() {
|
|
||||||
return Hex.toHexString(getPubKeyBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getPubKeyBytes() {
|
public byte[] getPubKeyBytes() {
|
||||||
byte[] rawKey = new byte[x.length + y.length];
|
byte[] rawKey = new byte[x.length + y.length];
|
||||||
@@ -36,38 +28,4 @@ public class EccPubKey {
|
|||||||
return rawKey;
|
return rawKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toSdfData() {
|
|
||||||
byte[] sdf = new byte[132];
|
|
||||||
System.arraycopy(Hex.decode("00010000"), 0, sdf, 0, 4);
|
|
||||||
System.arraycopy(x, 0, sdf, 36, 32);
|
|
||||||
System.arraycopy(y, 0, sdf, 100, 32);
|
|
||||||
return sdf;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EccPubKey fromHex(String pubKeyHex) {
|
|
||||||
return fromBytes(Hex.decode(pubKeyHex));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EccPubKey fromBytes(byte[] pubKey) {
|
|
||||||
Assert.notNull(pubKey, "公钥数据不能为null");
|
|
||||||
if (Objects.equals(pubKey.length, 65)) {
|
|
||||||
Assert.isTrue(Objects.equals(pubKey[0], 0x04), "Ecc公钥数据格式错误,必须04开头");
|
|
||||||
pubKey = Arrays.copyOfRange(pubKey, 1, pubKey.length);
|
|
||||||
} else if (Objects.equals(pubKey.length, 132)) {
|
|
||||||
// 00010000
|
|
||||||
pubKey = Arrays.copyOfRange(pubKey, 4, pubKey.length);
|
|
||||||
}
|
|
||||||
Assert.isTrue(Objects.equals(pubKey.length, 64) || Objects.equals(pubKey.length, 128), "Ecc公钥数据格式错误");
|
|
||||||
byte[] x = new byte[32];
|
|
||||||
byte[] y = new byte[32];
|
|
||||||
if (Objects.equals(pubKey.length, 64)) {
|
|
||||||
System.arraycopy(pubKey, 0, x, 0, 32);
|
|
||||||
System.arraycopy(pubKey, 32, y, 0, 32);
|
|
||||||
} else if (Objects.equals(pubKey.length, 128)) {
|
|
||||||
System.arraycopy(pubKey, 32, x, 0, 32);
|
|
||||||
System.arraycopy(pubKey, 96, y, 0, 32);
|
|
||||||
}
|
|
||||||
return new EccPubKey(256, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
package com.sunyard.chsm.sdf.model;
|
package com.sunyard.chsm.sdf.model;
|
||||||
|
|
||||||
import com.sunyard.chsm.utils.CodecUtils;
|
|
||||||
import com.sunyard.chsm.utils.gm.BCSM2Utils;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
* @version V1.0
|
* @version V1.0
|
||||||
@@ -25,19 +20,6 @@ public class EccSignature {
|
|||||||
// 签名的 s 部分
|
// 签名的 s 部分
|
||||||
private byte[] s;
|
private byte[] s;
|
||||||
|
|
||||||
|
|
||||||
public String getRawSignHex() {
|
|
||||||
return CodecUtils.encodeHex(getRawSignBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getDerSignBytes() {
|
|
||||||
try {
|
|
||||||
return BCSM2Utils.encodeSM2SignToDER(getRawSignBytes());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalArgumentException("ECC签名数据格式错误");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getRawSignBytes() {
|
public byte[] getRawSignBytes() {
|
||||||
byte[] signData = new byte[r.length + s.length];
|
byte[] signData = new byte[r.length + s.length];
|
||||||
System.arraycopy(r, 0, signData, 0, r.length);
|
System.arraycopy(r, 0, signData, 0, r.length);
|
||||||
@@ -45,32 +27,5 @@ public class EccSignature {
|
|||||||
return signData;
|
return signData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toSdfData() {
|
|
||||||
byte[] res = new byte[128];
|
|
||||||
System.arraycopy(r, 0, res, 32, 32);
|
|
||||||
System.arraycopy(s, 0, res, 96, 32);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EccSignature fromBytes(byte[] sign) {
|
|
||||||
if (sign == null || sign.length == 0) {
|
|
||||||
throw new IllegalArgumentException("ECC签名数据格式错误");
|
|
||||||
}
|
|
||||||
if (sign.length >= 70 && sign.length <= 75) {
|
|
||||||
sign = BCSM2Utils.decodeDERSM2Sign(sign);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sign.length == 64) {
|
|
||||||
byte[] r = Arrays.copyOfRange(sign, 0, 32);
|
|
||||||
byte[] s = Arrays.copyOfRange(sign, 32, 64);
|
|
||||||
return new EccSignature(r, s);
|
|
||||||
} else if (sign.length == 128) {
|
|
||||||
byte[] r = Arrays.copyOfRange(sign, 32, 64);
|
|
||||||
byte[] s = Arrays.copyOfRange(sign, 96, 128);
|
|
||||||
return new EccSignature(r, s);
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("ECC签名数据格式错误");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,20 +10,6 @@ import java.util.Arrays;
|
|||||||
*/
|
*/
|
||||||
public abstract class LangUtils {
|
public abstract class LangUtils {
|
||||||
|
|
||||||
|
|
||||||
public static byte[] removeLastZero(byte[] bytes) {
|
|
||||||
if (bytes == null) {
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
int len = bytes.length;
|
|
||||||
for (int i = len - 1; i >= 0; i--) {
|
|
||||||
if (bytes[i] != 0) {
|
|
||||||
return Arrays.copyOfRange(bytes, 0, i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] merge(byte[]... bytes) {
|
public static byte[] merge(byte[]... bytes) {
|
||||||
int newLen = Arrays.stream(bytes).mapToInt(it -> it.length).sum();
|
int newLen = Arrays.stream(bytes).mapToInt(it -> it.length).sum();
|
||||||
byte[] res = new byte[newLen];
|
byte[] res = new byte[newLen];
|
||||||
|
|||||||
@@ -1,38 +1,10 @@
|
|||||||
package com.sunyard.chsm.sdf.util;
|
package com.sunyard.chsm.sdf.util;
|
||||||
|
|
||||||
import com.sunyard.chsm.enums.Padding;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
*/
|
*/
|
||||||
public abstract class PaddingUtil {
|
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) {
|
public static byte[] PKCS7Padding(byte[] content, int blockSize) {
|
||||||
if (content == null || blockSize < 8)
|
if (content == null || blockSize < 8)
|
||||||
throw new IllegalStateException("parameter error");
|
throw new IllegalStateException("parameter error");
|
||||||
@@ -58,13 +30,14 @@ public abstract class PaddingUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] PKCS5Padding(byte[] content) {
|
public static byte[] PKCS5Padding(byte[] content) throws Exception {
|
||||||
return PKCS7Padding(content, 8);
|
return PKCS7Padding(content, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] PKCS7Unpadding(byte[] content, int blockSize) {
|
public static byte[] PKCS7Unpadding(byte[] content, int blockSize)
|
||||||
|
throws Exception {
|
||||||
if (blockSize < 8 || content == null || content.length % blockSize != 0)
|
if (blockSize < 8 || content == null || content.length % blockSize != 0)
|
||||||
throw new IllegalStateException("parameter error");
|
throw new Exception("parameter error");
|
||||||
return PKCS7Unpadding(content);
|
return PKCS7Unpadding(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,8 +57,9 @@ public abstract class PaddingUtil {
|
|||||||
return unpadded;
|
return unpadded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] PKCS5Unpadding(byte[] content) {
|
public static byte[] PKCS5Unpadding(byte[] content) throws Exception {
|
||||||
return PKCS7Unpadding(content, 8);
|
return PKCS7Unpadding(content, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,16 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface KeyInfoService {
|
public interface KeyInfoService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询单个密钥
|
||||||
|
* @param query
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
KeyInfoDTO.KeyValue selectKeyInApp(KeyInfoDTO.Query query);
|
||||||
|
|
||||||
Page<KeyInfoDTO.KeyView> selectPageList(KeyInfoDTO.Query query);
|
Page<KeyInfoDTO.KeyView> selectPageList(KeyInfoDTO.Query query);
|
||||||
|
|
||||||
KeyInfoDTO.KeyView selectById(Long id);
|
Long save(KeyInfoDTO.KeySave save);
|
||||||
|
|
||||||
List<Long> save(KeyInfoDTO.KeySave save);
|
|
||||||
|
|
||||||
void update(KeyInfoDTO.KeyUpdate update);
|
void update(KeyInfoDTO.KeyUpdate update);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.sunyard.chsm.service;
|
||||||
|
|
||||||
|
import com.sunyard.chsm.model.entity.KeyRecord;
|
||||||
|
|
||||||
|
public interface KeyRecordService {
|
||||||
|
KeyRecord selectById(Long id);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 keyId 查找密钥
|
||||||
|
* @param keyId keyId
|
||||||
|
* @return 可用值或 null
|
||||||
|
*/
|
||||||
|
KeyRecord selectByKeyId(Long keyId);
|
||||||
|
}
|
||||||
@@ -1,289 +0,0 @@
|
|||||||
package com.sunyard.chsm.service;
|
|
||||||
|
|
||||||
import com.sunyard.chsm.constant.ParamConfKeyConstant;
|
|
||||||
import com.sunyard.chsm.enums.DeviceTmkStatus;
|
|
||||||
import com.sunyard.chsm.mapper.ParamConfMapper;
|
|
||||||
import com.sunyard.chsm.mapper.SpDeviceMapper;
|
|
||||||
import com.sunyard.chsm.model.dto.DeviceCheckRes;
|
|
||||||
import com.sunyard.chsm.model.dto.TmkStatus;
|
|
||||||
import com.sunyard.chsm.model.entity.Device;
|
|
||||||
import com.sunyard.chsm.model.entity.ParamConf;
|
|
||||||
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.EccPubKey;
|
|
||||||
import com.sunyard.chsm.utils.CodecUtils;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/10
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class TmkService {
|
|
||||||
|
|
||||||
private final SpDeviceMapper spDeviceMapper;
|
|
||||||
private final ParamConfMapper paramConfMapper;
|
|
||||||
|
|
||||||
public void initTmk() {
|
|
||||||
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 = sdfApi.generateRandom(hs, 16);
|
|
||||||
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), "密码机加解密异常");
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public TmkStatus getTMKStatus() {
|
|
||||||
TmkStatus status = new TmkStatus();
|
|
||||||
boolean init = isTmkInit();
|
|
||||||
if (init) {
|
|
||||||
status.setHasDevice(true);
|
|
||||||
status.setTmkInit(true);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
status.setTmkInit(false);
|
|
||||||
Device device = getOneByStatus(DeviceTmkStatus.available);
|
|
||||||
status.setHasDevice(device != null);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public DeviceCheckRes checkDevice(Device check) {
|
|
||||||
|
|
||||||
log.debug("==========> begin check device : {}", check);
|
|
||||||
DeviceCheckRes res = new DeviceCheckRes();
|
|
||||||
SdfApiAdapter sdfApi = SdfApiAdapterFactory.newInstance(check.getManufacturerModel(), check.getServiceIp(), check.getServicePort());
|
|
||||||
String hd = sdfApi.openDevice();
|
|
||||||
String hs = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
hs = sdfApi.openSession(hd);
|
|
||||||
DeviceInfo info = sdfApi.getDeviceInfo(hs);
|
|
||||||
log.debug("get DeviceInfo: {}", info);
|
|
||||||
res.setDeviceSerial(info.getDeviceSerial());
|
|
||||||
res.setStatus(DeviceTmkStatus.key_error);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("check device connect error: {}:{}", check.getServiceIp(), check.getServicePort(), e);
|
|
||||||
res.setHasError(true);
|
|
||||||
res.setStatus(DeviceTmkStatus.device_error);
|
|
||||||
res.setMessage(e.getMessage());
|
|
||||||
}
|
|
||||||
if (res.isHasError()) {
|
|
||||||
Optional.ofNullable(hs).ifPresent(sdfApi::closeSession);
|
|
||||||
Optional.ofNullable(hd).ifPresent(sdfApi::closeDevice);
|
|
||||||
log.debug("==========> end check device : {}", res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
EccPubKey pubKey = sdfApi.exportEncPublicKeyECC(hs, check.getEncKeyIdx());
|
|
||||||
if (Arrays.equals(pubKey.getPubKeyBytes(), new byte[64])) {
|
|
||||||
throw new IllegalArgumentException("加密密钥索引不正确");
|
|
||||||
}
|
|
||||||
res.setPubKey(pubKey.getPubKeyHex());
|
|
||||||
log.debug("export enc pubKey at index: {}, {}", check.getEncKeyIdx(), res.getPubKey());
|
|
||||||
sdfApi.getPrivateKeyAccessRight(hs, check.getEncKeyIdx(), check.getAccessCredentials().getBytes());
|
|
||||||
if (isTmkInit()) {
|
|
||||||
log.debug("tmk is init...");
|
|
||||||
EccCipher cipher;
|
|
||||||
if (Objects.equals(check.getDeviceSerial(), res.getDeviceSerial())
|
|
||||||
&& Objects.equals(check.getPubKey(), res.getPubKey())
|
|
||||||
&& StringUtils.hasText(check.getEncTmk())) {
|
|
||||||
cipher = EccCipher.fromHex(check.getEncTmk());
|
|
||||||
log.debug("device serial, pubKey not changed, use origin device enc tmk");
|
|
||||||
} else {
|
|
||||||
if (DeviceTmkStatus.finished.name().equals(check.getTmkStatus())) {
|
|
||||||
res.setStatus(DeviceTmkStatus.available);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
log.debug("device serial, pubKey is changed, or no tmk in origin device");
|
|
||||||
Device device = getOneByStatus(DeviceTmkStatus.finished);
|
|
||||||
Assert.notNull(device, "系统主密钥设备异常,请联系管理员排查");
|
|
||||||
log.debug("get device from finished: {}", device);
|
|
||||||
SdfApiAdapter tmkAdapter = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort());
|
|
||||||
String tmkHd = tmkAdapter.openDevice();
|
|
||||||
String tmkHs = tmkAdapter.openSession(tmkHd);
|
|
||||||
tmkAdapter.getPrivateKeyAccessRight(tmkHs, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
|
||||||
cipher = tmkAdapter.exchangeDigitEnvelopeBaseOnECC(tmkHs, device.getEncKeyIdx(), pubKey, EccCipher.fromHex(device.getEncTmk()));
|
|
||||||
log.debug("exchanged envelope from finished success ...");
|
|
||||||
}
|
|
||||||
String hk = sdfApi.importKeyWithISKECC(hs, check.getEncKeyIdx(), cipher);
|
|
||||||
sdfApi.destroyKey(hs, hk);
|
|
||||||
if (!Objects.equals(check.getEncTmk(), cipher.getC1C3C2Hex())) {
|
|
||||||
res.setEncTmk(cipher.getC1C3C2Hex());
|
|
||||||
}
|
|
||||||
res.setStatus(DeviceTmkStatus.finished);
|
|
||||||
} else {
|
|
||||||
log.debug("tmk not init, start encrypt and import test ...");
|
|
||||||
byte[] random = sdfApi.generateRandom(hs, 16);
|
|
||||||
EccCipher eccCipher = sdfApi.externalEncryptECC(hs, pubKey, random);
|
|
||||||
String hk = sdfApi.importKeyWithISKECC(hs, check.getEncKeyIdx(), eccCipher);
|
|
||||||
sdfApi.destroyKey(hs, hk);
|
|
||||||
res.setStatus(DeviceTmkStatus.available);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("check device encKey error: {}:{}", check.getServiceIp(), check.getServicePort(), e);
|
|
||||||
res.setHasError(true);
|
|
||||||
res.setStatus(DeviceTmkStatus.key_error);
|
|
||||||
res.setMessage(e.getMessage());
|
|
||||||
}
|
|
||||||
Optional.ofNullable(hs).ifPresent(sdfApi::closeSession);
|
|
||||||
Optional.ofNullable(hd).ifPresent(sdfApi::closeDevice);
|
|
||||||
res.setSdfApiAdapter(sdfApi);
|
|
||||||
log.debug("==========> end check device : {}", res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void checkSoftDeviceTmk() {
|
|
||||||
if (!isTmkInit() || !isEnableSoftDevice()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(getSoftDeviceEncTmk())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log.warn("enabled soft device but no tmk in soft");
|
|
||||||
Device device = getOneByStatus(DeviceTmkStatus.finished);
|
|
||||||
if (device == null || Objects.equals(device.getManufacturerModel(), BouncyCastleProvider.PROVIDER_NAME)) {
|
|
||||||
log.warn("data error, no tmk found in system");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SdfApiAdapter softAdapter = SdfApiAdapterFactory.getBcAdapter();
|
|
||||||
EccPubKey pubKey = softAdapter.exportEncPublicKeyECC("", 1);
|
|
||||||
|
|
||||||
SdfApiAdapter tmkAdapter = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort());
|
|
||||||
String tmkHd = tmkAdapter.openDevice();
|
|
||||||
String tmkHs = tmkAdapter.openSession(tmkHd);
|
|
||||||
tmkAdapter.getPrivateKeyAccessRight(tmkHs, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
|
||||||
EccCipher cipher = tmkAdapter.exchangeDigitEnvelopeBaseOnECC(tmkHs, device.getEncKeyIdx(), pubKey, EccCipher.fromHex(device.getEncTmk()));
|
|
||||||
|
|
||||||
updateSoftDeviceEncTmk(cipher.getC1C3C2Bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Device getOneByStatus(DeviceTmkStatus status) {
|
|
||||||
Device device = spDeviceMapper.selectOneByStatus(status);
|
|
||||||
if (Objects.nonNull(device)) {
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
if (isEnableSoftDevice()) {
|
|
||||||
device = new Device();
|
|
||||||
device.setManufacturerModel(BouncyCastleProvider.PROVIDER_NAME);
|
|
||||||
device.setEncKeyIdx(1);
|
|
||||||
device.setServiceIp("127.0.0.1");
|
|
||||||
device.setServicePort(8889);
|
|
||||||
device.setAccessCredentials("543");
|
|
||||||
if (isTmkInit()) {
|
|
||||||
device.setEncTmk(CodecUtils.encodeHex(getSoftDeviceEncTmk()));
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean tmkInit;
|
|
||||||
private boolean enableSoftDevice;
|
|
||||||
private byte[] softEncTmk;
|
|
||||||
|
|
||||||
public synchronized boolean isTmkInit() {
|
|
||||||
if (tmkInit) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
|
|
||||||
tmkInit = conf != null && String.valueOf(true).equals(conf.getValue());
|
|
||||||
return tmkInit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnableSoftDevice() {
|
|
||||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.ENABLE_SOFT_DEVICE);
|
|
||||||
return conf != null && String.valueOf(true).equals(conf.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTmkInit(boolean value) {
|
|
||||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
|
|
||||||
if (conf == null) {
|
|
||||||
conf = new ParamConf();
|
|
||||||
conf.setValue(String.valueOf(value));
|
|
||||||
conf.setKey(ParamConfKeyConstant.TMK_INIT);
|
|
||||||
conf.setCreatTime(LocalDateTime.now());
|
|
||||||
paramConfMapper.insert(conf);
|
|
||||||
} else {
|
|
||||||
conf.setValue(String.valueOf(value));
|
|
||||||
paramConfMapper.updateById(conf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized byte[] getSoftDeviceEncTmk() {
|
|
||||||
boolean tmkInit = isTmkInit();
|
|
||||||
Assert.isTrue(tmkInit, "主密钥未初始化");
|
|
||||||
boolean enabled = isEnableSoftDevice();
|
|
||||||
Assert.isTrue(enabled, "未启用软设备");
|
|
||||||
if (softEncTmk != null) {
|
|
||||||
return softEncTmk;
|
|
||||||
}
|
|
||||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.SOFT_ENC_TMK);
|
|
||||||
if (conf == null || ObjectUtils.isEmpty(conf.getValue())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
softEncTmk = CodecUtils.decodeBase64(conf.getValue());
|
|
||||||
return softEncTmk;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSoftDeviceEncTmk(byte[] encTmk) {
|
|
||||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.SOFT_ENC_TMK);
|
|
||||||
if (conf == null) {
|
|
||||||
conf = new ParamConf();
|
|
||||||
conf.setValue(CodecUtils.encodeBase64(encTmk));
|
|
||||||
conf.setKey(ParamConfKeyConstant.SOFT_ENC_TMK);
|
|
||||||
conf.setCreatTime(LocalDateTime.now());
|
|
||||||
paramConfMapper.insert(conf);
|
|
||||||
} else {
|
|
||||||
conf.setValue(CodecUtils.encodeBase64(encTmk));
|
|
||||||
paramConfMapper.updateById(conf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,6 @@ import com.sunyard.chsm.mapper.AppCertMapper;
|
|||||||
import com.sunyard.chsm.mapper.ApplicationMapper;
|
import com.sunyard.chsm.mapper.ApplicationMapper;
|
||||||
import com.sunyard.chsm.mapper.KeyInfoMapper;
|
import com.sunyard.chsm.mapper.KeyInfoMapper;
|
||||||
import com.sunyard.chsm.mapper.SpKeyRecordMapper;
|
import com.sunyard.chsm.mapper.SpKeyRecordMapper;
|
||||||
import com.sunyard.chsm.model.Subject;
|
|
||||||
import com.sunyard.chsm.model.dto.CertDTO;
|
import com.sunyard.chsm.model.dto.CertDTO;
|
||||||
import com.sunyard.chsm.model.entity.AppCert;
|
import com.sunyard.chsm.model.entity.AppCert;
|
||||||
import com.sunyard.chsm.model.entity.Application;
|
import com.sunyard.chsm.model.entity.Application;
|
||||||
@@ -25,7 +24,12 @@ import com.sunyard.chsm.utils.gm.BCSM4Utils;
|
|||||||
import com.sunyard.chsm.utils.gm.cert.BCSM2CertUtils;
|
import com.sunyard.chsm.utils.gm.cert.BCSM2CertUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.bouncycastle.asn1.*;
|
import org.bouncycastle.asn1.ASN1BitString;
|
||||||
|
import org.bouncycastle.asn1.ASN1Integer;
|
||||||
|
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||||
|
import org.bouncycastle.asn1.ASN1OctetString;
|
||||||
|
import org.bouncycastle.asn1.ASN1Sequence;
|
||||||
|
import org.bouncycastle.asn1.DLSequence;
|
||||||
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
|
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
|
||||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
@@ -45,7 +49,12 @@ import java.nio.ByteBuffer;
|
|||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -145,8 +154,6 @@ public class AppCertServiceImpl implements AppCertService {
|
|||||||
|
|
||||||
AppCert exist = appCertMapper.selectBySN(x509Cert.getSerialNumber().toString());
|
AppCert exist = appCertMapper.selectBySN(x509Cert.getSerialNumber().toString());
|
||||||
Assert.isNull(exist, "此证书已经存在");
|
Assert.isNull(exist, "此证书已经存在");
|
||||||
exist = appCertMapper.selectByTypeAndDn(importCert.getCertType(), x509Cert.getSubjectX500Principal().getName());
|
|
||||||
Assert.isNull(exist, "此证书主题已经存在");
|
|
||||||
|
|
||||||
AppCert cert = genCert(x509Cert, keyInfo.getApplicationId(), record, importCert);
|
AppCert cert = genCert(x509Cert, keyInfo.getApplicationId(), record, importCert);
|
||||||
appCertMapper.insert(cert);
|
appCertMapper.insert(cert);
|
||||||
@@ -222,8 +229,7 @@ public class AppCertServiceImpl implements AppCertService {
|
|||||||
cert.setCertText(importCert.getCertText());
|
cert.setCertText(importCert.getCertText());
|
||||||
|
|
||||||
cert.setVersion(String.valueOf(x509Cert.getVersion()));
|
cert.setVersion(String.valueOf(x509Cert.getVersion()));
|
||||||
Subject subject = Subject.fromDN(x509Cert.getSubjectX500Principal().getName());
|
cert.setSubject(x509Cert.getSubjectX500Principal().getName());
|
||||||
cert.setSubject(subject.getDN());
|
|
||||||
cert.setSerialNumber(x509Cert.getSerialNumber().toString());
|
cert.setSerialNumber(x509Cert.getSerialNumber().toString());
|
||||||
cert.setIssuerDn(x509Cert.getIssuerX500Principal().getName());
|
cert.setIssuerDn(x509Cert.getIssuerX500Principal().getName());
|
||||||
cert.setNotBefore(x509Cert.getNotBefore());
|
cert.setNotBefore(x509Cert.getNotBefore());
|
||||||
|
|||||||
@@ -88,6 +88,16 @@ public class KeyInfoServiceImpl implements KeyInfoService {
|
|||||||
private SdfApiService sdfApiService;
|
private SdfApiService sdfApiService;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyInfoDTO.KeyValue selectKeyInApp(KeyInfoDTO.Query query) {
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<KeyInfoDTO.KeyView> selectPageList(KeyInfoDTO.Query query) {
|
public Page<KeyInfoDTO.KeyView> selectPageList(KeyInfoDTO.Query query) {
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
@@ -159,36 +169,7 @@ public class KeyInfoServiceImpl implements KeyInfoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyInfoDTO.KeyView selectById(Long id) {
|
public Long save(KeyInfoDTO.KeySave save) {
|
||||||
KeyInfo keyInfo = keyInfoMapper.selectById(id);
|
|
||||||
Assert.notNull(keyInfo, "密钥ID不存在");
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
KeyInfoDTO.KeyView view = new KeyInfoDTO.KeyView();
|
|
||||||
BeanUtils.copyProperties(keyInfo, view);
|
|
||||||
Optional.of(keyInfo.getKeyType()).map(KeyCategory::of).map(KeyCategory::getDesc).ifPresent(view::setKeyTypeText);
|
|
||||||
Map<String, String> usageMap = KeyUsage.getUsage(keyInfo.getKeyUsage())
|
|
||||||
.stream()
|
|
||||||
.collect(Collectors.toMap(KeyUsage::getCode, KeyUsage::getDesc));
|
|
||||||
view.setKeyUsages(new ArrayList<>(usageMap.keySet()));
|
|
||||||
view.setKeyUsageText(String.join(",", usageMap.values()));
|
|
||||||
KeyStatus keyStatus = KeyStatus.of(keyInfo.getStatus());
|
|
||||||
if (KeyStatus.ENABLED == keyStatus) {
|
|
||||||
if (now.isBefore(keyInfo.getEffectiveTime())) {
|
|
||||||
view.setStatus(KeyStatus.WAIT_ENABLED.getCode());
|
|
||||||
view.setStatusText(KeyStatus.WAIT_ENABLED.getDesc());
|
|
||||||
} else if (now.isAfter(keyInfo.getExpiredTime())) {
|
|
||||||
view.setStatus(KeyStatus.EXPIRED.getCode());
|
|
||||||
view.setStatusText(KeyStatus.EXPIRED.getDesc());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ObjectUtils.isEmpty(view.getStatusText())) {
|
|
||||||
view.setStatusText(keyStatus.getDesc());
|
|
||||||
}
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Long> save(KeyInfoDTO.KeySave save) {
|
|
||||||
|
|
||||||
KeyTemplate keyTemplate = keyTemplateMapper.selectOne(
|
KeyTemplate keyTemplate = keyTemplateMapper.selectOne(
|
||||||
new LambdaQueryWrapper<KeyTemplate>()
|
new LambdaQueryWrapper<KeyTemplate>()
|
||||||
@@ -200,7 +181,7 @@ public class KeyInfoServiceImpl implements KeyInfoService {
|
|||||||
Assert.isTrue(EnableStatus.ENABLED.getCode().equals(app.getStatus()), "应用不是启用状态");
|
Assert.isTrue(EnableStatus.ENABLED.getCode().equals(app.getStatus()), "应用不是启用状态");
|
||||||
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
List<Long> ids = new ArrayList<>();
|
|
||||||
for (int i = 0; i < save.getGenNumber(); i++) {
|
for (int i = 0; i < save.getGenNumber(); i++) {
|
||||||
|
|
||||||
// 密钥信息
|
// 密钥信息
|
||||||
@@ -229,11 +210,9 @@ public class KeyInfoServiceImpl implements KeyInfoService {
|
|||||||
info.setCheckValue(record.getCheckValue());
|
info.setCheckValue(record.getCheckValue());
|
||||||
keyInfoMapper.insert(info);
|
keyInfoMapper.insert(info);
|
||||||
spKeyRecordMapper.insert(record);
|
spKeyRecordMapper.insert(record);
|
||||||
|
|
||||||
ids.add(info.getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ids;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -249,7 +228,7 @@ public class KeyInfoServiceImpl implements KeyInfoService {
|
|||||||
|
|
||||||
List<KeyInfo> keyInfos = keyInfoMapper.selectBatchIds(ids);
|
List<KeyInfo> keyInfos = keyInfoMapper.selectBatchIds(ids);
|
||||||
if (CollectionUtils.isEmpty(keyInfos)) {
|
if (CollectionUtils.isEmpty(keyInfos)) {
|
||||||
log.warn("updateKey no exist key with ids: {}", ids.stream().map(String::valueOf).collect(Collectors.joining(",")));
|
log.warn("enableKey no exist key with ids: {}", ids.stream().map(String::valueOf).collect(Collectors.joining(",")));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<String> unNormalCodes = keyInfos.stream()
|
List<String> unNormalCodes = keyInfos.stream()
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.sunyard.chsm.service.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.sunyard.chsm.mapper.KeyRecordMapper;
|
||||||
|
import com.sunyard.chsm.model.entity.KeyRecord;
|
||||||
|
import com.sunyard.chsm.service.KeyRecordService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Cheney
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class KeyRecordServiceImpl implements KeyRecordService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private KeyRecordMapper keyRecordMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyRecord selectById(Long id) {
|
||||||
|
return keyRecordMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyRecord selectByKeyId(Long keyId) {
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
LambdaQueryWrapper<KeyRecord> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
// 添加 keyId 的条件
|
||||||
|
queryWrapper.eq(KeyRecord::getKeyId, keyId);
|
||||||
|
// 添加 effectiveTime 小于当前时间的条件
|
||||||
|
queryWrapper.lt(KeyRecord::getEffectiveTime, now);
|
||||||
|
// 添加 expiredTime 大于当前时间的条件
|
||||||
|
queryWrapper.gt(KeyRecord::getExpiredTime, now);
|
||||||
|
|
||||||
|
return keyRecordMapper.selectOne(queryWrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
package com.sunyard.chsm.utils;
|
|
||||||
|
|
||||||
import org.bouncycastle.asn1.ASN1Integer;
|
|
||||||
import org.bouncycastle.asn1.ASN1Sequence;
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.security.Security;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.CertificateFactory;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
|
|
||||||
import static com.sunyard.chsm.utils.SydCmsUtil.readContentInfo;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zyh
|
|
||||||
* @since 2024/12/19
|
|
||||||
*/
|
|
||||||
public class CertUtil {
|
|
||||||
static {
|
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static X509Certificate convertToX509Cert(String certificateString) {
|
|
||||||
String pemCert;
|
|
||||||
if(certificateString.contains("-----BEGIN CERTIFICATE-----")){
|
|
||||||
pemCert =certificateString;
|
|
||||||
}else {
|
|
||||||
String cert_begin = "-----BEGIN CERTIFICATE-----\n";
|
|
||||||
String end_cert = "\n-----END CERTIFICATE-----";
|
|
||||||
pemCert = cert_begin + certificateString + end_cert;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
CertificateFactory CF = CertificateFactory.getInstance("X.509", "BC"); // 从证书工厂中获取X.509的单例类
|
|
||||||
return (X509Certificate) CF.generateCertificate(new ByteArrayInputStream(pemCert.getBytes())); // 将文件流的证书转化为证书类
|
|
||||||
} catch (CertificateException | NoSuchProviderException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static String getSn(String cert) {
|
|
||||||
try {
|
|
||||||
|
|
||||||
if(cert.contains("-----BEGIN CERTIFICATE-----")){
|
|
||||||
String[] lines = cert.split("\n");
|
|
||||||
// 构建新的证书字符串,去掉第一行和最后一行
|
|
||||||
StringBuilder cleanedCertificate = new StringBuilder();
|
|
||||||
for (int i = 1; i < lines.length - 1; i++) {
|
|
||||||
cleanedCertificate.append(lines[i]);
|
|
||||||
}
|
|
||||||
cert = cleanedCertificate.toString();
|
|
||||||
}
|
|
||||||
//从证书中获取sn
|
|
||||||
Object pkContent = readContentInfo(CodecUtils.decodeBase64(cert));
|
|
||||||
|
|
||||||
//逐级从结构体中获取需要的sn
|
|
||||||
ASN1Sequence pkSeq = ASN1Sequence.getInstance(pkContent);
|
|
||||||
ASN1Sequence pkSeq0 = (ASN1Sequence) pkSeq.getObjectAt(0).toASN1Primitive();
|
|
||||||
ASN1Integer sn = (ASN1Integer) pkSeq0.getObjectAt(1).toASN1Primitive();
|
|
||||||
String serNum = CodecUtils.encodeHex(sn.getEncoded());
|
|
||||||
|
|
||||||
//去掉长度
|
|
||||||
return serNum.substring(4);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package com.sunyard.chsm.utils;
|
|
||||||
|
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
|
||||||
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/6
|
|
||||||
*/
|
|
||||||
public abstract class CodecUtils {
|
|
||||||
|
|
||||||
public static String encodeBase64(byte[] data) {
|
|
||||||
return Base64.getEncoder().encodeToString(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] decodeBase64(String str) {
|
|
||||||
if (str == null || str.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Base64.getDecoder().decode(str);
|
|
||||||
} catch (Exception var3) {
|
|
||||||
if (str.length() > 32) {
|
|
||||||
str = str.substring(0, 32) + "...";
|
|
||||||
}
|
|
||||||
|
|
||||||
String format = String.format("参数[%s]不是正确的base64格式", str);
|
|
||||||
throw new IllegalArgumentException(format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String encodeHex(byte[] data) {
|
|
||||||
if (data == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return Hex.toHexString(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] decodeHex(String str) {
|
|
||||||
if (str == null || str.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Hex.decode(str);
|
|
||||||
} catch (Exception var3) {
|
|
||||||
if (str.length() > 32) {
|
|
||||||
str = str.substring(0, 32) + "...";
|
|
||||||
}
|
|
||||||
String format = String.format("参数[%s]不是正确的hex格式", str);
|
|
||||||
throw new IllegalArgumentException(format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
package com.sunyard.chsm.utils;
|
package com.sunyard.chsm.utils;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@@ -20,10 +18,4 @@ public abstract class DateFormat {
|
|||||||
public static final DateTimeFormatter DATE = DateTimeFormatter.ofPattern(YYYY_MM_DD);
|
public static final DateTimeFormatter DATE = DateTimeFormatter.ofPattern(YYYY_MM_DD);
|
||||||
public static final DateTimeFormatter DATE_TIME = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);
|
public static final DateTimeFormatter DATE_TIME = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);
|
||||||
|
|
||||||
|
|
||||||
public static String formDate(Date date) {
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
|
||||||
return sdf.format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
package com.sunyard.chsm.utils;
|
|
||||||
|
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
public class IpUtils {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取真实ip地址,避免获取代理ip
|
|
||||||
*/
|
|
||||||
public static String getIpAddress(HttpServletRequest request) {
|
|
||||||
if (request == null) {
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
String ip = request.getHeader("x-forwarded-for");
|
|
||||||
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
|
||||||
ip = request.getHeader("Proxy-Client-IP");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
|
||||||
ip = request.getHeader("X-Forwarded-For");
|
|
||||||
if (StringUtils.hasText(ip) && !"unknown".equalsIgnoreCase(ip)) {
|
|
||||||
// 多次反向代理后会有多个IP值,第一个为真实IP。
|
|
||||||
int index = ip.indexOf(',');
|
|
||||||
if (index != -1) {
|
|
||||||
ip = ip.substring(0, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
|
||||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
|
||||||
ip = request.getHeader("X-Real-IP");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
|
||||||
ip = request.getRemoteAddr();
|
|
||||||
}
|
|
||||||
if("0:0:0:0:0:0:0:1".equals(ip)){
|
|
||||||
return "127.0.0.1";
|
|
||||||
}else {
|
|
||||||
if(ip.equals("127.0.0.1") || ip.equalsIgnoreCase("localhost") && ObjectUtils.isEmpty(request.getRemoteAddr())){
|
|
||||||
ip = request.getRemoteAddr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package com.sunyard.chsm.utils;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.bouncycastle.asn1.*;
|
|
||||||
import org.bouncycastle.asn1.cms.EncryptedContentInfo;
|
|
||||||
|
|
||||||
import java.util.Enumeration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* SignedAndEnvelopedData ::=SEQUENCE {
|
|
||||||
* version Version,
|
|
||||||
* recipientInfos RecipientInfos,
|
|
||||||
* digestAlgorithms DigestAlgorithmIdentifiers
|
|
||||||
* encryptedContentInfo EncryptedContentInfo,
|
|
||||||
* certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
|
|
||||||
* crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
|
|
||||||
* signerInfos SignerInfos
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/25
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SignedAndEnvelopedData extends ASN1Object {
|
|
||||||
|
|
||||||
private ASN1Integer version;
|
|
||||||
private ASN1Set recipientInfos;
|
|
||||||
private ASN1Set digestAlgorithms;
|
|
||||||
private EncryptedContentInfo encryptedContentInfo;
|
|
||||||
private ASN1Set certificates;
|
|
||||||
private ASN1Set crls;
|
|
||||||
private ASN1Set signerInfos;
|
|
||||||
|
|
||||||
|
|
||||||
public static SignedAndEnvelopedData getInstance(
|
|
||||||
Object obj) {
|
|
||||||
if (obj instanceof SignedAndEnvelopedData) {
|
|
||||||
return (SignedAndEnvelopedData) obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj != null) {
|
|
||||||
return new SignedAndEnvelopedData(ASN1Sequence.getInstance(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SignedAndEnvelopedData(ASN1Sequence seq) {
|
|
||||||
Enumeration e = seq.getObjects();
|
|
||||||
|
|
||||||
version = ASN1Integer.getInstance(e.nextElement());
|
|
||||||
recipientInfos = ((ASN1Set) e.nextElement());
|
|
||||||
digestAlgorithms = ((ASN1Set) e.nextElement());
|
|
||||||
encryptedContentInfo = EncryptedContentInfo.getInstance(e.nextElement());
|
|
||||||
|
|
||||||
ASN1Set sigInfs = null;
|
|
||||||
while (e.hasMoreElements()) {
|
|
||||||
ASN1Primitive o = (ASN1Primitive) e.nextElement();
|
|
||||||
if (o instanceof ASN1TaggedObject) {
|
|
||||||
ASN1TaggedObject tagged = (ASN1TaggedObject) o;
|
|
||||||
switch (tagged.getTagNo()) {
|
|
||||||
case 0:
|
|
||||||
certificates = ASN1Set.getInstance(tagged, false);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
crls = ASN1Set.getInstance(tagged, false);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!(o instanceof ASN1Set)) {
|
|
||||||
throw new IllegalArgumentException("SET expected, not encountered");
|
|
||||||
}
|
|
||||||
sigInfs = (ASN1Set) o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sigInfs == null) {
|
|
||||||
throw new IllegalArgumentException("signerInfos not set");
|
|
||||||
}
|
|
||||||
signerInfos = sigInfs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ASN1Primitive toASN1Primitive() {
|
|
||||||
ASN1EncodableVector v = new ASN1EncodableVector(7);
|
|
||||||
v.add(version);
|
|
||||||
v.add(recipientInfos);
|
|
||||||
v.add(digestAlgorithms);
|
|
||||||
v.add(encryptedContentInfo);
|
|
||||||
if (certificates != null) {
|
|
||||||
v.add(new DERTaggedObject(false, 0, certificates));
|
|
||||||
}
|
|
||||||
if (crls != null) {
|
|
||||||
v.add(new DERTaggedObject(false, 1, crls));
|
|
||||||
}
|
|
||||||
v.add(signerInfos);
|
|
||||||
return new DLSequence(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
package com.sunyard.chsm.utils;
|
|
||||||
|
|
||||||
import org.bouncycastle.asn1.*;
|
|
||||||
import org.bouncycastle.asn1.cms.ContentInfo;
|
|
||||||
import org.bouncycastle.asn1.cms.EncryptedContentInfo;
|
|
||||||
import org.bouncycastle.asn1.cms.OriginatorInfo;
|
|
||||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
|
||||||
import org.bouncycastle.cms.CMSException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
public class SydCmsUtil {
|
|
||||||
|
|
||||||
public static Object readContentInfo(
|
|
||||||
byte[] input) {
|
|
||||||
ASN1InputStream is = new ASN1InputStream(input);
|
|
||||||
Object v = null;
|
|
||||||
try {
|
|
||||||
v = is.readObject();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Map<String, Object> getEncryptedContentInfo(ASN1Encodable obj){
|
|
||||||
Map<String, Object>map = new HashMap<String, Object>();
|
|
||||||
ASN1Sequence seq = ASN1Sequence.getInstance(obj );
|
|
||||||
if (seq.size() < 2)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Truncated Sequence Found");
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1ObjectIdentifier contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
|
|
||||||
map.put( "contentType", contentType );
|
|
||||||
|
|
||||||
AlgorithmIdentifier contentEncryptionAlgorithm = AlgorithmIdentifier.getInstance(
|
|
||||||
seq.getObjectAt(1));
|
|
||||||
|
|
||||||
map.put( "contentEncryptionAlgorithm", contentEncryptionAlgorithm );
|
|
||||||
|
|
||||||
if (seq.size() > 2)
|
|
||||||
{
|
|
||||||
ASN1OctetString encryptedContent = ASN1OctetString.getInstance(
|
|
||||||
(ASN1TaggedObject)seq.getObjectAt(2), false);
|
|
||||||
map.put( "encryptedContent", encryptedContent );
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, Object> getOriginatorInfo(ASN1TaggedObject obj,
|
|
||||||
boolean explicit){
|
|
||||||
Map<String, Object>map = new HashMap<String, Object>();
|
|
||||||
ASN1Sequence seq = ASN1Sequence.getInstance(obj, explicit);
|
|
||||||
switch (seq.size())
|
|
||||||
{
|
|
||||||
case 0: // empty
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0);
|
|
||||||
switch (o.getTagNo())
|
|
||||||
{
|
|
||||||
case 0 :
|
|
||||||
ASN1Set certs = ASN1Set.getInstance(o, false);
|
|
||||||
map.put("certs", certs);
|
|
||||||
break;
|
|
||||||
case 1 :
|
|
||||||
ASN1Set crls = ASN1Set.getInstance(o, false);
|
|
||||||
map.put("crls", crls);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Bad tag in OriginatorInfo: " + o.getTagNo());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
ASN1Set certs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(0), false);
|
|
||||||
map.put("certs", certs);
|
|
||||||
ASN1Set crls = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(1), false);
|
|
||||||
map.put("crls", crls);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("OriginatorInfo too big");
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// public static ContentInfo getContentInfo( byte[] input ) {
|
|
||||||
// Object content = readContentInfo( input );
|
|
||||||
// ASN1Sequence seq = ASN1Sequence.getInstance( content );
|
|
||||||
// return new ContentInfo(seq);
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static Map<String, Object> readCmsInfo( byte[] input ) throws CMSException {
|
|
||||||
Map<String, Object>map = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
Object content = readContentInfo( input );
|
|
||||||
ASN1Sequence seq = ASN1Sequence.getInstance( content );
|
|
||||||
ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) seq.getObjectAt(0);
|
|
||||||
map.put("oid", oid);
|
|
||||||
|
|
||||||
seq = ASN1Sequence.getInstance((ASN1TaggedObject) seq.getObjectAt(1), true);
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
ASN1Integer version = (ASN1Integer)seq.getObjectAt(index++);
|
|
||||||
map.put( "version", version );
|
|
||||||
|
|
||||||
Object tmp = seq.getObjectAt(index++);
|
|
||||||
|
|
||||||
if (tmp instanceof ASN1TaggedObject)
|
|
||||||
{
|
|
||||||
OriginatorInfo originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false);
|
|
||||||
// Map<String, Object>originatorInfo = getOriginatorInfo((ASN1TaggedObject)tmp, false);
|
|
||||||
map.put( "originatorInfo", originatorInfo );
|
|
||||||
tmp = seq.getObjectAt(index++);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Set recipientInfos = ASN1Set.getInstance(tmp);
|
|
||||||
map.put( "recipientInfos", recipientInfos );
|
|
||||||
|
|
||||||
EncryptedContentInfo encryptedContentInfo = EncryptedContentInfo.getInstance( seq.getObjectAt(index++) );
|
|
||||||
// Map<String, Object> encryptedContentInfo = getEncryptedContentInfo(seq.getObjectAt(index++));
|
|
||||||
map.put( "encryptedContentInfo", encryptedContentInfo );
|
|
||||||
|
|
||||||
if(seq.size() > index)
|
|
||||||
{
|
|
||||||
ASN1Set unprotectedAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false);
|
|
||||||
map.put( "unprotectedAttrs", unprotectedAttrs );
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -80,7 +80,7 @@ public class BCSM4Utils extends GMBaseUtil {
|
|||||||
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
|
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
|
||||||
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,
|
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,
|
||||||
InvalidAlgorithmParameterException {
|
InvalidAlgorithmParameterException {
|
||||||
Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.ENCRYPT_MODE, key, iv);
|
Cipher cipher = generateCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.ENCRYPT_MODE, key, iv);
|
||||||
return cipher.doFinal(data);
|
return cipher.doFinal(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ public class BCSM4Utils extends GMBaseUtil {
|
|||||||
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
|
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
|
||||||
NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
|
NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
|
||||||
InvalidAlgorithmParameterException {
|
InvalidAlgorithmParameterException {
|
||||||
Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.DECRYPT_MODE, key, iv);
|
Cipher cipher = generateCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.DECRYPT_MODE, key, iv);
|
||||||
return cipher.doFinal(cipherText);
|
return cipher.doFinal(cipherText);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ public class BCSM4Utils extends GMBaseUtil {
|
|||||||
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
|
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
|
||||||
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,
|
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,
|
||||||
InvalidAlgorithmParameterException {
|
InvalidAlgorithmParameterException {
|
||||||
Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.ENCRYPT_MODE, key, iv);
|
Cipher cipher = generateCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.ENCRYPT_MODE, key, iv);
|
||||||
return cipher.doFinal(data);
|
return cipher.doFinal(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ public class BCSM4Utils extends GMBaseUtil {
|
|||||||
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
|
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
|
||||||
NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
|
NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
|
||||||
InvalidAlgorithmParameterException {
|
InvalidAlgorithmParameterException {
|
||||||
Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.DECRYPT_MODE, key, iv);
|
Cipher cipher = generateCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.DECRYPT_MODE, key, iv);
|
||||||
return cipher.doFinal(cipherText);
|
return cipher.doFinal(cipherText);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ public class BCSM4Utils extends GMBaseUtil {
|
|||||||
return cipher;
|
return cipher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Cipher generateCBCCipher(String algorithmName, int mode, byte[] key, byte[] iv)
|
public static Cipher generateCipher(String algorithmName, int mode, byte[] key, byte[] iv)
|
||||||
throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
|
throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
|
||||||
NoSuchProviderException, NoSuchPaddingException {
|
NoSuchProviderException, NoSuchPaddingException {
|
||||||
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
|
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
|||||||
@@ -1,294 +0,0 @@
|
|||||||
package com.sunyard.chsm.utils.gm;
|
|
||||||
|
|
||||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
|
||||||
import org.bouncycastle.asn1.ASN1Encoding;
|
|
||||||
import org.bouncycastle.asn1.ASN1Integer;
|
|
||||||
import org.bouncycastle.asn1.ASN1Primitive;
|
|
||||||
import org.bouncycastle.asn1.ASN1Sequence;
|
|
||||||
import org.bouncycastle.asn1.DERSequence;
|
|
||||||
import org.bouncycastle.crypto.CipherParameters;
|
|
||||||
import org.bouncycastle.crypto.CryptoException;
|
|
||||||
import org.bouncycastle.crypto.CryptoServicesRegistrar;
|
|
||||||
import org.bouncycastle.crypto.Digest;
|
|
||||||
import org.bouncycastle.crypto.digests.SM3Digest;
|
|
||||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
|
||||||
import org.bouncycastle.crypto.params.ECKeyParameters;
|
|
||||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
|
||||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
|
||||||
import org.bouncycastle.crypto.params.ParametersWithID;
|
|
||||||
import org.bouncycastle.crypto.params.ParametersWithRandom;
|
|
||||||
import org.bouncycastle.crypto.signers.DSAKCalculator;
|
|
||||||
import org.bouncycastle.crypto.signers.RandomDSAKCalculator;
|
|
||||||
import org.bouncycastle.math.ec.ECAlgorithms;
|
|
||||||
import org.bouncycastle.math.ec.ECConstants;
|
|
||||||
import org.bouncycastle.math.ec.ECFieldElement;
|
|
||||||
import org.bouncycastle.math.ec.ECMultiplier;
|
|
||||||
import org.bouncycastle.math.ec.ECPoint;
|
|
||||||
import org.bouncycastle.math.ec.FixedPointCombMultiplier;
|
|
||||||
import org.bouncycastle.util.Arrays;
|
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 有的国密需求是用户可以自己做预处理,签名验签只是对预处理的结果进行签名和验签
|
|
||||||
*/
|
|
||||||
public class SM2PreprocessSigner implements ECConstants {
|
|
||||||
private static final int DIGEST_LENGTH = 32; // bytes
|
|
||||||
|
|
||||||
private final DSAKCalculator kCalculator = new RandomDSAKCalculator();
|
|
||||||
private Digest digest = null;
|
|
||||||
|
|
||||||
private ECDomainParameters ecParams;
|
|
||||||
private ECPoint pubPoint;
|
|
||||||
private ECKeyParameters ecKey;
|
|
||||||
private byte[] userID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化
|
|
||||||
*
|
|
||||||
* @param forSigning true表示用于签名,false表示用于验签
|
|
||||||
* @param param
|
|
||||||
*/
|
|
||||||
public void init(boolean forSigning, CipherParameters param) {
|
|
||||||
init(forSigning, new SM3Digest(), param);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化
|
|
||||||
*
|
|
||||||
* @param forSigning true表示用于签名,false表示用于验签
|
|
||||||
* @param digest SM2算法的话,一般是采用SM3摘要算法
|
|
||||||
* @param param
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public void init(boolean forSigning, Digest digest, CipherParameters param) throws RuntimeException {
|
|
||||||
CipherParameters baseParam;
|
|
||||||
|
|
||||||
if (digest.getDigestSize() != DIGEST_LENGTH) {
|
|
||||||
throw new RuntimeException("Digest size must be " + DIGEST_LENGTH);
|
|
||||||
}
|
|
||||||
this.digest = digest;
|
|
||||||
|
|
||||||
if (param instanceof ParametersWithID) {
|
|
||||||
baseParam = ((ParametersWithID) param).getParameters();
|
|
||||||
userID = ((ParametersWithID) param).getID();
|
|
||||||
} else {
|
|
||||||
baseParam = param;
|
|
||||||
userID = Hex.decode("31323334353637383132333435363738"); // the default value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forSigning) {
|
|
||||||
if (baseParam instanceof ParametersWithRandom) {
|
|
||||||
ParametersWithRandom rParam = (ParametersWithRandom) baseParam;
|
|
||||||
|
|
||||||
ecKey = (ECKeyParameters) rParam.getParameters();
|
|
||||||
ecParams = ecKey.getParameters();
|
|
||||||
kCalculator.init(ecParams.getN(), rParam.getRandom());
|
|
||||||
} else {
|
|
||||||
ecKey = (ECKeyParameters) baseParam;
|
|
||||||
ecParams = ecKey.getParameters();
|
|
||||||
kCalculator.init(ecParams.getN(), CryptoServicesRegistrar.getSecureRandom());
|
|
||||||
}
|
|
||||||
pubPoint = createBasePointMultiplier().multiply(ecParams.getG(), ((ECPrivateKeyParameters) ecKey).getD()).normalize();
|
|
||||||
} else {
|
|
||||||
ecKey = (ECKeyParameters) baseParam;
|
|
||||||
ecParams = ecKey.getParameters();
|
|
||||||
pubPoint = ((ECPublicKeyParameters) ecKey).getQ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 预处理,辅助方法
|
|
||||||
* ZA=H256(ENT LA ∥ IDA ∥ a ∥ b ∥ xG ∥yG ∥ xA ∥ yA)。
|
|
||||||
* M=ZA ∥ M;
|
|
||||||
* e = Hv(M)
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public byte[] preprocess(byte[] m) {
|
|
||||||
return preprocess(m, 0, m.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public byte[] preprocess(byte[] m, int off, int len) {
|
|
||||||
byte[] z = getZ(userID);
|
|
||||||
digest.update(z, 0, z.length);
|
|
||||||
digest.update(m, off, len);
|
|
||||||
byte[] eHash = new byte[DIGEST_LENGTH];
|
|
||||||
digest.doFinal(eHash, 0);
|
|
||||||
return eHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean verifySignature(byte[] eHash, byte[] signature) {
|
|
||||||
try {
|
|
||||||
BigInteger[] rs = derDecode(signature);
|
|
||||||
if (rs != null) {
|
|
||||||
return verifySignature(eHash, rs[0], rs[1]);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
digest.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] generateSignature(byte[] eHash) throws CryptoException {
|
|
||||||
BigInteger n = ecParams.getN();
|
|
||||||
BigInteger e = calculateE(eHash);
|
|
||||||
BigInteger d = ((ECPrivateKeyParameters) ecKey).getD();
|
|
||||||
|
|
||||||
BigInteger r, s;
|
|
||||||
|
|
||||||
ECMultiplier basePointMultiplier = createBasePointMultiplier();
|
|
||||||
|
|
||||||
// 5.2.1 Draft RFC: SM2 Public Key Algorithms
|
|
||||||
do // generate s
|
|
||||||
{
|
|
||||||
BigInteger k;
|
|
||||||
do // generate r
|
|
||||||
{
|
|
||||||
// A3
|
|
||||||
k = kCalculator.nextK();
|
|
||||||
|
|
||||||
// A4
|
|
||||||
ECPoint p = basePointMultiplier.multiply(ecParams.getG(), k).normalize();
|
|
||||||
|
|
||||||
// A5
|
|
||||||
r = e.add(p.getAffineXCoord().toBigInteger()).mod(n);
|
|
||||||
}
|
|
||||||
while (r.equals(ZERO) || r.add(k).equals(n));
|
|
||||||
|
|
||||||
// A6
|
|
||||||
BigInteger dPlus1ModN = d.add(ONE).modInverse(n);
|
|
||||||
|
|
||||||
s = k.subtract(r.multiply(d)).mod(n);
|
|
||||||
s = dPlus1ModN.multiply(s).mod(n);
|
|
||||||
}
|
|
||||||
while (s.equals(ZERO));
|
|
||||||
|
|
||||||
// A7
|
|
||||||
try {
|
|
||||||
return derEncode(r, s);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new CryptoException("unable to encode signature: " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean verifySignature(byte[] eHash, BigInteger r, BigInteger s) {
|
|
||||||
BigInteger n = ecParams.getN();
|
|
||||||
|
|
||||||
// 5.3.1 Draft RFC: SM2 Public Key Algorithms
|
|
||||||
// B1
|
|
||||||
if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// B2
|
|
||||||
if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// B3 eHash
|
|
||||||
|
|
||||||
// B4
|
|
||||||
BigInteger e = calculateE(eHash);
|
|
||||||
|
|
||||||
// B5
|
|
||||||
BigInteger t = r.add(s).mod(n);
|
|
||||||
if (t.equals(ZERO)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// B6
|
|
||||||
ECPoint q = ((ECPublicKeyParameters) ecKey).getQ();
|
|
||||||
ECPoint x1y1 = ECAlgorithms.sumOfTwoMultiplies(ecParams.getG(), s, q, t).normalize();
|
|
||||||
if (x1y1.isInfinity()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// B7
|
|
||||||
BigInteger expectedR = e.add(x1y1.getAffineXCoord().toBigInteger()).mod(n);
|
|
||||||
|
|
||||||
return expectedR.equals(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] digestDoFinal() {
|
|
||||||
byte[] result = new byte[digest.getDigestSize()];
|
|
||||||
digest.doFinal(result, 0);
|
|
||||||
|
|
||||||
reset();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] getZ(byte[] userID) {
|
|
||||||
digest.reset();
|
|
||||||
|
|
||||||
addUserID(digest, userID);
|
|
||||||
|
|
||||||
addFieldElement(digest, ecParams.getCurve().getA());
|
|
||||||
addFieldElement(digest, ecParams.getCurve().getB());
|
|
||||||
addFieldElement(digest, ecParams.getG().getAffineXCoord());
|
|
||||||
addFieldElement(digest, ecParams.getG().getAffineYCoord());
|
|
||||||
addFieldElement(digest, pubPoint.getAffineXCoord());
|
|
||||||
addFieldElement(digest, pubPoint.getAffineYCoord());
|
|
||||||
|
|
||||||
byte[] result = new byte[digest.getDigestSize()];
|
|
||||||
|
|
||||||
digest.doFinal(result, 0);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addUserID(Digest digest, byte[] userID) {
|
|
||||||
int len = userID.length * 8;
|
|
||||||
digest.update((byte) (len >> 8 & 0xFF));
|
|
||||||
digest.update((byte) (len & 0xFF));
|
|
||||||
digest.update(userID, 0, userID.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addFieldElement(Digest digest, ECFieldElement v) {
|
|
||||||
byte[] p = v.getEncoded();
|
|
||||||
digest.update(p, 0, p.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ECMultiplier createBasePointMultiplier() {
|
|
||||||
return new FixedPointCombMultiplier();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected BigInteger calculateE(byte[] message) {
|
|
||||||
return new BigInteger(1, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected BigInteger[] derDecode(byte[] encoding)
|
|
||||||
throws IOException {
|
|
||||||
ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(encoding));
|
|
||||||
if (seq.size() != 2) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
BigInteger r = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue();
|
|
||||||
BigInteger s = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue();
|
|
||||||
|
|
||||||
byte[] expectedEncoding = derEncode(r, s);
|
|
||||||
if (!Arrays.constantTimeAreEqual(expectedEncoding, encoding)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BigInteger[]{r, s};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected byte[] derEncode(BigInteger r, BigInteger s)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
|
||||||
v.add(new ASN1Integer(r));
|
|
||||||
v.add(new ASN1Integer(s));
|
|
||||||
return new DERSequence(v).getEncoded(ASN1Encoding.DER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -67,8 +67,7 @@ public class CommonCertUtils extends GMBaseUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static PKCS10CertificationRequest createCSR(X500Name subject, BCECPublicKey pubKey, PrivateKey priKey) throws OperatorCreationException {
|
public static PKCS10CertificationRequest createCSR(X500Name subject, BCECPublicKey pubKey, PrivateKey priKey) throws OperatorCreationException {
|
||||||
SM2PublicKey sm2SubPub = new SM2PublicKey(pubKey.getAlgorithm(), pubKey);
|
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(subject, pubKey);
|
||||||
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(subject, sm2SubPub);
|
|
||||||
ContentSigner signerBuilder = new JcaContentSignerBuilder("SM3withSM2")
|
ContentSigner signerBuilder = new JcaContentSignerBuilder("SM3withSM2")
|
||||||
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build(priKey);
|
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build(priKey);
|
||||||
return csrBuilder.build(signerBuilder);
|
return csrBuilder.build(signerBuilder);
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.sunyard.chsm.utils.gm.cert;
|
|
||||||
|
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
|
||||||
import org.bouncycastle.asn1.ASN1OctetString;
|
|
||||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
|
||||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
|
||||||
import org.bouncycastle.asn1.x9.X9ECPoint;
|
|
||||||
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
|
|
||||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
|
||||||
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
|
|
||||||
|
|
||||||
public class SM2PublicKey extends BCECPublicKey {
|
|
||||||
public static final ASN1ObjectIdentifier ID_SM2_PUBKEY_PARAM = new ASN1ObjectIdentifier("1.2.156.10197.1.301");
|
|
||||||
|
|
||||||
private boolean withCompression;
|
|
||||||
|
|
||||||
public SM2PublicKey(BCECPublicKey key) {
|
|
||||||
super(key.getAlgorithm(), key);
|
|
||||||
this.withCompression = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SM2PublicKey(String algorithm, BCECPublicKey key) {
|
|
||||||
super(algorithm, key);
|
|
||||||
this.withCompression = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getEncoded() {
|
|
||||||
ASN1OctetString p = ASN1OctetString.getInstance(
|
|
||||||
new X9ECPoint(getQ(), withCompression).toASN1Primitive());
|
|
||||||
|
|
||||||
// stored curve is null if ImplicitlyCa
|
|
||||||
SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
|
|
||||||
new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, ID_SM2_PUBKEY_PARAM),
|
|
||||||
p.getOctets());
|
|
||||||
|
|
||||||
return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPointFormat(String style) {
|
|
||||||
withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
package com.sunyard.chsm.utils.gm.cert;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
|
||||||
import org.bouncycastle.asn1.DERIA5String;
|
|
||||||
import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
|
|
||||||
import org.bouncycastle.asn1.x500.RDN;
|
|
||||||
import org.bouncycastle.asn1.x500.X500Name;
|
|
||||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
|
||||||
import org.bouncycastle.asn1.x500.style.IETFUtils;
|
|
||||||
import org.bouncycastle.asn1.x509.BasicConstraints;
|
|
||||||
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
|
|
||||||
import org.bouncycastle.asn1.x509.Extension;
|
|
||||||
import org.bouncycastle.asn1.x509.GeneralName;
|
|
||||||
import org.bouncycastle.asn1.x509.GeneralNames;
|
|
||||||
import org.bouncycastle.asn1.x509.KeyPurposeId;
|
|
||||||
import org.bouncycastle.asn1.x509.KeyUsage;
|
|
||||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
|
||||||
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
|
||||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
|
||||||
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
||||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
|
||||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SM2X509CertMaker {
|
|
||||||
|
|
||||||
private static enum CertLevel {
|
|
||||||
RootCA,
|
|
||||||
SubCA,
|
|
||||||
EndEntity
|
|
||||||
} // class CertLevel
|
|
||||||
|
|
||||||
public static final String SIGN_ALGO_SM3WITHSM2 = "SM3withSM2";
|
|
||||||
|
|
||||||
private long certExpire;
|
|
||||||
private X500Name issuerDN;
|
|
||||||
// private CertSNAllocator snAllocator;
|
|
||||||
private KeyPair issuerKeyPair;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param issuerKeyPair 证书颁发者的密钥对。
|
|
||||||
* 其实一般的CA的私钥都是要严格保护的。
|
|
||||||
* 一般CA的私钥都会放在加密卡/加密机里,证书的签名由加密卡/加密机完成。
|
|
||||||
* 这里仅是为了演示BC库签发证书的用法,所以暂时不作太多要求。
|
|
||||||
* @param certExpire 证书有效时间,单位毫秒
|
|
||||||
* @param issuer 证书颁发者信息
|
|
||||||
* @param snAllocator 维护/分配证书序列号的实例,证书序列号应该递增且不重复
|
|
||||||
*/
|
|
||||||
public SM2X509CertMaker(KeyPair issuerKeyPair, long certExpire, X500Name issuer)
|
|
||||||
// , CertSNAllocator snAllocator)
|
|
||||||
{
|
|
||||||
this.issuerKeyPair = issuerKeyPair;
|
|
||||||
this.certExpire = certExpire;
|
|
||||||
this.issuerDN = issuer;
|
|
||||||
// this.snAllocator = snAllocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成根CA证书
|
|
||||||
*
|
|
||||||
* @param csr CSR
|
|
||||||
* @return 新的证书
|
|
||||||
* @throws Exception 如果错误发生
|
|
||||||
*/
|
|
||||||
public X509Certificate makeRootCACert(byte[] csr)
|
|
||||||
throws Exception {
|
|
||||||
KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign);
|
|
||||||
return makeCertificate(CertLevel.RootCA, null, csr, usage, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成SubCA证书
|
|
||||||
*
|
|
||||||
* @param csr CSR
|
|
||||||
* @return 新的证书
|
|
||||||
* @throws Exception 如果错误发生
|
|
||||||
*/
|
|
||||||
public X509Certificate makeSubCACert(byte[] csr)
|
|
||||||
throws Exception {
|
|
||||||
KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign);
|
|
||||||
return makeCertificate(CertLevel.SubCA, 0, csr, usage, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成SSL用户证书
|
|
||||||
*
|
|
||||||
* @param csr CSR
|
|
||||||
* @return 新的证书
|
|
||||||
* @throws Exception 如果错误发生
|
|
||||||
*/
|
|
||||||
public X509Certificate makeSSLEndEntityCert(byte[] csr)
|
|
||||||
throws Exception {
|
|
||||||
return makeEndEntityCert(csr,
|
|
||||||
new KeyPurposeId[]{KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成用户证书
|
|
||||||
*
|
|
||||||
* @param csr CSR
|
|
||||||
* @param extendedKeyUsages 扩展指数用途。
|
|
||||||
* @return 新的证书
|
|
||||||
* @throws Exception 如果错误发生
|
|
||||||
*/
|
|
||||||
public X509Certificate makeEndEntityCert(byte[] csr,
|
|
||||||
KeyPurposeId[] extendedKeyUsages)
|
|
||||||
throws Exception {
|
|
||||||
KeyUsage usage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyAgreement
|
|
||||||
| KeyUsage.dataEncipherment | KeyUsage.keyEncipherment);
|
|
||||||
return makeCertificate(CertLevel.EndEntity, null, csr, usage, extendedKeyUsages);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param isCA 是否是颁发给CA的证书
|
|
||||||
* @param keyUsage 证书用途
|
|
||||||
* @param csr CSR
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private X509Certificate makeCertificate(CertLevel certLevel, Integer pathLenConstrain,
|
|
||||||
byte[] csr, KeyUsage keyUsage, KeyPurposeId[] extendedKeyUsages)
|
|
||||||
throws Exception {
|
|
||||||
if (certLevel == CertLevel.EndEntity) {
|
|
||||||
if (keyUsage.hasUsages(KeyUsage.keyCertSign)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"keyusage keyCertSign is not allowed in EndEntity Certificate");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PKCS10CertificationRequest request = new PKCS10CertificationRequest(csr);
|
|
||||||
SubjectPublicKeyInfo subPub = request.getSubjectPublicKeyInfo();
|
|
||||||
|
|
||||||
PrivateKey issPriv = issuerKeyPair.getPrivate();
|
|
||||||
PublicKey issPub = issuerKeyPair.getPublic();
|
|
||||||
|
|
||||||
X500Name subject = request.getSubject();
|
|
||||||
String email = null;
|
|
||||||
String commonName = null;
|
|
||||||
/*
|
|
||||||
* RFC 5280 §4.2.1.6 Subject
|
|
||||||
* Conforming implementations generating new certificates with
|
|
||||||
* electronic mail addresses MUST use the rfc822Name in the subject
|
|
||||||
* alternative name extension (Section 4.2.1.6) to describe such
|
|
||||||
* identities. Simultaneous inclusion of the emailAddress attribute in
|
|
||||||
* the subject distinguished name to support legacy implementations is
|
|
||||||
* deprecated but permitted.
|
|
||||||
*/
|
|
||||||
RDN[] rdns = subject.getRDNs();
|
|
||||||
List<RDN> newRdns = new ArrayList<>(rdns.length);
|
|
||||||
for (int i = 0; i < rdns.length; i++) {
|
|
||||||
RDN rdn = rdns[i];
|
|
||||||
|
|
||||||
AttributeTypeAndValue atv = rdn.getFirst();
|
|
||||||
ASN1ObjectIdentifier type = atv.getType();
|
|
||||||
if (BCStyle.EmailAddress.equals(type)) {
|
|
||||||
email = IETFUtils.valueToString(atv.getValue());
|
|
||||||
} else {
|
|
||||||
if (BCStyle.CN.equals(type)) {
|
|
||||||
commonName = IETFUtils.valueToString(atv.getValue());
|
|
||||||
}
|
|
||||||
newRdns.add(rdn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GeneralName> subjectAltNames = new LinkedList<>();
|
|
||||||
if (email != null) {
|
|
||||||
subject = new X500Name(newRdns.toArray(new RDN[0]));
|
|
||||||
subjectAltNames.add(
|
|
||||||
new GeneralName(GeneralName.rfc822Name,
|
|
||||||
new DERIA5String(email, true)));
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean selfSignedEECert = false;
|
|
||||||
switch (certLevel) {
|
|
||||||
case RootCA:
|
|
||||||
if (issuerDN.equals(subject)) {
|
|
||||||
subject = issuerDN;
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("subject != issuer for certLevel " + CertLevel.RootCA);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SubCA:
|
|
||||||
if (issuerDN.equals(subject)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"subject MUST not equals issuer for certLevel " + certLevel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (issuerDN.equals(subject)) {
|
|
||||||
selfSignedEECert = true;
|
|
||||||
subject = issuerDN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BigInteger serialNumber = snAllocator.nextSerialNumber();
|
|
||||||
BigInteger serialNumber = new BigInteger(IdWorker.getIdStr());
|
|
||||||
Date notBefore = new Date();
|
|
||||||
Date notAfter = new Date(notBefore.getTime() + certExpire);
|
|
||||||
X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(
|
|
||||||
issuerDN, serialNumber,
|
|
||||||
notBefore, notAfter,
|
|
||||||
subject, subPub);
|
|
||||||
|
|
||||||
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
|
|
||||||
v3CertGen.addExtension(Extension.subjectKeyIdentifier, false,
|
|
||||||
extUtils.createSubjectKeyIdentifier(subPub));
|
|
||||||
if (certLevel != CertLevel.RootCA && !selfSignedEECert) {
|
|
||||||
v3CertGen.addExtension(Extension.authorityKeyIdentifier, false,
|
|
||||||
extUtils.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(issPub.getEncoded())));
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 5280 §4.2.1.9 Basic Constraints:
|
|
||||||
// Conforming CAs MUST include this extension in all CA certificates
|
|
||||||
// that contain public keys used to validate digital signatures on
|
|
||||||
// certificates and MUST mark the extension as critical in such
|
|
||||||
// certificates.
|
|
||||||
BasicConstraints basicConstraints;
|
|
||||||
if (certLevel == CertLevel.EndEntity) {
|
|
||||||
basicConstraints = new BasicConstraints(false);
|
|
||||||
} else {
|
|
||||||
basicConstraints = pathLenConstrain == null
|
|
||||||
? new BasicConstraints(true) : new BasicConstraints(pathLenConstrain.intValue());
|
|
||||||
}
|
|
||||||
v3CertGen.addExtension(Extension.basicConstraints, true, basicConstraints);
|
|
||||||
|
|
||||||
// RFC 5280 §4.2.1.3 Key Usage: When present, conforming CAs SHOULD mark this extension as critical.
|
|
||||||
v3CertGen.addExtension(Extension.keyUsage, true, keyUsage);
|
|
||||||
|
|
||||||
if (extendedKeyUsages != null) {
|
|
||||||
ExtendedKeyUsage xku = new ExtendedKeyUsage(extendedKeyUsages);
|
|
||||||
v3CertGen.addExtension(Extension.extendedKeyUsage, false, xku);
|
|
||||||
|
|
||||||
boolean forSSLServer = false;
|
|
||||||
for (KeyPurposeId purposeId : extendedKeyUsages) {
|
|
||||||
if (KeyPurposeId.id_kp_serverAuth.equals(purposeId)) {
|
|
||||||
forSSLServer = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forSSLServer) {
|
|
||||||
if (commonName == null) {
|
|
||||||
throw new IllegalArgumentException("commonName must not be null");
|
|
||||||
}
|
|
||||||
GeneralName name = new GeneralName(GeneralName.dNSName,
|
|
||||||
new DERIA5String(commonName, true));
|
|
||||||
subjectAltNames.add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!subjectAltNames.isEmpty()) {
|
|
||||||
v3CertGen.addExtension(Extension.subjectAlternativeName, false,
|
|
||||||
new GeneralNames(subjectAltNames.toArray(new GeneralName[0])));
|
|
||||||
}
|
|
||||||
|
|
||||||
JcaContentSignerBuilder contentSignerBuilder = makeContentSignerBuilder(issPub);
|
|
||||||
X509Certificate cert = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
|
||||||
.getCertificate(v3CertGen.build(contentSignerBuilder.build(issPriv)));
|
|
||||||
cert.verify(issPub);
|
|
||||||
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JcaContentSignerBuilder makeContentSignerBuilder(PublicKey issPub) throws Exception {
|
|
||||||
if (issPub.getAlgorithm().equals("EC")) {
|
|
||||||
JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(SIGN_ALGO_SM3WITHSM2);
|
|
||||||
contentSignerBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME);
|
|
||||||
return contentSignerBuilder;
|
|
||||||
}
|
|
||||||
throw new Exception("Unsupported PublicKey Algorithm:" + issPub.getAlgorithm());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,13 +16,5 @@
|
|||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.validation</groupId>
|
|
||||||
<artifactId>jakarta.validation-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.sunyard.chsm.enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/10/22
|
|
||||||
*/
|
|
||||||
public enum HashAlg {
|
|
||||||
SM3,
|
|
||||||
;
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import javax.validation.constraints.Size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/11/13
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class AppTokenReq {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 平台分配的appKey
|
|
||||||
*/
|
|
||||||
@NotBlank
|
|
||||||
@Size(min = 16, max = 64, message = "appKey长度必须为16-64")
|
|
||||||
private String appKey;
|
|
||||||
/**
|
|
||||||
* 时间戳毫秒数,与服务器时间不能超过5分钟
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
private Long timestamp;
|
|
||||||
/**
|
|
||||||
* 使用appKey+random+appSecret作为原文,使用appSecret作为key,根据HmacSM3算法计算得到hmac值,转为Hex编码
|
|
||||||
*/
|
|
||||||
@NotBlank
|
|
||||||
@Size(min = 32, max = 64, message = "hmac长度在60-64之间")
|
|
||||||
private String hmac;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/11/13
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class AppTokenResp {
|
|
||||||
/**
|
|
||||||
* 获取的token的值
|
|
||||||
*/
|
|
||||||
private String token;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import javax.validation.constraints.Size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Wangjingcheng
|
|
||||||
* @Version 1.0.0
|
|
||||||
* @Date 2023/8/4 9:56
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class AsymDecryptReq {
|
|
||||||
// 密钥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;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymDecryptResp {
|
|
||||||
// 密钥ID
|
|
||||||
private Long keyId;
|
|
||||||
// 密钥索引
|
|
||||||
private String keyIndex;
|
|
||||||
// 明文,使用Base64编码
|
|
||||||
private String plainData;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymEncryptReq {
|
|
||||||
|
|
||||||
// 密钥ID
|
|
||||||
@NotNull(message = "密钥ID不能为空")
|
|
||||||
private Long keyId;
|
|
||||||
|
|
||||||
// 明文,使用Base64编码
|
|
||||||
@NotBlank(message = "明文不能为空")
|
|
||||||
private String plainData;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymEncryptResp {
|
|
||||||
|
|
||||||
// 密钥ID
|
|
||||||
private Long keyId;
|
|
||||||
|
|
||||||
// 密钥索引
|
|
||||||
private String keyIndex;
|
|
||||||
|
|
||||||
// 密文C1C3C2,使用Base64编码
|
|
||||||
private String cipherData;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymEnvelopeSealReq {
|
|
||||||
|
|
||||||
// 签名证书主题
|
|
||||||
private String signSubject;
|
|
||||||
|
|
||||||
// 接收者加密证书
|
|
||||||
@NotBlank(message = "加密证书不能为空")
|
|
||||||
private String encCert;
|
|
||||||
|
|
||||||
// 明文,使用Base64编码
|
|
||||||
@NotBlank(message = "明文不能为空")
|
|
||||||
private String plainData;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymEnvelopeSealResp {
|
|
||||||
|
|
||||||
// 数字信封。使用Base64编码
|
|
||||||
private String envelopeData;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymEnvelopeUnsealReq {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 加密证书的主题
|
|
||||||
*/
|
|
||||||
// @NotBlank(message = "加密证书不能为空")
|
|
||||||
// private String subject;
|
|
||||||
|
|
||||||
// 数字信封。使用Base64编码
|
|
||||||
@NotBlank(message = "数字信封不能为空")
|
|
||||||
private String envelopeData;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymEnvelopeUnsealResp {
|
|
||||||
|
|
||||||
|
|
||||||
// 明文,使用Base64编码
|
|
||||||
private String plainData;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymSignP7Req {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 签名证书的主题
|
|
||||||
*/
|
|
||||||
@NotBlank(message = "签名证书不能为空")
|
|
||||||
private String subject;
|
|
||||||
|
|
||||||
// 原文,使用Base64编码
|
|
||||||
@NotBlank(message = "原文不能为空")
|
|
||||||
private String plainData;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymSignP7Resp {
|
|
||||||
|
|
||||||
// 签名值 Base64编码
|
|
||||||
private String signData;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymSignRawReq {
|
|
||||||
|
|
||||||
// 密钥ID
|
|
||||||
@NotNull(message = "密钥ID不能为空")
|
|
||||||
private Long keyId;
|
|
||||||
|
|
||||||
// 原文,使用Base64编码
|
|
||||||
@NotBlank(message = "明文不能为空")
|
|
||||||
private String plainData;
|
|
||||||
|
|
||||||
// 是否进行预处理 默认是
|
|
||||||
private boolean preProcess = true;
|
|
||||||
|
|
||||||
// 预处理的userId,使用Base64编码
|
|
||||||
private String userId;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymSignRawResp {
|
|
||||||
|
|
||||||
// 密钥ID
|
|
||||||
private Long keyId;
|
|
||||||
|
|
||||||
// 密钥索引
|
|
||||||
private String keyIndex;
|
|
||||||
|
|
||||||
// 签名值 Base64编码
|
|
||||||
private String signData;
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AsymVerifyP7Req {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 签名证书的主题
|
|
||||||
*/
|
|
||||||
// @NotBlank(message = "签名证书不能为空")
|
|
||||||
// private String subject;
|
|
||||||
|
|
||||||
// 原文,使用Base64编码
|
|
||||||
private String plainData;
|
|
||||||
|
|
||||||
// 签名值, 使用Base64编码
|
|
||||||
@NotBlank(message = "签名值不能为空")
|
|
||||||
private String signData;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
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 AsymVerifyRawReq {
|
|
||||||
|
|
||||||
// 密钥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 signData;
|
|
||||||
|
|
||||||
// 原文,使用Base64编码
|
|
||||||
@NotBlank(message = "明文不能为空")
|
|
||||||
private String plainData;
|
|
||||||
|
|
||||||
// 是否进行预处理 默认是
|
|
||||||
private boolean preProcess = true;
|
|
||||||
|
|
||||||
// 预处理的userId,使用Base64编码
|
|
||||||
private String userId;
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zyh
|
|
||||||
* @since 2024/12/20
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class CertCheckResp {
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书有效期
|
|
||||||
*/
|
|
||||||
private String NotBefore;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书过期时间
|
|
||||||
*/
|
|
||||||
private String NotAfter;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书签名
|
|
||||||
* /
|
|
||||||
*/
|
|
||||||
private String Signature;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
CRL
|
|
||||||
*/
|
|
||||||
private String CRL;
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zyh
|
|
||||||
* @since 2024/12/19
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class CertExinfoResp {
|
|
||||||
|
|
||||||
// /*
|
|
||||||
// 密钥用法
|
|
||||||
// */
|
|
||||||
// private String SubjectDN;
|
|
||||||
|
|
||||||
/*
|
|
||||||
签名算法OID
|
|
||||||
*/
|
|
||||||
private String SigAlgOID;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书签名
|
|
||||||
*/
|
|
||||||
private String Signature;
|
|
||||||
|
|
||||||
// /*
|
|
||||||
// 证书约束
|
|
||||||
// */
|
|
||||||
// private String SubjectType;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zyh
|
|
||||||
* @since 2024/12/19
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class CertInfoResp {
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书主题
|
|
||||||
*/
|
|
||||||
private String SubjectDN;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书颁发者
|
|
||||||
*/
|
|
||||||
private String IssuerDN;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书序列号
|
|
||||||
*/
|
|
||||||
private String SerialNumber;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书有效期
|
|
||||||
*/
|
|
||||||
private String NotBefore;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书过期时间
|
|
||||||
*/
|
|
||||||
private String NotAfter;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书签名算法
|
|
||||||
*/
|
|
||||||
private String SigAlgName;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书公钥 hex格式
|
|
||||||
*/
|
|
||||||
private String PublicKey;
|
|
||||||
|
|
||||||
/*
|
|
||||||
证书版本
|
|
||||||
*/
|
|
||||||
private int Version;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/27
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ExportCertReq {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 证书的主题
|
|
||||||
*/
|
|
||||||
@NotBlank(message = "证书主题不能为空")
|
|
||||||
private String subject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 证书类型: encrypt_decrypt 加密证书, sign_verify 签名证书
|
|
||||||
*/
|
|
||||||
@NotBlank(message = "证书类型不能为空")
|
|
||||||
private String certType;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/27
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ExportCertResp {
|
|
||||||
|
|
||||||
// 证书内容, base64编码
|
|
||||||
private String certText;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/27
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ExportPubKeyReq {
|
|
||||||
|
|
||||||
// 密钥ID
|
|
||||||
@NotNull(message = "密钥ID不能为空")
|
|
||||||
private Long keyId;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/27
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ExportPubKeyResp {
|
|
||||||
|
|
||||||
// 密钥ID
|
|
||||||
private Long keyId;
|
|
||||||
|
|
||||||
// 密钥索引
|
|
||||||
private String keyIndex;
|
|
||||||
|
|
||||||
// 公钥:x+y, base64编码
|
|
||||||
private String pubKey;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.Max;
|
|
||||||
import javax.validation.constraints.Min;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/25
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class GenRandomReq {
|
|
||||||
|
|
||||||
// 随机数长度, 最大10240
|
|
||||||
@NotNull(message = "随机数长度不能为空")
|
|
||||||
@Min(value = 1L, message = "随机数长度最小为1")
|
|
||||||
@Max(value = 1024L, message = "随机数长度最大为1024")
|
|
||||||
private Integer length;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/25
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class GenRandomResp {
|
|
||||||
|
|
||||||
// 随机数, base64编码
|
|
||||||
private String random;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import com.sunyard.chsm.enums.HashAlg;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class HashReq {
|
|
||||||
|
|
||||||
// 明文,使用Base64编码
|
|
||||||
private String plainData;
|
|
||||||
|
|
||||||
// 句柄, 多包计算Init后返回
|
|
||||||
private String handle;
|
|
||||||
// Hash算法, 默认SM3
|
|
||||||
private HashAlg alg = HashAlg.SM3;
|
|
||||||
|
|
||||||
// 公钥,使用Base64编码
|
|
||||||
private String pubKey;
|
|
||||||
// userId,使用Base64编码
|
|
||||||
private String userId;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class HashResp {
|
|
||||||
|
|
||||||
// 句柄, 多包计算Init后返回
|
|
||||||
private String handle;
|
|
||||||
|
|
||||||
// mac值,使用Base64编码
|
|
||||||
private String hash;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/27
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ImportCertReq {
|
|
||||||
/**
|
|
||||||
* 密钥算法 目前支持: SM2
|
|
||||||
*/
|
|
||||||
@NotEmpty(message = "密钥算法不能为空")
|
|
||||||
private String keyAlg;
|
|
||||||
/**
|
|
||||||
* 是否单证,
|
|
||||||
*/
|
|
||||||
@NotNull(message = "单双证不能为空")
|
|
||||||
private Boolean single;
|
|
||||||
/**
|
|
||||||
* 证书类型: encrypt_decrypt 加密证书, sign_verify 签名证书
|
|
||||||
*/
|
|
||||||
private String certType;
|
|
||||||
/**
|
|
||||||
* 单证证书内容
|
|
||||||
*/
|
|
||||||
private String certText;
|
|
||||||
/**
|
|
||||||
* 签名证书内容
|
|
||||||
*/
|
|
||||||
private String signCertText;
|
|
||||||
/**
|
|
||||||
* 加密证书内容
|
|
||||||
*/
|
|
||||||
private String encCertText;
|
|
||||||
/**
|
|
||||||
* 加密密钥信封
|
|
||||||
*/
|
|
||||||
private String envelopedKey;
|
|
||||||
private String remark;
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import javax.validation.constraints.Max;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/17
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class KeyCreateReq {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密钥模版编码
|
|
||||||
*/
|
|
||||||
@NotNull(message = "密钥模版不能为空")
|
|
||||||
private String keyTemplateCode;
|
|
||||||
/**
|
|
||||||
* 生成数量
|
|
||||||
*/
|
|
||||||
@NotNull(message = "生成数量不能为空")
|
|
||||||
@Max(value = 100, message = "一次最多生成100个密钥")
|
|
||||||
private Integer genNumber;
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import com.sunyard.chsm.enums.KeyCategory;
|
|
||||||
import com.sunyard.chsm.enums.KeyStatus;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/17
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class KeyInfoQuery {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前页
|
|
||||||
*/
|
|
||||||
private int pageNumber = 1;
|
|
||||||
/**
|
|
||||||
* 每页大小
|
|
||||||
*/
|
|
||||||
private int pageSize = 10;
|
|
||||||
/**
|
|
||||||
* 密钥状态
|
|
||||||
*/
|
|
||||||
private KeyStatus status;
|
|
||||||
/**
|
|
||||||
* 密钥类型
|
|
||||||
*/
|
|
||||||
private KeyCategory keyType;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/17
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class KeyInfoResp {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密钥ID
|
|
||||||
*/
|
|
||||||
private Long KeyId;
|
|
||||||
/**
|
|
||||||
* 密钥算法
|
|
||||||
*/
|
|
||||||
private String keyAlg;
|
|
||||||
/**
|
|
||||||
* 密钥类型
|
|
||||||
*/
|
|
||||||
private String keyType;
|
|
||||||
private String keyTypeText;
|
|
||||||
/**
|
|
||||||
* 密钥用途
|
|
||||||
*/
|
|
||||||
private List<String> keyUsages;
|
|
||||||
private String keyUsageText;
|
|
||||||
/**
|
|
||||||
* 校验算法
|
|
||||||
*/
|
|
||||||
private String checkAlg;
|
|
||||||
/**
|
|
||||||
* 校验值
|
|
||||||
*/
|
|
||||||
private String checkValue;
|
|
||||||
/**
|
|
||||||
* 密钥状态
|
|
||||||
*/
|
|
||||||
private String status;
|
|
||||||
private String statusText;
|
|
||||||
/**
|
|
||||||
* 生效时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime effectiveTime;
|
|
||||||
/**
|
|
||||||
* 过期时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime expiredTime;
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import javax.validation.constraints.Size;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/17
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class KeyManageReq {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密钥id列表
|
|
||||||
*/
|
|
||||||
@Size(min = 1, max = 100, message = "密钥id列表长度在1-100之间")
|
|
||||||
@NotNull(message = "密钥id列表不能为空")
|
|
||||||
private List<Long> ids;
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package com.sunyard.chsm.param;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import javax.validation.constraints.Size;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liulu
|
|
||||||
* @since 2024/12/17
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class KeyUpdateReq {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密钥id列表
|
|
||||||
*/
|
|
||||||
@Size(min = 1, max = 100, message = "密钥id列表长度在1-100之间")
|
|
||||||
@NotNull(message = "密钥id列表不能为空")
|
|
||||||
private List<Long> ids;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新密钥生效时间 yyyy-MM-dd
|
|
||||||
*/
|
|
||||||
private LocalDate effectiveTime;
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user