using System;
using System.Text;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using Com.Bocom.OpenApi.Security.Crypt;

namespace Com.Bocom.OpenApi
{
    namespace Security
    {
        namespace KeyGen
        {
            public class SM2KeyGen
            {
                public static AsymmetricCipherKeyPair GenSM2KeyPair()
                {
                    // 获取SM2标准中推荐的256bit的质数域的椭圆曲线域参数
                    X9ECParameters x9ECParameters = GMNamedCurves.GetByOid(GMObjectIdentifiers.sm2p256v1);
                    ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters);
                    
                    // 构造EC密钥生成算法参数
                    ECKeyGenerationParameters ecKeyGenerationParameters =
                        new ECKeyGenerationParameters(ecDomainParameters, new SecureRandom());

                    // 初始化EC密钥生成器
                    IAsymmetricCipherKeyPairGenerator asymmetricCipherKeyPairGenerator =
                        GeneratorUtilities.GetKeyPairGenerator("EC");
                    asymmetricCipherKeyPairGenerator.Init(ecKeyGenerationParameters);

                    return asymmetricCipherKeyPairGenerator.GenerateKeyPair();
                }

                /// <summary>
                /// 从KeyPair对象中得到字符串表示的公钥（Hex编码）。
                /// </summary>
                /// <param name="keyPair"></param>
                /// <returns></returns>
                public static string GetPublicKeyStr(AsymmetricCipherKeyPair keyPair)
                {
                    ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.Public;
                    return Encoding.UTF8.GetString(Hex.Encode(publicKey.Q.GetEncoded(false)));
                }

                /// <summary>
                /// 从KeyPair对象中得到字符串表示的私钥（Hex编码）。
                /// </summary>
                /// <param name="keyPair"></param>
                /// <returns></returns>
                public static string GetPrivateKeyStr(AsymmetricCipherKeyPair keyPair)
                {
                    ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.Private;
                    return Encoding.UTF8.GetString(Hex.Encode(privateKey.D.ToByteArray()));
                }

                /// <summary>
                /// 公钥字符串（Hex编码）转成ECPublicKeyParameters对象。
                /// </summary>
                /// <param name="publicKey"></param>
                /// <returns></returns>
                public static ECPublicKeyParameters GetECPublicKey(string publicKey)
                {
                    X9ECParameters x9ECParameters = GMNamedCurves.GetByOid(GMObjectIdentifiers.sm2p256v1);

                    ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters);

                    ECPoint q = x9ECParameters.Curve.DecodePoint(Hex.Decode(Encoding.UTF8.GetBytes(publicKey)));

                    return new ECPublicKeyParameters(q, ecDomainParameters);
                }

                /// <summary>
                /// 私钥字符串（Hex编码）转成ECPrivateKeyParameters对象。
                /// </summary>
                /// <param name="privateKey"></param>
                /// <returns></returns>
                public static ECPrivateKeyParameters GetECPrivateKey(string privateKey)
                {
                    X9ECParameters x9ECParameters = GMNamedCurves.GetByOid(GMObjectIdentifiers.sm2p256v1);

                    ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters);

                    BigInteger d = new BigInteger(Hex.Decode(Encoding.UTF8.GetBytes(privateKey)));

                    return new ECPrivateKeyParameters(d, ecDomainParameters);
                }

                public static void Main(string[] args)
                {
                    AsymmetricCipherKeyPair keyPair = SM2KeyGen.GenSM2KeyPair();
                    string pubKey = SM2KeyGen.GetPublicKeyStr(keyPair);
                    string priKey = SM2KeyGen.GetPrivateKeyStr(keyPair);
                    Console.WriteLine("公钥：" + pubKey);
                    Console.WriteLine("公钥位数：" + pubKey.Length);
                    Console.WriteLine("私钥：" + priKey);
                    Console.WriteLine("私钥位数：" + priKey.Length);

                    string plainText = "交通银行软件开发中心";
                    string encryptedText = SM2Cryptor.Encrypt(plainText, "04d174bced6dab54eae6cb9d4c4794ea77008b4b123663c464084edc04b26da553ec3132b9d44ae5f28522beb0312d178f709d18cf9ad722d8ad0e4431085a2fb0", "UTF-8");
                    Console.WriteLine("加密后的密文：" + encryptedText);
                    string decryptedText = SM2Cryptor.Decrypt(encryptedText, "3dea5f72479ef4005e3017e617384d1bf4c66d536204dd44faa4c7075abfb5d5", "UTF-8");
                    Console.WriteLine("解密后的明文：" + decryptedText);
                }
            }
        }
    }
}