From 81b0ea4c3b6e0e927c41eff3423916a88530eb93 Mon Sep 17 00:00:00 2001 From: liulu Date: Tue, 24 Dec 2024 14:25:54 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9D=9E=E5=AF=B9=E7=A7=B0=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E9=AA=8C=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sunyard/chsm/service/AsymKeyService.java | 117 +++++++++++++++--- 1 file changed, 98 insertions(+), 19 deletions(-) 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 9834553..ad8137f 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 @@ -11,45 +11,49 @@ import com.sunyard.chsm.mapper.SpKeyRecordMapper; import com.sunyard.chsm.model.entity.AppCert; import com.sunyard.chsm.model.entity.KeyInfo; import com.sunyard.chsm.model.entity.KeyRecord; -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.sdf.SdfApiService; import com.sunyard.chsm.sdf.model.EccCipher; import com.sunyard.chsm.sdf.model.EccSignature; 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.cms.*; +import org.bouncycastle.asn1.gm.GMObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; +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.cms.CMSProcessableByteArray; -import org.bouncycastle.cms.CMSSignedData; -import org.bouncycastle.cms.CMSSignedDataGenerator; -import org.bouncycastle.cms.CMSTypedData; -import org.bouncycastle.cms.SignerInfoGenerator; -import org.bouncycastle.cms.SignerInformation; -import org.bouncycastle.cms.SignerInformationStore; +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.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.security.cert.X509Certificate; import java.time.LocalDateTime; import java.util.Collection; @@ -235,7 +239,7 @@ public class AsymKeyService { return resp; } - private static byte[] p7Sign(byte[] pri, String cert, byte[] plainData, boolean encapsulate) { + private byte[] p7Sign(byte[] pri, String cert, byte[] plainData, boolean encapsulate) { try { BCECPrivateKey privateKey = BCECUtils.createPrivateKey(pri); X509Certificate x509Cert = BCSM2CertUtils.getX509Cert(cert); @@ -290,6 +294,81 @@ public class AsymKeyService { return false; } + @SneakyThrows + private byte[] makeEnvelopeData(byte[] srcMsg, byte[] certData) { + X509Certificate cert = BCSM2CertUtils.getX509Certificate(certData); + 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); + + X500Name x500Name = X500Name.getInstance(cert.getIssuerX500Principal().getEncoded()); + KeyTransRecipientInfo keyTransRecipientInfo = new KeyTransRecipientInfo( + new RecipientIdentifier(new IssuerAndSerialNumber(x500Name, cert.getSerialNumber())), + asymAlg, + new DEROctetString(encryptKey) + ); + + byte[] encContent = BCSM4Utils.encrypt_ECB_Padding(symKey, srcMsg); + RecipientInfo recipientInfo = new RecipientInfo(keyTransRecipientInfo); + EncryptedContentInfo encContentInfo = new EncryptedContentInfo( + new ASN1ObjectIdentifier("1.2.156.10197.6.1.4.2.1"), + symAlg, + new DEROctetString(encContent) + ); + EnvelopedData envelopedData = 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); + + // 解密数字信封 + CMSEnvelopedData ed = new CMSEnvelopedData(envelopeData); + RecipientInformationStore recipientInfos = ed.getRecipientInfos(); + Collection recipients = recipientInfos.getRecipients(); + RecipientInformation next = recipients.iterator().next(); + + 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)); + } + + private KeyInfo checkKey(Long keyId, KeyUsage usage) { KeyInfo keyInfo = keyInfoMapper.selectById(keyId);