diff --git a/chsm-common/src/main/java/com/sunyard/chsm/mapper/AppCertMapper.java b/chsm-common/src/main/java/com/sunyard/chsm/mapper/AppCertMapper.java index 3fa90e3..234709a 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/mapper/AppCertMapper.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/mapper/AppCertMapper.java @@ -43,5 +43,18 @@ public interface AppCertMapper extends BaseMapper { return certs.iterator().next(); } + default AppCert selectEncBySubject(String dn) { + Assert.hasText(dn, "证书序列号不能为空"); + String subject = Subject.fromDN(dn).getDN(); + List certs = selectList(new LambdaQueryWrapper() + .eq(AppCert::getSubject, subject) + .eq(AppCert::getCertType, KeyUsage.ENCRYPT_DECRYPT.getCode()) + ); + if (CollectionUtils.isEmpty(certs)) { + return null; + } + return certs.iterator().next(); + } + } diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeSealReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeSealReq.java new file mode 100644 index 0000000..d1d1762 --- /dev/null +++ b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeSealReq.java @@ -0,0 +1,20 @@ +package com.sunyard.chsm.param; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +public class AsymEnvelopeSealReq { + + /** + * 证书主题 + */ + @NotBlank(message = "证书主题不能为空") + private String subject; + + // 明文,使用Base64编码 + @NotBlank(message = "明文不能为空") + private String plainData; + +} diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeSealResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeSealResp.java new file mode 100644 index 0000000..e291dca --- /dev/null +++ b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeSealResp.java @@ -0,0 +1,11 @@ +package com.sunyard.chsm.param; + +import lombok.Data; + +@Data +public class AsymEnvelopeSealResp { + + // 数字信封。使用Base64编码 + private String envelopeData; + +} diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeUnsealReq.java b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeUnsealReq.java new file mode 100644 index 0000000..5b83c23 --- /dev/null +++ b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeUnsealReq.java @@ -0,0 +1,21 @@ +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; + + +} diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeUnsealResp.java b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeUnsealResp.java new file mode 100644 index 0000000..002ae50 --- /dev/null +++ b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymEnvelopeUnsealResp.java @@ -0,0 +1,12 @@ +package com.sunyard.chsm.param; + +import lombok.Data; + +@Data +public class AsymEnvelopeUnsealResp { + + + // 明文,使用Base64编码 + private String plainData; + +} diff --git a/chsm-params/src/main/java/com/sunyard/chsm/param/AsymVerifyP7Req.java b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymVerifyP7Req.java index d556b4c..e2b397d 100644 --- a/chsm-params/src/main/java/com/sunyard/chsm/param/AsymVerifyP7Req.java +++ b/chsm-params/src/main/java/com/sunyard/chsm/param/AsymVerifyP7Req.java @@ -14,10 +14,10 @@ public class AsymVerifyP7Req { // private String subject; // 原文,使用Base64编码 - @NotBlank(message = "明文不能为空") private String plainData; // 签名值, 使用Base64编码 + @NotBlank(message = "签名值不能为空") private String signData; } diff --git a/chsm-web-server/pom.xml b/chsm-web-server/pom.xml index cb2620c..69c9382 100644 --- a/chsm-web-server/pom.xml +++ b/chsm-web-server/pom.xml @@ -25,12 +25,6 @@ ${project.version} - - com.sunyard.chsm - chsm-web-manage - ${project.version} - - com.dm DmJdbcDriver diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/AsymKeyController.java b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/AsymKeyController.java index 518c4cc..8154074 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/AsymKeyController.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/AsymKeyController.java @@ -3,17 +3,7 @@ package com.sunyard.chsm.controller; import com.sunyard.chsm.auth.AuthCode; import com.sunyard.chsm.constant.AuthCodeConst; import com.sunyard.chsm.model.R; -import com.sunyard.chsm.param.AsymDecryptReq; -import com.sunyard.chsm.param.AsymDecryptResp; -import com.sunyard.chsm.param.AsymEncryptReq; -import com.sunyard.chsm.param.AsymEncryptResp; -import com.sunyard.chsm.param.AsymSignP7Req; -import com.sunyard.chsm.param.AsymSignP7Resp; -import com.sunyard.chsm.param.AsymSignRawReq; -import com.sunyard.chsm.param.AsymSignRawResp; -import com.sunyard.chsm.param.AsymVerifyP7Req; -import com.sunyard.chsm.param.AsymVerifyRawReq; -import com.sunyard.chsm.param.VerifyResp; +import com.sunyard.chsm.param.*; import com.sunyard.chsm.service.AsymKeyService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; @@ -55,7 +45,7 @@ public class AsymKeyController { * @param req * @return */ - @PostMapping("/encrypt") + @PostMapping("/decrypt") @AuthCode(AuthCodeConst.asym_enc) public R decrypt(@Valid @RequestBody AsymDecryptReq req) { AsymDecryptResp resp = asymKeyService.decrypt(req); @@ -140,7 +130,31 @@ public class AsymKeyController { return R.data(resp); } + /** + * P7数字信封加封 + * + * @param req + * @return + */ + @PostMapping("/envelope/seal") + @AuthCode(AuthCodeConst.envelope_seal) + public R envelopeSeal(@Valid @RequestBody AsymEnvelopeSealReq req) { + AsymEnvelopeSealResp resp = asymKeyService.envelopeSeal(req); + return R.data(resp); + } + /** + * P7数字信封解封 + * + * @param req + * @return + */ + @PostMapping("/envelope/unseal") + @AuthCode(AuthCodeConst.envelope_unseal) + public R envelopeUnseal(@Valid @RequestBody AsymEnvelopeUnsealReq req) { + AsymEnvelopeUnsealResp resp = asymKeyService.envelopeUnseal(req); + return R.data(resp); + } } diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/CertController.java b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/CertController.java index 65e24a4..d6f6db3 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/CertController.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/CertController.java @@ -1,14 +1,14 @@ package com.sunyard.chsm.controller; -import com.sunyard.chsm.constant.AuditLogConst; import com.sunyard.chsm.model.R; import com.sunyard.chsm.model.dto.CertDTO; -import com.sunyard.chsm.param.*; +import com.sunyard.chsm.param.CertExinfoResp; +import com.sunyard.chsm.param.CertInfoResp; import com.sunyard.chsm.service.AppCertService; import com.sunyard.chsm.service.CertService; -import com.sunyard.ssp.common.annotation.AuditControllerLog; import org.springframework.web.bind.annotation.*; + import javax.annotation.Resource; import javax.validation.Valid; @@ -84,7 +84,6 @@ public class CertController { * @return void */ @DeleteMapping - @AuditControllerLog(description = "删除证书", operateType = AuditLogConst.DELETE) public R delete(Long id) { appCertService.delete(id); return R.ok(); diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java index 10e51dc..2ccc44e 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java @@ -5,11 +5,7 @@ import com.sunyard.chsm.enums.AlgMode; import com.sunyard.chsm.enums.Padding; import com.sunyard.chsm.sdf.SdfApiService; import com.sunyard.chsm.sdf.context.AlgId; -import com.sunyard.chsm.sdf.model.EccCipher; -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.*; import com.sunyard.chsm.sdf.util.PaddingUtil; import com.sunyard.chsm.utils.CodecUtils; import com.sunyard.chsm.utils.gm.BCECUtils; @@ -57,13 +53,6 @@ public class LoadBalancedSdfApiService implements SdfApiService { Assert.notNull(iv, "CBC模式下, iv不能为空"); Assert.isTrue(iv.length >= key.length, "CBC模式下, iv长度不能低于key的长度"); } - log.info("symEncrypt: alg:{}, padding: {}, key: {}, iv:{}, plainData:{}", - alg.name(), - padding.getCode(), - CodecUtils.encodeHex(key), - CodecUtils.encodeHex(iv), - CodecUtils.encodeHex(data) - ); byte[] paddingData = PaddingUtil.padding(padding, data); return apply(s -> { String keyHandle = s.getSdfApiAdapter().importKey(s.getSessionHandle(), key); diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/service/AsymKeyService.java b/chsm-web-server/src/main/java/com/sunyard/chsm/service/AsymKeyService.java index ad8137f..b49eb1b 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/service/AsymKeyService.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/service/AsymKeyService.java @@ -1,10 +1,7 @@ package com.sunyard.chsm.service; import com.sunyard.chsm.auth.UserContext; -import com.sunyard.chsm.enums.KeyAlg; -import com.sunyard.chsm.enums.KeyCategory; -import com.sunyard.chsm.enums.KeyStatus; -import com.sunyard.chsm.enums.KeyUsage; +import com.sunyard.chsm.enums.*; import com.sunyard.chsm.mapper.AppCertMapper; import com.sunyard.chsm.mapper.KeyInfoMapper; import com.sunyard.chsm.mapper.SpKeyRecordMapper; @@ -13,20 +10,16 @@ import com.sunyard.chsm.model.entity.KeyInfo; import com.sunyard.chsm.model.entity.KeyRecord; import com.sunyard.chsm.param.*; import com.sunyard.chsm.sdf.SdfApiService; +import com.sunyard.chsm.sdf.context.AlgId; import com.sunyard.chsm.sdf.model.EccCipher; import com.sunyard.chsm.sdf.model.EccSignature; +import com.sunyard.chsm.sdf.util.LangUtils; import com.sunyard.chsm.utils.CodecUtils; -import com.sunyard.chsm.utils.gm.BCECUtils; -import com.sunyard.chsm.utils.gm.BCSM2Utils; -import com.sunyard.chsm.utils.gm.BCSM4Utils; import com.sunyard.chsm.utils.gm.cert.BCSM2CertUtils; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSet; +import org.bouncycastle.asn1.*; import org.bouncycastle.asn1.cms.*; import org.bouncycastle.asn1.gm.GMObjectIdentifiers; import org.bouncycastle.asn1.x500.X500Name; @@ -34,26 +27,20 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; import org.bouncycastle.cms.*; import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; -import org.bouncycastle.cms.jcajce.JcaSignerInfoVerifierBuilder; -import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient; -import org.bouncycastle.crypto.params.ECPrivateKeyParameters; -import org.bouncycastle.jcajce.io.CipherInputStream; -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.operator.InputDecryptor; -import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.operator.*; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; import org.bouncycastle.util.Store; import org.springframework.stereotype.Service; import org.springframework.util.Assert; -import javax.crypto.Cipher; -import javax.crypto.spec.SecretKeySpec; -import java.io.InputStream; -import java.security.Key; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.time.LocalDateTime; import java.util.Collection; @@ -213,7 +200,7 @@ public class AsymKeyService { byte[] plainData = CodecUtils.decodeBase64(req.getPlainData()); AppCert appCert = appCertMapper.selectSignBySubject(req.getSubject()); Assert.notNull(appCert, "证书主题对应的证书不存在"); - Assert.isTrue(Objects.equals(appCert.getApplicationId(), UserContext.getCurrentAppId()), "您无权使用此密钥ID"); + Assert.isTrue(Objects.equals(appCert.getApplicationId(), UserContext.getCurrentAppId()), "您无权使用此证书"); byte[] encPri = CodecUtils.decodeHex(appCert.getEncPriKey()); byte[] pri = sdfApiService.decryptByTMK(encPri); @@ -241,17 +228,34 @@ public class AsymKeyService { private byte[] p7Sign(byte[] pri, String cert, byte[] plainData, boolean encapsulate) { try { - BCECPrivateKey privateKey = BCECUtils.createPrivateKey(pri); X509Certificate x509Cert = BCSM2CertUtils.getX509Cert(cert); // 构造签名内容 CMSTypedData cmsData = new CMSProcessableByteArray(plainData); + + ContentSigner signer = new ContentSigner() { + private final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + @Override + public AlgorithmIdentifier getAlgorithmIdentifier() { + return new AlgorithmIdentifier(GMObjectIdentifiers.sm2sign_with_sm3); + } + + @Override + public OutputStream getOutputStream() { + return stream; + } + + @Override + public byte[] getSignature() { + EccSignature signature = sdfApiService.externalSignWithIdECC(pri, stream.toByteArray(), null); + return signature.getDerSignBytes(); + } + }; + // 生成签名者信息 SignerInfoGenerator signerInfoGenerator = new JcaSignerInfoGeneratorBuilder( new JcaDigestCalculatorProviderBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build() - ).build( - new JcaContentSignerBuilder("SM3withSM2").setProvider(BouncyCastleProvider.PROVIDER_NAME).build(privateKey), - x509Cert - ); + ).build(signer, x509Cert); // 构建 CMS Signed Data CMSSignedDataGenerator generator = new CMSSignedDataGenerator(); generator.addSignerInfoGenerator(signerInfoGenerator); @@ -264,7 +268,7 @@ public class AsymKeyService { } } - public static boolean p7Verify(byte[] signedDataBytes, byte[] originalData) throws Exception { + public boolean p7Verify(byte[] signedDataBytes, byte[] originalData) throws Exception { CMSSignedData signedData; if (originalData == null || originalData.length == 0) { @@ -286,24 +290,86 @@ public class AsymKeyService { X509Certificate cert = new JcaX509CertificateConverter() .setProvider(BouncyCastleProvider.PROVIDER_NAME) .getCertificate(certHolder); - if (signer.verify(new JcaSignerInfoVerifierBuilder( - new JcaDigestCalculatorProviderBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build()).build(cert))) { + CMSSignatureAlgorithmNameGenerator sigAlgNameGen = new DefaultCMSSignatureAlgorithmNameGenerator(); + SignatureAlgorithmIdentifierFinder sigAlgIDFinder = new DefaultSignatureAlgorithmIdentifierFinder(); + DigestCalculatorProvider digestProvider = new JcaDigestCalculatorProviderBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(); + SignerInformationVerifier verifier = new SignerInformationVerifier(sigAlgNameGen, sigAlgIDFinder, build(cert), digestProvider); + + if (signer.verify(verifier)) { return true; } } return false; } + public ContentVerifierProvider build(X509Certificate certificate) + throws OperatorCreationException { + X509CertificateHolder certHolder; + byte[] xy; + try { + certHolder = new JcaX509CertificateHolder(certificate); + BCECPublicKey publicKey = (BCECPublicKey) certificate.getPublicKey(); + xy = LangUtils.merge(publicKey.getQ().getXCoord().getEncoded(), publicKey.getQ().getYCoord().getEncoded()); + } catch (CertificateEncodingException e) { + throw new OperatorCreationException("cannot process certificate: " + e.getMessage(), e); + } + + return new ContentVerifierProvider() { + public boolean hasAssociatedCertificate() { + return true; + } + + public X509CertificateHolder getAssociatedCertificate() { + return certHolder; + } + + public ContentVerifier get(AlgorithmIdentifier algorithm) { + return new ContentVerifier() { + private final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + @Override + public AlgorithmIdentifier getAlgorithmIdentifier() { + return algorithm; + } + + @Override + public OutputStream getOutputStream() { + return stream; + } + + @Override + public boolean verify(byte[] expected) { + return sdfApiService.externalVerifyWithIdECC(xy, stream.toByteArray(), expected, null); + } + }; + } + }; + } + @SneakyThrows - private byte[] makeEnvelopeData(byte[] srcMsg, byte[] certData) { - X509Certificate cert = BCSM2CertUtils.getX509Certificate(certData); + public AsymEnvelopeSealResp envelopeSeal(AsymEnvelopeSealReq req) { + byte[] plainData = CodecUtils.decodeBase64(req.getPlainData()); + AppCert appCert = appCertMapper.selectEncBySubject(req.getSubject()); + Assert.notNull(appCert, "证书主题对应的证书不存在"); + Assert.isTrue(Objects.equals(appCert.getApplicationId(), UserContext.getCurrentAppId()), "您无权使用此证书"); + + byte[] envelopeData = makeEnvelopeData(plainData, appCert.getCertText()); + AsymEnvelopeSealResp resp = new AsymEnvelopeSealResp(); + resp.setEnvelopeData(CodecUtils.encodeBase64(envelopeData)); + return resp; + } + + @SneakyThrows + private byte[] makeEnvelopeData(byte[] srcMsg, String certText) { + X509Certificate cert = BCSM2CertUtils.getX509Cert(certText); AlgorithmIdentifier symAlg = new AlgorithmIdentifier(GMObjectIdentifiers.sm_scheme.branch("104")); // sm4 AlgorithmIdentifier asymAlg = new AlgorithmIdentifier(GMObjectIdentifiers.sm2encrypt, DERNull.INSTANCE); byte[] symKey = sdfApiService.generateRandom(16); - BCECPublicKey publicKey = (BCECPublicKey) cert.getPublicKey(); - byte[] encryptKey = BCSM2Utils.encrypt(publicKey, symKey); + byte[] xy = LangUtils.merge(publicKey.getQ().getXCoord().getEncoded(), publicKey.getQ().getYCoord().getEncoded()); + EccCipher cipher = sdfApiService.externalEncryptECC(xy, symKey); + byte[] encryptKey = cipher.getC1C3C2Bytes(); X500Name x500Name = X500Name.getInstance(cert.getIssuerX500Principal().getEncoded()); KeyTransRecipientInfo keyTransRecipientInfo = new KeyTransRecipientInfo( @@ -311,64 +377,47 @@ public class AsymKeyService { asymAlg, new DEROctetString(encryptKey) ); - - byte[] encContent = BCSM4Utils.encrypt_ECB_Padding(symKey, srcMsg); RecipientInfo recipientInfo = new RecipientInfo(keyTransRecipientInfo); + + byte[] encContent = sdfApiService.symEncrypt(AlgId.SGD_SM4_ECB, Padding.PCKS7Padding, symKey, null, srcMsg); EncryptedContentInfo encContentInfo = new EncryptedContentInfo( new ASN1ObjectIdentifier("1.2.156.10197.6.1.4.2.1"), symAlg, new DEROctetString(encContent) ); - EnvelopedData envelopedData = new EnvelopedData(null, + + EnvelopedData contentInfo = new EnvelopedData(null, new DERSet(recipientInfo), encContentInfo, (org.bouncycastle.asn1.ASN1Set) null); - - ContentInfo contentInfo = new ContentInfo(new ASN1ObjectIdentifier("1.2.156.10197.6.1.4.2.3"), envelopedData); return contentInfo.getEncoded("DER"); } @SneakyThrows - private byte[] decryptEnvelopeData(byte[] envelopeData, byte[] priKeyD) { - ECPrivateKeyParameters priKeyParameters = BCECUtils.createECPrivateKeyParameters(priKeyD); - final BCECPrivateKey priKey = new BCECPrivateKey("EC", priKeyParameters, BouncyCastleProvider.CONFIGURATION); - + public AsymEnvelopeUnsealResp envelopeUnseal(AsymEnvelopeUnsealReq req) { + byte[] envelopeData = CodecUtils.decodeBase64(req.getEnvelopeData()); // 解密数字信封 - CMSEnvelopedData ed = new CMSEnvelopedData(envelopeData); - RecipientInformationStore recipientInfos = ed.getRecipientInfos(); - Collection recipients = recipientInfos.getRecipients(); - RecipientInformation next = recipients.iterator().next(); + EnvelopedData ed = EnvelopedData.getInstance(envelopeData); + ASN1Set infos = ed.getRecipientInfos(); + RecipientInfo recipientInfo = RecipientInfo.getInstance(infos.getObjectAt(0)); + KeyTransRecipientInfo transRecipientInfo = KeyTransRecipientInfo.getInstance(recipientInfo.getInfo()); + IssuerAndSerialNumber serialNumber = IssuerAndSerialNumber.getInstance(transRecipientInfo.getRecipientIdentifier().getId()); + String sn = serialNumber.getSerialNumber().getValue().toString(); + AppCert appCert = appCertMapper.selectBySN(sn); + Assert.notNull(appCert, "此信封对应的证书不存在"); + Assert.isTrue(Objects.equals(appCert.getApplicationId(), UserContext.getCurrentAppId()), "您无权使用此信封的解密证书"); + byte[] pri = sdfApiService.decryptByTMK(CodecUtils.decodeHex(appCert.getEncPriKey())); + byte[] encryptedKey = transRecipientInfo.getEncryptedKey().getOctets(); + byte[] symKey = sdfApiService.externalDecryptECC(pri, encryptedKey); - return next.getContent(new JceKeyTransEnvelopedRecipient(priKey) { - @Override - @SneakyThrows - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, - AlgorithmIdentifier contentEncryptionAlgorithm, - byte[] encryptedContentKey) { - String keyEncId = keyEncAlg.getAlgorithm().getId(); - if (Objects.equals(GMObjectIdentifiers.sm2encrypt.getId(), keyEncId)) { - byte[] keyBytes = BCSM2Utils.decrypt(priKeyParameters, encryptedContentKey); - Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS7Padding", BouncyCastleProvider.PROVIDER_NAME); - Key sm4Key = new SecretKeySpec(keyBytes, "SM4"); - cipher.init(Cipher.DECRYPT_MODE, sm4Key); - return new RecipientOperator(new InputDecryptor() { - @Override - public AlgorithmIdentifier getAlgorithmIdentifier() { - return contentEncryptionAlgorithm; - } - - @Override - public InputStream getInputStream(InputStream dataIn) { - return new CipherInputStream(dataIn, cipher); - } - }); - } - return super.getRecipientOperator(keyEncAlg, contentEncryptionAlgorithm, encryptedContentKey); - } - }.setProvider(BouncyCastleProvider.PROVIDER_NAME)); + EncryptedContentInfo info = ed.getEncryptedContentInfo(); + byte[] octets = info.getEncryptedContent().getOctets(); + byte[] plain = sdfApiService.symDecrypt(AlgId.SGD_SM4_ECB, Padding.PCKS7Padding, symKey, null, octets); + AsymEnvelopeUnsealResp resp = new AsymEnvelopeUnsealResp(); + resp.setPlainData(CodecUtils.encodeBase64(plain)); + return resp; } - private KeyInfo checkKey(Long keyId, KeyUsage usage) { KeyInfo keyInfo = keyInfoMapper.selectById(keyId); @@ -385,4 +434,5 @@ public class AsymKeyService { return keyInfo; } + } diff --git a/chsm-web-server/src/test/java/api/AsymKeyTest.java b/chsm-web-server/src/test/java/api/AsymKeyTest.java new file mode 100644 index 0000000..0c4f71d --- /dev/null +++ b/chsm-web-server/src/test/java/api/AsymKeyTest.java @@ -0,0 +1,57 @@ +package api; + +import com.sunyard.chsm.param.*; +import com.sunyard.chsm.utils.CodecUtils; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author liulu + * @since 2024/12/24 + */ +@Slf4j +public class AsymKeyTest extends BaseTest { + + private static Long keyId; + private static final byte[] plain = "hjsu234127qikqwndqqw13412as324".getBytes(); + private static final Long certKeyId = 1871443220005818369L; + private static final String dn = "CN=cert-test,O=SYD,L=HZ,ST=ZJ,C=CN"; + + + @Test + public void testAttach() { + AsymSignP7Req signP7Req = new AsymSignP7Req(); + signP7Req.setSubject(dn); + signP7Req.setPlainData(CodecUtils.encodeBase64(plain)); + AsymSignP7Resp signP7Resp = execute("/asym/sign/P7Attach", signP7Req, AsymSignP7Resp.class); + log.info("signP7: {}", signP7Resp.getSignData()); + + AsymVerifyP7Req verifyP7Req = new AsymVerifyP7Req(); + verifyP7Req.setSignData(signP7Resp.getSignData()); + VerifyResp verifyResp = execute("/asym/verify/P7Attach", verifyP7Req, VerifyResp.class); + log.info("verifyResp: {}", verifyResp.getVerified()); + + Assertions.assertTrue(verifyResp.getVerified()); + + } + + @Test + public void testEnvelopedData() { + AsymEnvelopeSealReq sealReq = new AsymEnvelopeSealReq(); + sealReq.setSubject(dn); + sealReq.setPlainData(CodecUtils.encodeBase64(plain)); + AsymEnvelopeSealResp sealResp = execute("/asym/envelope/seal", sealReq, AsymEnvelopeSealResp.class); + log.info("signP7: {}", sealResp.getEnvelopeData()); + + AsymEnvelopeUnsealReq unsealReq = new AsymEnvelopeUnsealReq(); + unsealReq.setEnvelopeData(sealResp.getEnvelopeData()); + AsymEnvelopeUnsealResp unsealResp = execute("/asym/envelope/unseal", unsealReq, AsymEnvelopeUnsealResp.class); + log.info("verifyResp: {}", unsealResp.getPlainData()); + log.info("verifyResp: {}", new String(CodecUtils.decodeBase64(unsealResp.getPlainData()))); + + + } + + +}