package org.dromara.settlement.common.bank.minsheng;

import cmbc.cfca.sm2rsa.common.Mechanism;
import cmbc.cfca.sm2rsa.common.PKIException;
import cmbc.cfca.util.CertUtil;
import cmbc.cfca.util.EnvelopeUtil;
import cmbc.cfca.util.KeyUtil;
import cmbc.cfca.util.SignatureUtil2;
import cmbc.cfca.util.cipher.lib.JCrypto;
import cmbc.cfca.util.cipher.lib.Session;
import cmbc.cfca.x509.certificate.X509Cert;
import cmbc.cfca.x509.certificate.X509CertHelper;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.security.PrivateKey;


/**
 * 联调外联平台 用 bankcersm2.cer和corp.sm2 ,仅可用于加密 和 解密外联平台传输过来的文件和报文
 */
public class FileEncryptAndDecryptUtil {
    /**
     * 以下用到的文件或存放文件的目录需提前建好，否则报错
     */
    public static void main(String[] args) {

        /*String path = Thread.currentThread().getContextClassLoader().getResource("file/mhtText.txt").getPath();

        File file = new File(path);
        String path1 = file.getPath();
        String name = file.getName();
        String filePath = path1.substring(0, path1.length() - name.length());
        // 商户私钥
        String sm2MhtPriCertPath = Thread.currentThread().getContextClassLoader().getResource(TestDemo.SM2_MERCHANT_PRIVATE_CERT_NAME).getPath();
        //银行公钥
        String sm2CmbcPubCertPath = Thread.currentThread().getContextClassLoader().getResource(TestDemo.SM2_CMBC_PUBLIC_CERT_NAME).getPath();
        String sm2Psword = TestDemo.SM2_MERCHANT_PRIVATE_CERT_PSWORD;
        try {
            //加密
            encryptFile(name, filePath, sm2MhtPriCertPath, sm2Psword, sm2CmbcPubCertPath);
            //解密
            String encryptedFileName = "CMBC_LOAN_20230219.csv";
            decryptFile(encryptedFileName, filePath, sm2MhtPriCertPath, sm2Psword);
        } catch (Exception e) {
            e.printStackTrace();
        }*/
    }

    /**
     * 文件加签加密
     * a.商户使用商户私钥对文件进行签名
     * b.商户使用银行公钥对签名后的文件进行加密（测试环境请用 corp.sm2和bankcersm2.cer）
     *
     * @param fileName            要加密的文件名
     * @param filePath            要加密的文件所在路径
     * @param sm2MhtPriCertPath   商户sm2私钥证书路径
     * @param sm2MhtPriCertPsword 商户sm2私钥证书密码
     * @param sm2CmbcPubCertPath  民生sm2 公钥证书路径
     * @throws Exception
     */
    public static void encryptFile(String fileName, String filePath, String sm2MhtPriCertPath, String sm2MhtPriCertPsword, String sm2CmbcPubCertPath) throws Exception {

        //商户加密

        // 签名
        X509Cert mhtSM2Cert = CertUtil.getCertFromSM2(sm2MhtPriCertPath);
        PrivateKey mhtPriKey = KeyUtil.getPrivateKeyFromSM2(sm2MhtPriCertPath, sm2MhtPriCertPsword);

        // 待加密文件路径
        String sourceFilePath = filePath + fileName;
        //签名后文件路径
        String signFilePath = filePath + "\\sign\\" + fileName;
        //加密后文件路径
        String encryptFilePath = filePath + "\\encrypt\\" + fileName;
        Session session = getSession();

        SignatureUtil2 signatureUtil2 = new SignatureUtil2();
        // SM2签名包含Z值
        signatureUtil2.setSm2WithZFlag(true);
        String signAlg = Mechanism.SM3_SM2;
        signatureUtil2.p7SignFileAttach(signAlg, sourceFilePath, signFilePath, mhtPriKey, mhtSM2Cert, session);

        //加密
        X509Cert bankX509Cert = X509CertHelper.parse(FileUtils.readFileToByteArray(new File(sm2CmbcPubCertPath)));
        X509Cert[] bankCertArr = new X509Cert[]{bankX509Cert};
        String encryptAlgrithm = Mechanism.SM4_CBC;
        EnvelopeUtil.envelopeFile(signFilePath, encryptFilePath, encryptAlgrithm, bankCertArr, session);

    }

    /**
     * 文件解密验签
     * a.商户使用银行公钥对文件进行解密
     * b.对文件进行验签（测试环境请用 corp.sm2和bankcersm2.cer）
     *
     * @param encryptFileName   要解密验签的文件
     * @param filePath          要加密的文件所在路径
     * @param sm2MhtPriCertPath 商户sm2私钥证书路径
     * @param sm2Psword         商户sm2私钥证书密码
     * @param outSourceFilePath  验签后文件路径--解密验签后的明文路径
     * @throws Exception
     */
    public static String decryptFile(String encryptFileName, String filePath, String sm2MhtPriCertPath, String sm2Psword,String outSourceFilePath) throws Exception {
        String encryptFilePath = filePath + encryptFileName;
        // 解密后待验签文件路径
        String veryfiSignFilePath = filePath + "veryfiSign" + encryptFileName;
        // 银行私钥
        SignatureUtil2 signatureUtil2 = new SignatureUtil2();
        // 解密
        Session session = getSession();

        PrivateKey mhtPriKey = KeyUtil.getPrivateKeyFromSM2(sm2MhtPriCertPath, sm2Psword);
        X509Cert mhtRcvX509Cert = CertUtil.getCertFromSM2(sm2MhtPriCertPath);
        EnvelopeUtil.openEnvelopedFile(encryptFilePath, veryfiSignFilePath, mhtPriKey, mhtRcvX509Cert, session);

        // 校验
        boolean verifyResult = signatureUtil2.p7VerifyFileAttach(veryfiSignFilePath, outSourceFilePath, session);
        System.out.println("验签结果：" + verifyResult);
        new File(veryfiSignFilePath).delete();
        return outSourceFilePath;
    }

    /**
     * 获取Session
     *
     * @return
     * @throws PKIException
     */
    private static Session getSession() throws PKIException {
        String deviceName = JCrypto.JSOFT_LIB;
        JCrypto.getInstance().initialize(deviceName, null);
        Session session = JCrypto.getInstance().openSession(deviceName);
        return session;
    }
}
