数字信封加密和解密

This commit is contained in:
liulu 2024-12-24 17:34:08 +08:00
parent 17bc552dc5
commit da77d42f89
12 changed files with 291 additions and 111 deletions

View File

@ -43,5 +43,18 @@ public interface AppCertMapper extends BaseMapper<AppCert> {
return certs.iterator().next();
}
default AppCert selectEncBySubject(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.ENCRYPT_DECRYPT.getCode())
);
if (CollectionUtils.isEmpty(certs)) {
return null;
}
return certs.iterator().next();
}
}

View File

@ -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;
}

View File

@ -0,0 +1,11 @@
package com.sunyard.chsm.param;
import lombok.Data;
@Data
public class AsymEnvelopeSealResp {
// 数字信封使用Base64编码
private String envelopeData;
}

View File

@ -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;
}

View File

@ -0,0 +1,12 @@
package com.sunyard.chsm.param;
import lombok.Data;
@Data
public class AsymEnvelopeUnsealResp {
// 明文,使用Base64编码
private String plainData;
}

View File

@ -14,10 +14,10 @@ public class AsymVerifyP7Req {
// private String subject;
// 原文,使用Base64编码
@NotBlank(message = "明文不能为空")
private String plainData;
// 签名值, 使用Base64编码
@NotBlank(message = "签名值不能为空")
private String signData;
}

View File

@ -25,12 +25,6 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.sunyard.chsm</groupId>
<artifactId>chsm-web-manage</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.dm</groupId>
<artifactId>DmJdbcDriver</artifactId>

View File

@ -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<AsymDecryptResp> 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<AsymEnvelopeSealResp> 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<AsymEnvelopeUnsealResp> envelopeUnseal(@Valid @RequestBody AsymEnvelopeUnsealReq req) {
AsymEnvelopeUnsealResp resp = asymKeyService.envelopeUnseal(req);
return R.data(resp);
}
}

View File

@ -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<Void> delete(Long id) {
appCertService.delete(id);
return R.ok();

View File

@ -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);

View File

@ -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<RecipientInformation> 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;
}
}

View File

@ -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())));
}
}