package com.ruoyi.common.utils.crypto;

import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

public class CryptoUtil {
    public static final int SM3_DIGEST_LENGTH = 32;
    private static final BigInteger SM2_ECC_P = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16);
    private static final BigInteger SM2_ECC_A = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16);
    private static final BigInteger SM2_ECC_B = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16);
    private static final BigInteger SM2_ECC_N = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16);
    private static final BigInteger SM2_ECC_GX = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
    private static final BigInteger SM2_ECC_GY = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
    private static final ECCurve CURVE;
    private static final ECPoint G_POINT;
    private static final ECDomainParameters DOMAIN_PARAMS;

    static {
        CURVE = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, (BigInteger)null, (BigInteger)null);
        G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
        DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT, SM2_ECC_N, BigInteger.ONE);
    }

    public static ECPublicKeyParameters importPublicKeyFromHex(String publicKeyStr) throws Exception{
        ECPoint pubKey = null;

        try {
            pubKey = CURVE.decodePoint(org.apache.commons.codec.binary.Hex.decodeHex(publicKeyStr));
        } catch (Exception var3) {
            throw new Exception("读取公钥失败:" + var3.getMessage());
        }

        return new ECPublicKeyParameters(pubKey, DOMAIN_PARAMS);
    }


    /**
     * 方法描述：sm2加密
     */
    public static String sm2Encrypt(String signature, String plainText) throws Exception {
        ECPublicKeyParameters ecPublicKeyParameters = importPublicKeyFromHex(signature);
        byte[] srcData = plainText.getBytes(StandardCharsets.UTF_8);
        byte[] bodyBytes;
        try {
            SM2Engine engine = new SM2Engine();
            ParametersWithRandom pwr = new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom());
            engine.init(true, pwr);
            bodyBytes =  engine.processBlock(srcData, 0, srcData.length);
        } catch (InvalidCipherTextException var4) {
            throw new Exception("加密失败:" + var4.getMessage());
        }
        return Hex.toHexString(bodyBytes);
    }

    public static ECPrivateKeyParameters importPrivateKey(String privateKeyHex) {
        BigInteger privateKey = new BigInteger(privateKeyHex, 16);
        return new ECPrivateKeyParameters(privateKey, DOMAIN_PARAMS);
    }

    /**
     * 方法描述：sm2解密
     */
    public static String sm2Decrypt(String signature, String cipherText) throws Exception {
        ECPrivateKeyParameters ecPrivateKeyParameters = importPrivateKey(signature);
        byte[] bodyBytes;
        try {
            SM2Engine engine = new SM2Engine();
            byte[] sm2CipherText = Hex.decode(cipherText.getBytes(StandardCharsets.UTF_8));
            engine.init(false, ecPrivateKeyParameters);
            bodyBytes = engine.processBlock(sm2CipherText, 0, sm2CipherText.length);
        } catch (InvalidCipherTextException var3) {
            throw new Exception("解密失败:" + var3.getMessage());
        }
        return new String(bodyBytes, StandardCharsets.UTF_8);
    }
}