整理sm2国密算法

bluewelkin 2020-05-10

/// 
    ///     国密SM2算法(ECC算法)加密器
    ///     签名部分采用SM3算法进行摘要计算
    /// 
    public class Sm2Encryptor
    {
        /// 
        ///     SM2算法默认用户ID,目前开放平台不会使用非默认用户ID
        /// 
        public const string DefaultUserId = "1234567812345678";

        public string GetAsymmetricType()
        {
            return "SM2";
        }

        public (string privatePem, string publicPem) DoKeyPairGenerator()
        {
            var SM2_ECC_P        = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16);
            var SM2_ECC_A        = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16);
            var SM2_ECC_B        = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16);
            var SM2_ECC_N        = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16);
            var SM2_ECC_H        = BigInteger.One;
            var SM2_ECC_GX       = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
            var SM2_ECC_GY       = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
            var SM2_ECC_Random   = new SecureRandom();

            ECCurve curve        = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H);

            var g                = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY);
            var domainParams     = new ECDomainParameters(curve, g, SM2_ECC_N);

            var keyPairGenerator = new ECKeyPairGenerator();


            var aKeyGenParams    = new ECKeyGenerationParameters(domainParams, SM2_ECC_Random);

            keyPairGenerator.Init(aKeyGenParams);

            var aKp              = keyPairGenerator.GenerateKeyPair();

            var aPub             = (ECPublicKeyParameters) aKp.Public;
            var aPriv            = (ECPrivateKeyParameters) aKp.Private;

            var pkinfoPri        = PrivateKeyInfoFactory.CreatePrivateKeyInfo(aPriv);
            var priPem           = Convert.ToBase64String(pkinfoPri.GetDerEncoded());

            var pkinfoPub        = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(aPub);
            var pubPem           = Convert.ToBase64String(pkinfoPub.GetDerEncoded());
            return (priPem, pubPem);
        }

        public string DoDecrypt(string cipherTextBase64, string charset, string privateKey)
        {
            //加载私钥参数
            var cipherParams = BuildPrivateKeyParams(privateKey).Parameters;

            //初始化SM2算法引擎
            var sm2Engine    = new SM2Engine();
            sm2Engine.Init(false, cipherParams);

            //对输入密文进行解密
            var input        = Convert.FromBase64String(cipherTextBase64);
            var output       = sm2Engine.ProcessBlock(input, 0, input.Length);

            //将解密后的明文按指定字符集编码后返回
            return Encoding.GetEncoding(charset).GetString(output);
        }

        public string DoEncrypt(string plainText, string charset, string publicKey)
        {
            //加载公钥参数
            var cipherParams         = BuildPublicKeyParams(publicKey).Parameters;
            var parametersWithRandom = new ParametersWithRandom(cipherParams);

            //初始化SM2算法引擎
            var sm2Engine            = new SM2Engine();
            sm2Engine.Init(true, parametersWithRandom);

            //对输入明文进行加密
            var input                = Encoding.GetEncoding(charset).GetBytes(plainText);
            var output               = sm2Engine.ProcessBlock(input, 0, input.Length);

            //将密文Base64编码后返回
            return Convert.ToBase64String(output);
        }

        public string DoSign(string content, string charset, string privateKey)
        {
            //加载私钥参数
            var parametersWithId = BuildPrivateKeyParams(privateKey);

            //加载签名器
            var signer           = new SM2Signer();
            signer.Init(true, parametersWithId);

            //向签名器中输入原文
            var input            = Encoding.GetEncoding(charset).GetBytes(content);
            signer.BlockUpdate(input, 0, input.Length);

            //将签名结果转换为Base64
            return Convert.ToBase64String(signer.GenerateSignature());
        }

        public bool DoVerify(string content, string charset, string publicKey, string sign)
        {
            //加载公钥参数
            var parametersWithId = BuildPublicKeyParams(publicKey);

            //加载签名器
            var signer           = new SM2Signer();
            signer.Init(false, parametersWithId);

            //向签名器中输入原文
            var input            = Encoding.GetEncoding(charset).GetBytes(content);
            signer.BlockUpdate(input, 0, input.Length);

            //传入指定签名串进行验签并返回结果
            return signer.VerifySignature(Convert.FromBase64String(sign));
        }

        private ParametersWithID BuildPrivateKeyParams(string privateKey)
        {
            var key              = PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
            var parametersWithId = new ParametersWithID(key, Encoding.UTF8.GetBytes(DefaultUserId));
            return parametersWithId;
        }

        private static ParametersWithID BuildPublicKeyParams(string publicKey)
        {
            var key              = PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
            var parametersWithId = new ParametersWithID(key, Encoding.UTF8.GetBytes(DefaultUserId));
            return parametersWithId;
        }
    }
    //推荐参数http://www.oscca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml
    //参考:https://github.com/alipay/alipay-sdk-net-all
    //参考:https://github.com/Arthurvdmerwe/AS2805.6.5.3/blob/6ee870947c0504da427734604aa79503d8ee3607/Crypto/test/src/crypto/test/SM2EngineTest.cs

相关推荐