密钥管理接口
This commit is contained in:
@@ -49,6 +49,10 @@
|
||||
<artifactId>jedis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>javax.persistence-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.dm</groupId>
|
||||
<artifactId>DmJdbcDriver</artifactId>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.sunyard.chsm.controller;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/10/29
|
||||
*/
|
||||
public class ApplicationController {
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* 非对称密钥管理接口
|
||||
*
|
||||
* @author liulu
|
||||
* @since 2024/10/28
|
||||
*/
|
||||
@@ -71,5 +72,14 @@ public class KeyInfoAsymController {
|
||||
.body(new ByteArrayResource(content));
|
||||
}
|
||||
|
||||
@PostMapping("/createCsr")
|
||||
public R<KeyInfoDTO.CreateCSRResp> createCsr(KeyInfoDTO.CreateCsr createCsr) {
|
||||
|
||||
String csr = keyInfoService.createCsr(createCsr);
|
||||
|
||||
KeyInfoDTO.CreateCSRResp resp = new KeyInfoDTO.CreateCSRResp();
|
||||
resp.setCsr(csr);
|
||||
return R.data(resp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.sunyard.chsm.dto;
|
||||
|
||||
import com.sunyard.chsm.model.PageQuery;
|
||||
import com.sunyard.chsm.model.Subject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@@ -118,5 +119,21 @@ public abstract class KeyInfoDTO {
|
||||
|
||||
}
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public static class CreateCsr extends Subject {
|
||||
/**
|
||||
* 密钥id
|
||||
*/
|
||||
@NotNull(message = "密钥id不能为空")
|
||||
private Long id;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class CreateCSRResp {
|
||||
// 证书请求内容
|
||||
private String csr;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ public interface KeyInfoService {
|
||||
|
||||
String recoveryKey(InputStream is);
|
||||
|
||||
String createCsr(KeyInfoDTO.CreateCsr createCsr);
|
||||
|
||||
void enableKey(List<Long> ids);
|
||||
|
||||
void disableKey(List<Long> ids);
|
||||
|
||||
+98
-7
@@ -9,9 +9,11 @@ import com.sunyard.chsm.dto.KeyInfoDTO;
|
||||
import com.sunyard.chsm.enums.KeyCategory;
|
||||
import com.sunyard.chsm.enums.KeyStatus;
|
||||
import com.sunyard.chsm.enums.KeyUsage;
|
||||
import com.sunyard.chsm.mapper.KeyCsrMapper;
|
||||
import com.sunyard.chsm.mapper.KeyInfoMapper;
|
||||
import com.sunyard.chsm.mapper.KeyTemplateMapper;
|
||||
import com.sunyard.chsm.mapper.SpKeyRecordMapper;
|
||||
import com.sunyard.chsm.model.entity.KeyCsr;
|
||||
import com.sunyard.chsm.model.entity.KeyInfo;
|
||||
import com.sunyard.chsm.model.entity.KeyRecord;
|
||||
import com.sunyard.chsm.model.entity.KeyTemplate;
|
||||
@@ -19,9 +21,23 @@ import com.sunyard.chsm.sdf.SdfApiService;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.service.KeyInfoService;
|
||||
import com.sunyard.chsm.utils.JsonUtils;
|
||||
import com.sunyard.chsm.utils.gm.BCECUtils;
|
||||
import com.sunyard.chsm.utils.gm.cert.CommonCertUtils;
|
||||
import com.sunyard.chsm.utils.gm.cert.SM2PublicKey;
|
||||
import com.sunyard.chsm.utils.gm.cert.SM2X509CertMaker;
|
||||
import com.sunyard.ssp.common.exception.SspwebException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.bouncycastle.util.io.pem.PemObject;
|
||||
import org.bouncycastle.util.io.pem.PemWriter;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -35,12 +51,14 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -55,6 +73,8 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class KeyInfoServiceImpl implements KeyInfoService {
|
||||
|
||||
@Resource
|
||||
private KeyCsrMapper keyCsrMapper;
|
||||
@Resource
|
||||
private KeyInfoMapper keyInfoMapper;
|
||||
@Resource
|
||||
@@ -210,18 +230,20 @@ public class KeyInfoServiceImpl implements KeyInfoService {
|
||||
|
||||
if (KeyCategory.SYM_KEY.getCode().equals(info.getKeyType())) {
|
||||
byte[] symKey = sdfApiService.generateRandom(16);
|
||||
record.setKeyData(Hex.encodeHexString(symKey));
|
||||
String checkHash = Hex.encodeHexString(sdfApiService.hash(symKey));
|
||||
byte[] encSymKey = sdfApiService.encryptByMKNoPadding(symKey);
|
||||
record.setKeyData(Hex.toHexString(encSymKey));
|
||||
String checkHash = Hex.toHexString(sdfApiService.hash(symKey));
|
||||
record.setCheckValue(checkHash);
|
||||
} else {
|
||||
EccKey eccKey = sdfApiService.genKeyPairEcc();
|
||||
byte[] d = eccKey.getPriKey().getD();
|
||||
record.setKeyData(Hex.encodeHexString(d));
|
||||
String checkHash = Hex.encodeHexString(sdfApiService.hash(d));
|
||||
byte[] encD = sdfApiService.encryptByMKNoPadding(d);
|
||||
record.setKeyData(Hex.toHexString(encD));
|
||||
String checkHash = Hex.toHexString(sdfApiService.hash(d));
|
||||
record.setCheckValue(checkHash);
|
||||
|
||||
byte[] pubKeyBytes = eccKey.getPubKey().getPubKeyBytes();
|
||||
record.setPubKey(Hex.encodeHexString(pubKeyBytes));
|
||||
record.setPubKey(Hex.toHexString(pubKeyBytes));
|
||||
}
|
||||
return record;
|
||||
}
|
||||
@@ -254,7 +276,7 @@ public class KeyInfoServiceImpl implements KeyInfoService {
|
||||
public String recoveryKey(InputStream is) {
|
||||
int suc = 0, count = 0, err = 0, exd = 0;
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))){
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
|
||||
String line;
|
||||
while (true) {
|
||||
try {
|
||||
@@ -290,6 +312,75 @@ public class KeyInfoServiceImpl implements KeyInfoService {
|
||||
return String.format("恢复完成,共%d条数据,跳过已经存在的密钥%d条,恢复成功%d条,解析失败%d条", count, exd, suc, err);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createCsr(KeyInfoDTO.CreateCsr createCsr) {
|
||||
|
||||
String subject = createCsr.getDN();
|
||||
KeyCsr exist = keyCsrMapper.selectBySubject(subject);
|
||||
if (Objects.nonNull(exist)) {
|
||||
if (Objects.equals(exist.getKeyId(), createCsr.getId())) {
|
||||
return exist.getCsrTxt();
|
||||
}
|
||||
throw new IllegalArgumentException("此证书主题已经被使用!");
|
||||
}
|
||||
KeyInfo keyInfo = keyInfoMapper.selectById(createCsr.getId());
|
||||
Assert.notNull(keyInfo, "密钥不存在!");
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
Assert.isTrue(KeyCategory.ASYM_KEY.getCode().equals(keyInfo.getKeyType())
|
||||
&& KeyStatus.ENABLED.getCode().equals(keyInfo.getStatus())
|
||||
&& now.isAfter(keyInfo.getEffectiveTime())
|
||||
&& now.isBefore(keyInfo.getExpiredTime()),
|
||||
"只能选择已启用的非对称密钥生成证书请求");
|
||||
KeyRecord record = spKeyRecordMapper.selectUsedByKeyId(keyInfo.getId());
|
||||
Assert.notNull(record, "数据异常,没有在使用中的密钥");
|
||||
|
||||
X500Name dn = new X500Name(subject);
|
||||
|
||||
byte[] xy = Hex.decode(record.getPubKey());
|
||||
byte[] x = Arrays.copyOfRange(xy, 0, 32);
|
||||
byte[] y = Arrays.copyOfRange(xy, 32, 64);
|
||||
ECPublicKeyParameters pubKeyParam = BCECUtils.createECPublicKeyParameters(x, y);
|
||||
|
||||
byte[] priKeyBytes = sdfApiService.decryptByMKNoPadding(Hex.decode(record.getKeyData()));
|
||||
// byte[][] pri18 = LangUtils.splitAverage(priKeyBytes);
|
||||
ECPrivateKeyParameters priKeyParam = BCECUtils.createECPrivateKeyParameters(priKeyBytes);
|
||||
ECDomainParameters domainParams = priKeyParam.getParameters();
|
||||
ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(), domainParams.getN(), domainParams.getH());
|
||||
BCECPublicKey pubKey = new BCECPublicKey("EC", pubKeyParam, spec, BouncyCastleProvider.CONFIGURATION);
|
||||
BCECPrivateKey priKey = new BCECPrivateKey("EC", priKeyParam, pubKey, spec, BouncyCastleProvider.CONFIGURATION);
|
||||
//
|
||||
SM2PublicKey sm2SubPub = new SM2PublicKey(pubKey.getAlgorithm(), pubKey);
|
||||
String csrTxt;
|
||||
try {
|
||||
byte[] csr = CommonCertUtils.createCSR(dn, sm2SubPub, priKey, SM2X509CertMaker.SIGN_ALGO_SM3WITHSM2).getEncoded();
|
||||
|
||||
PemObject pem = new PemObject("CERTIFICATE REQUEST", csr);
|
||||
StringWriter str = new StringWriter();
|
||||
PemWriter pemWriter = new PemWriter(str);
|
||||
pemWriter.writeObject(pem);
|
||||
pemWriter.close();
|
||||
str.close();
|
||||
|
||||
csrTxt = str.toString();
|
||||
} catch (Exception e) {
|
||||
log.error("生成CSR异常", e);
|
||||
throw new IllegalArgumentException("生成证书请求异常");
|
||||
}
|
||||
KeyCsr csr = new KeyCsr();
|
||||
csr.setId(IdWorker.getId());
|
||||
csr.setApplicationId(keyInfo.getApplicationId());
|
||||
csr.setKeyId(keyInfo.getId());
|
||||
csr.setKeyRecordId(record.getId());
|
||||
csr.setPubKey(record.getPubKey());
|
||||
csr.setKeyData(record.getKeyData());
|
||||
csr.setSubject(subject);
|
||||
csr.setCreateTime(LocalDateTime.now());
|
||||
csr.setCsrTxt(csrTxt);
|
||||
keyCsrMapper.insert(csr);
|
||||
return csrTxt;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void enableKey(List<Long> ids) {
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
|
||||
+5
-5
@@ -42,13 +42,13 @@ public class KeyTemplateServiceImpl implements KeyTemplateService {
|
||||
|
||||
@Override
|
||||
public Page<KeyTemplateDTO.KTView> selectPageList(KeyTemplateDTO.Query query) {
|
||||
LambdaQueryWrapper<KeyTemplate> wrapper = new LambdaQueryWrapper<KeyTemplate>()
|
||||
.eq(StringUtils.hasText(query.getKeyType()), KeyTemplate::getKeyType, query.getKeyType())
|
||||
.orderByDesc(KeyTemplate::getCreateTime);
|
||||
|
||||
IPage<KeyTemplate> page = keyTemplateMapper.selectPage(
|
||||
new Page<>(query.getPageNumber(), query.getPageSize()),
|
||||
wrapper);
|
||||
new LambdaQueryWrapper<KeyTemplate>()
|
||||
.eq(StringUtils.hasText(query.getKeyType()), KeyTemplate::getKeyType, query.getKeyType())
|
||||
.orderByDesc(KeyTemplate::getCreateTime)
|
||||
);
|
||||
List<KeyTemplate> records = page.getRecords();
|
||||
if (CollectionUtils.isEmpty(records)) {
|
||||
return new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
||||
@@ -145,7 +145,7 @@ public class KeyTemplateServiceImpl implements KeyTemplateService {
|
||||
.map(KeyUsage::valueOf)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (KeyCategory.SYM_KEY == keyCategory ) {
|
||||
if (KeyCategory.SYM_KEY == keyCategory) {
|
||||
Assert.isTrue(!usageList.contains(KeyUsage.SIGN_VERIFY), "对称密钥不能用于签名验签");
|
||||
} else {
|
||||
Assert.isTrue(!usageList.contains(KeyUsage.HMAC), "非对称密钥不能用于计算HMac");
|
||||
|
||||
Reference in New Issue
Block a user