package com.sunyard.chsm.service;

import com.sunyard.chsm.auth.UserContext;
import com.sunyard.chsm.enums.*;
import com.sunyard.chsm.mapper.AppCertMapper;
import com.sunyard.chsm.mapper.KeyInfoMapper;
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.*;
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.SignedAndEnvelopedData;
import com.sunyard.chsm.utils.gm.cert.BCSM2CertUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.cms.*;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.ContentInfo;
import org.bouncycastle.asn1.pkcs.SignedData;
import org.bouncycastle.asn1.pkcs.SignerInfo;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.io.ByteArrayOutputStream;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.Objects;
import java.util.Optional;

/**
 * @author liulu
 * @since 2024/12/20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AsymKeyService {

    private final AppCertMapper appCertMapper;
    private final KeyInfoMapper keyInfoMapper;
    private final SpKeyRecordMapper spKeyRecordMapper;
    private final SdfApiService sdfApiService;

    public ExportPubKeyResp exportPubKey(ExportPubKeyReq req) {
        KeyInfo keyInfo = checkKey(req.getKeyId(), null);
        KeyRecord keyRecord = spKeyRecordMapper.selectUsedByKeyId(keyInfo.getId());

        ExportPubKeyResp resp = new ExportPubKeyResp();
        resp.setKeyId(keyInfo.getId());
        resp.setKeyIndex(keyRecord.getKeyIndex());
        byte[] pub = CodecUtils.decodeHex(keyRecord.getPubKey());
        resp.setPubKey(CodecUtils.encodeBase64(pub));
        return resp;
    }

    public AsymEncryptResp encrypt(AsymEncryptReq req) {
        byte[] plainData = CodecUtils.decodeBase64(req.getPlainData());
        KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.ENCRYPT_DECRYPT);
        KeyAlg keyAlg = KeyAlg.of(keyInfo.getKeyAlg());
        Assert.notNull(keyAlg, "数据异常");
        KeyRecord keyRecord = spKeyRecordMapper.selectUsedByKeyId(keyInfo.getId());
        Assert.notNull(keyRecord, "数据异常");
        byte[] cipherData;
        switch (keyAlg) {
            case SM2:
                byte[] pub = CodecUtils.decodeHex(keyRecord.getPubKey());
                EccCipher eccCipher = sdfApiService.externalEncryptECC(pub, plainData);
                cipherData = eccCipher.getC1C3C2Bytes();
                break;
            default:
                throw new UnsupportedOperationException("不支持的密钥算法:" + keyAlg.getCode());
        }

        AsymEncryptResp resp = new AsymEncryptResp();
        resp.setKeyId(keyInfo.getId());
        resp.setKeyIndex(keyRecord.getKeyIndex());
        resp.setCipherData(CodecUtils.encodeBase64(cipherData));
        return resp;
    }

    public AsymDecryptResp decrypt(AsymDecryptReq req) {
        byte[] cipherData = CodecUtils.decodeBase64(req.getCipherData());
        KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.ENCRYPT_DECRYPT);
        KeyAlg keyAlg = KeyAlg.of(keyInfo.getKeyAlg());
        Assert.notNull(keyAlg, "数据异常");
        KeyRecord keyRecord = spKeyRecordMapper.selectById(Long.valueOf(req.getKeyIndex()));
        Assert.notNull(keyRecord, "数据异常");
        Assert.isTrue(Objects.equals(keyRecord.getKeyId(), keyInfo.getId()), "密钥Id和密钥索引不匹配");
        byte[] plainData;
        switch (keyAlg) {
            case SM2:
                byte[] encPri = CodecUtils.decodeHex(keyRecord.getKeyData());
                byte[] pri = sdfApiService.decryptByTMK(encPri);
                plainData = sdfApiService.externalDecryptECC(pri, cipherData);
                break;
            default:
                throw new UnsupportedOperationException("不支持的密钥算法:" + keyAlg.getCode());
        }
        AsymDecryptResp resp = new AsymDecryptResp();
        resp.setKeyId(keyInfo.getId());
        resp.setKeyIndex(keyRecord.getKeyIndex());
        resp.setPlainData(CodecUtils.encodeBase64(plainData));
        return resp;
    }

    public AsymSignRawResp signRaw(AsymSignRawReq req) {
        byte[] plainData = CodecUtils.decodeBase64(req.getPlainData());
        byte[] userId = CodecUtils.decodeBase64(req.getUserId());
        KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.SIGN_VERIFY);
        KeyAlg keyAlg = KeyAlg.of(keyInfo.getKeyAlg());
        Assert.notNull(keyAlg, "数据异常");
        KeyRecord keyRecord = spKeyRecordMapper.selectUsedByKeyId(keyInfo.getId());
        Assert.notNull(keyRecord, "数据异常");
        byte[] signData;
        switch (keyAlg) {
            case SM2:
                byte[] encPri = CodecUtils.decodeHex(keyRecord.getKeyData());
                byte[] pri = sdfApiService.decryptByTMK(encPri);
                EccSignature signature = req.isPreProcess()
                        ? sdfApiService.externalSignWithIdECC(pri, plainData, userId)
                        : sdfApiService.externalSignECC(pri, plainData);
                signData = signature.getRawSignBytes();
                break;
            default:
                throw new UnsupportedOperationException("不支持的密钥算法:" + keyAlg.getCode());
        }

        AsymSignRawResp resp = new AsymSignRawResp();
        resp.setKeyId(keyInfo.getId());
        resp.setKeyIndex(keyRecord.getKeyIndex());
        resp.setSignData(CodecUtils.encodeBase64(signData));
        return resp;
    }


    public VerifyResp verifyRaw(AsymVerifyRawReq req) {
        byte[] plainData = CodecUtils.decodeBase64(req.getPlainData());
        byte[] signData = CodecUtils.decodeBase64(req.getSignData());
        byte[] userId = CodecUtils.decodeBase64(req.getUserId());
        KeyInfo keyInfo = checkKey(req.getKeyId(), KeyUsage.SIGN_VERIFY);
        KeyAlg keyAlg = KeyAlg.of(keyInfo.getKeyAlg());
        Assert.notNull(keyAlg, "数据异常");
        KeyRecord keyRecord = spKeyRecordMapper.selectById(Long.valueOf(req.getKeyIndex()));
        Assert.notNull(keyRecord, "数据异常");
        Assert.isTrue(Objects.equals(keyRecord.getKeyId(), keyInfo.getId()), "密钥Id和密钥索引不匹配");
        boolean verified;
        switch (keyAlg) {
            case SM2:
                byte[] pub = CodecUtils.decodeHex(keyRecord.getPubKey());
                verified = req.isPreProcess()
                        ? sdfApiService.externalVerifyWithIdECC(pub, plainData, signData, userId)
                        : sdfApiService.externalVerifyECC(pub, plainData, signData);
                break;
            default:
                throw new UnsupportedOperationException("不支持的密钥算法:" + keyAlg.getCode());
        }
        VerifyResp resp = new VerifyResp();
        resp.setVerified(verified);
        return resp;
    }

    @SneakyThrows
    public AsymSignP7Resp signP7Attach(AsymSignP7Req req) {
        byte[] plainData = CodecUtils.decodeBase64(req.getPlainData());
        AppCert appCert = appCertMapper.selectSignBySubject(req.getSubject());
        Assert.notNull(appCert, "证书主题对应的证书不存在");
        Assert.isTrue(Objects.equals(appCert.getApplicationId(), UserContext.getCurrentAppId()), "您无权使用此密钥ID");
        byte[] encPri = CodecUtils.decodeHex(appCert.getEncPriKey());
        byte[] pri = sdfApiService.decryptByTMK(encPri);

        SignedData signedData = p7Sign(pri, appCert.getCertText(), plainData, true);
        ContentInfo contentInfo = new ContentInfo(Signed_Data, signedData);

        AsymSignP7Resp resp = new AsymSignP7Resp();
        resp.setSignData(CodecUtils.encodeBase64(contentInfo.getEncoded()));
        return resp;
    }

    public VerifyResp verifyP7Attach(AsymVerifyP7Req req) {
        byte[] signData = CodecUtils.decodeBase64(req.getSignData());
        boolean verify;
        try {
            verify = p7Verify(signData, null);

        } catch (Exception e) {
            log.warn("", e);
            verify = false;
        }
        VerifyResp resp = new VerifyResp();
        resp.setVerified(verify);
        return resp;
    }

    @SneakyThrows
    public AsymSignP7Resp signP7Detach(AsymSignP7Req req) {
        byte[] plainData = CodecUtils.decodeBase64(req.getPlainData());
        AppCert appCert = appCertMapper.selectSignBySubject(req.getSubject());
        Assert.notNull(appCert, "证书主题对应的证书不存在");
        Assert.isTrue(Objects.equals(appCert.getApplicationId(), UserContext.getCurrentAppId()), "您无权使用此证书");
        byte[] encPri = CodecUtils.decodeHex(appCert.getEncPriKey());
        byte[] pri = sdfApiService.decryptByTMK(encPri);

        SignedData signedData = p7Sign(pri, appCert.getCertText(), plainData, false);
        ContentInfo contentInfo = new ContentInfo(Signed_Data, signedData);
        AsymSignP7Resp resp = new AsymSignP7Resp();
        resp.setSignData(CodecUtils.encodeBase64(contentInfo.getEncoded()));
        return resp;
    }

    public VerifyResp verifyP7Detach(AsymVerifyP7Req req) {
        Assert.hasText(req.getPlainData(), "P7Detach验签原文不能为空");
        byte[] signData = CodecUtils.decodeBase64(req.getSignData());
        byte[] plainData = CodecUtils.decodeBase64(req.getPlainData());
        boolean verify;
        try {
            verify = p7Verify(signData, plainData);

        } catch (Exception e) {
            verify = false;
        }
        VerifyResp resp = new VerifyResp();
        resp.setVerified(verify);
        return resp;
    }

    private static final ASN1ObjectIdentifier Data = new ASN1ObjectIdentifier("1.2.156.10197.6.1.4.2.1");
    private static final ASN1ObjectIdentifier Signed_Data = new ASN1ObjectIdentifier("1.2.156.10197.6.1.4.2.2");
    private static final ASN1ObjectIdentifier Enveloped_Data = new ASN1ObjectIdentifier("1.2.156.10197.6.1.4.2.3");
    private static final ASN1ObjectIdentifier Signed_Enveloped_Data = new ASN1ObjectIdentifier("1.2.156.10197.6.1.4.2.4");

    private SignedData p7Sign(byte[] pri, String cert, byte[] plainData, boolean encapsulate) {
        try {
            X509Certificate x509Cert = BCSM2CertUtils.getX509Cert(cert);
            X500Name x500Name = X500Name.getInstance(x509Cert.getIssuerX500Principal().getEncoded());
            EccSignature signature = sdfApiService.externalSignWithIdECC(pri, plainData, null);
            SignerInfo signerInfo = new SignerInfo(
                    new ASN1Integer(1),
                    new org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber(x500Name, x509Cert.getSerialNumber()),
                    new AlgorithmIdentifier(GMObjectIdentifiers.sm3),
                    null,
                    new AlgorithmIdentifier(GMObjectIdentifiers.sm2sign),
                    new DEROctetString(signature.getDerSignBytes()),
                    null
            );

            ContentInfo plainContent = new ContentInfo(Data, encapsulate ? new DEROctetString(plainData) : null);

            X509CertificateHolder holder = new X509CertificateHolder(x509Cert.getEncoded());
            return new SignedData(
                    new ASN1Integer(1),
                    new DERSet(new AlgorithmIdentifier(GMObjectIdentifiers.sm3)),
                    plainContent,
                    new DLSet(holder.toASN1Structure()),
                    null,
                    new DLSet(signerInfo)
            );
        } catch (Exception ex) {
            log.warn("", ex);
            throw new IllegalArgumentException("P7签名异常");
        }
    }

    public boolean p7Verify(byte[] signedDataBytes, byte[] originalData) throws Exception {

        ContentInfo contentInfo = ContentInfo.getInstance(signedDataBytes);
        Assert.isTrue(Objects.equals(Signed_Data.getId(), contentInfo.getContentType().getId()), "P7签名数据格式错误");

        SignedData signedData = SignedData.getInstance(contentInfo.getContent());

        byte[] plainData = Optional.ofNullable(signedData.getContentInfo())
                .map(ContentInfo::getContent)
                .map(it -> (ASN1OctetString) it)
                .map(ASN1OctetString::getOctets)
                .orElse(originalData);
        Assert.notNull(plainData, "未能解析到原文, 请检查签名数据");

        ASN1Primitive primitive = Optional.ofNullable(signedData.getCertificates())
                .map(ASN1Set::iterator)
                .map(Iterator::next)
                .map(ASN1Encodable::toASN1Primitive)
                .orElse(null);
        Assert.notNull(primitive, "解析证书异常");
        X509Certificate cert = BCSM2CertUtils.getX509Certificate(primitive.getEncoded());
        BCECPublicKey publicKey = (BCECPublicKey) cert.getPublicKey();
        byte[] xy = LangUtils.merge(publicKey.getQ().getXCoord().getEncoded(), publicKey.getQ().getYCoord().getEncoded());

        SignerInfo signerInfo = SignerInfo.getInstance(signedData.getSignerInfos().iterator().next());
        byte[] octets = signerInfo.getEncryptedDigest().getOctets();
        return sdfApiService.externalVerifyWithIdECC(xy, plainData, octets, null);
    }

    @SneakyThrows
    public AsymEnvelopeSealResp envelopeSeal(AsymEnvelopeSealReq req) {
        byte[] plainData = CodecUtils.decodeBase64(req.getPlainData());

        EnvelopedData envelopedData = getEnvelopedData(req.getEncCert(), plainData);
        ContentInfo contentInfo = new ContentInfo(ContentInfo.envelopedData, envelopedData);
        byte[] envelopeData = contentInfo.getEncoded();

        AsymEnvelopeSealResp resp = new AsymEnvelopeSealResp();
        resp.setEnvelopeData(CodecUtils.encodeBase64(envelopeData));
        return resp;
    }

    private EnvelopedData getEnvelopedData(String encCert, byte[] plainData) throws CertificateException, NoSuchProviderException {
        X509Certificate cert = BCSM2CertUtils.getX509Cert(encCert);
        AlgorithmIdentifier symAlg = new AlgorithmIdentifier(GMObjectIdentifiers.sms4_ecb);
        AlgorithmIdentifier asymAlg = new AlgorithmIdentifier(GMObjectIdentifiers.sm2encrypt);

        byte[] symKey = sdfApiService.generateRandom(16);
        BCECPublicKey publicKey = (BCECPublicKey) cert.getPublicKey();
        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(
                new RecipientIdentifier(new IssuerAndSerialNumber(x500Name, cert.getSerialNumber())),
                asymAlg,
                new DEROctetString(encryptKey)
        );
        RecipientInfo recipientInfo = new RecipientInfo(keyTransRecipientInfo);

        byte[] encContent = sdfApiService.symEncrypt(AlgId.SGD_SM4_ECB, Padding.PCKS7Padding, symKey, null, plainData);
        EncryptedContentInfo encContentInfo = new EncryptedContentInfo(Data, symAlg, new DEROctetString(encContent));

        return new EnvelopedData(null,
                new DERSet(recipientInfo),
                encContentInfo,
                (ASN1Set) null);
    }

    @SneakyThrows
    public AsymEnvelopeUnsealResp envelopeUnseal(AsymEnvelopeUnsealReq req) {
        byte[] envelopeData = CodecUtils.decodeBase64(req.getEnvelopeData());
        // 解密数字信封
        byte[] plain = getPlainFromEnvelopedData(envelopeData);
        AsymEnvelopeUnsealResp resp = new AsymEnvelopeUnsealResp();
        resp.setPlainData(CodecUtils.encodeBase64(plain));
        return resp;
    }

    private byte[] getPlainFromEnvelopedData(byte[] edData) {
        ContentInfo contentInfo = ContentInfo.getInstance(edData);
        String id = contentInfo.getContentType().getId();
        boolean isEd = Objects.equals(id, ContentInfo.envelopedData.getId()) || Objects.equals(id, Enveloped_Data.getId());
        Assert.isTrue(isEd, "数字信封数据格式异常");

        EnvelopedData ed = EnvelopedData.getInstance(contentInfo.getContent());
        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()), "您无权使用此信封的解密证书");

        AlgorithmIdentifier algorithm = transRecipientInfo.getKeyEncryptionAlgorithm();
        Assert.isTrue(Objects.equals(algorithm.getAlgorithm().getId(), GMObjectIdentifiers.sm2encrypt.getId()), "密钥加密算法只支持SM2");

        byte[] pri = sdfApiService.decryptByTMK(CodecUtils.decodeHex(appCert.getEncPriKey()));
        byte[] encryptedKey = transRecipientInfo.getEncryptedKey().getOctets();
        byte[] symKey = sdfApiService.externalDecryptECC(pri, encryptedKey);

        EncryptedContentInfo info = ed.getEncryptedContentInfo();
        Assert.isTrue(Objects.equals(info.getContentEncryptionAlgorithm().getAlgorithm().getId(), GMObjectIdentifiers.sms4_ecb.getId()), "内容加密算法只支持SM4_ECB");

        byte[] octets = info.getEncryptedContent().getOctets();
        byte[] plain = sdfApiService.symDecrypt(AlgId.SGD_SM4_ECB, Padding.PCKS7Padding, symKey, null, octets);
        return plain;
    }

    @SneakyThrows
    public AsymEnvelopeSealResp signedEnvelopeSeal(AsymEnvelopeSealReq req) {
        Assert.hasText(req.getSignSubject(), "签名证书主题不能为空");
        byte[] plainData = CodecUtils.decodeBase64(req.getPlainData());
        AppCert appCert = appCertMapper.selectSignBySubject(req.getSignSubject());
        Assert.notNull(appCert, "证书主题对应的签名证书不存在");
        Assert.isTrue(Objects.equals(appCert.getApplicationId(), UserContext.getCurrentAppId()), "您无权使用此证书");
        byte[] encPri = CodecUtils.decodeHex(appCert.getEncPriKey());
        byte[] pri = sdfApiService.decryptByTMK(encPri);

        SignedData signedData = p7Sign(pri, appCert.getCertText(), plainData, false);
        EnvelopedData envelopedData = getEnvelopedData(req.getEncCert(), plainData);
        SignedAndEnvelopedData signedAndEnvelopedData = new SignedAndEnvelopedData(
                new ASN1Integer(1),
                envelopedData.getRecipientInfos(),
                signedData.getDigestAlgorithms(),
                envelopedData.getEncryptedContentInfo(),
                signedData.getCertificates(),
                signedData.getCRLs(),
                signedData.getSignerInfos()
        );
        ContentInfo contentInfo = new ContentInfo(Signed_Enveloped_Data, signedAndEnvelopedData);
        AsymEnvelopeSealResp resp = new AsymEnvelopeSealResp();
        resp.setEnvelopeData(CodecUtils.encodeBase64(contentInfo.getEncoded()));
        return resp;
    }

    @SneakyThrows
    public AsymEnvelopeUnsealResp signedEnvelopeUnseal(AsymEnvelopeUnsealReq req) {
        byte[] data = CodecUtils.decodeBase64(req.getEnvelopeData());
        ContentInfo info = ContentInfo.getInstance(data);
        Assert.isTrue(Objects.equals(Signed_Enveloped_Data.getId(), info.getContentType().getId()), "P7签名数字信封格式错误");

        SignedAndEnvelopedData signedAndEnvelopedData = SignedAndEnvelopedData.getInstance(info.getContent());

        EnvelopedData envelopedData = new EnvelopedData(
                null,
                signedAndEnvelopedData.getRecipientInfos(),
                signedAndEnvelopedData.getEncryptedContentInfo(),
                (ASN1Set) null
        );
        ContentInfo EnvelopedDataInfo = new ContentInfo(CMSObjectIdentifiers.envelopedData, envelopedData);
        byte[] plainData = getPlainFromEnvelopedData(EnvelopedDataInfo.getEncoded());

        CMSTypedData cmsData = new CMSProcessableByteArray(plainData);
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        cmsData.write(bOut);
        bOut.close();
        ContentInfo encInfo = new ContentInfo(cmsData.getContentType(), new BEROctetString(bOut.toByteArray()));
        SignedData sd = new SignedData(
                new ASN1Integer(1),
                signedAndEnvelopedData.getDigestAlgorithms(),
                encInfo,
                signedAndEnvelopedData.getCertificates(),
                signedAndEnvelopedData.getCrls(),
                signedAndEnvelopedData.getSignerInfos()
        );
        ContentInfo contentInfo = new ContentInfo(Signed_Data, sd);
        boolean verify = p7Verify(contentInfo.getEncoded(), null);
        Assert.isTrue(verify, "签名验证失败");
        AsymEnvelopeUnsealResp resp = new AsymEnvelopeUnsealResp();
        resp.setPlainData(CodecUtils.encodeBase64(plainData));
        return resp;
    }


    private KeyInfo checkKey(Long keyId, KeyUsage usage) {

        KeyInfo keyInfo = keyInfoMapper.selectById(keyId);
        Assert.notNull(keyInfo, "密钥ID不存在");
        Assert.isTrue(Objects.equals(keyInfo.getApplicationId(), UserContext.getCurrentAppId()), "您无权使用此密钥ID");
        Assert.isTrue(KeyCategory.ASYM_KEY.getCode().equals(keyInfo.getKeyType()), "此密钥不是非对称密钥");

        KeyStatus status = KeyStatus.of(keyInfo.getStatus());
        LocalDateTime now = LocalDateTime.now();
        Assert.isTrue(KeyStatus.ENABLED == status, "此密钥不是启用状态, 无法操作");
        Assert.isTrue(now.isAfter(keyInfo.getEffectiveTime()) && now.isBefore(keyInfo.getExpiredTime()), "此密钥不是启用状态, 无法操作");
        if (usage != null) {
            Assert.isTrue(KeyUsage.hasUsage(keyInfo.getKeyUsage(), usage), "此密钥无权进行" + usage.getDesc() + "操作");
        }

        return keyInfo;
    }


}
