C#SM2加密算法

发布时间 2023-08-16 14:55:55作者: 【君莫笑】
1.新建SM2Util类
    public class SM2Util
    {
        /**
           * 生成SM2秘钥对
           * string[0] 公钥
           * string[1] 私钥
           */
        public static string[] GenerateKeyPair()
        {
            return SM2.GenerateKeyPair();
        }

        /**
         * SM2签名
         * data 签名的数据
         * priKey 私钥
         */
        public static string Sign(string data, string priKey)
        {
            SM2 sm2 = new SM2(priKey, null);
            return sm2.Sign(data);

        }


        /**
         * SM2签名
         * sign 源数据
         * pubKey 公钥
         * sign 签名的数据
         */
        public static bool verifySign(string msg, string pubKey, string sign)
        {
            SM2 sm2 = new SM2(null, pubKey);
            return sm2.verifySign(msg, sign);
        }


        /**
         * 加密
         * 返回Base64字符串
         *  公钥加密
         *  plainText 要加密的文本
         *  pubKey 公钥
         */
        public static string encryptBase64(string plainText, string pubKey)
        {
            SM2 sm2 = new SM2(null, pubKey);
            byte[] encryptByte = sm2.encrypt(Encoding.UTF8.GetBytes(plainText));
            return Base64.ToBase64String(encryptByte);
        }

        /**
         * 解密
         *  私钥解密
         *  plainText 要加密的文本
         *  pubKey 公钥
         */
        public static string decryptBase64(string plainText, string priKey)
        {
            SM2 sm2 = new SM2(priKey, null);
            byte[] deCode = Base64.Decode(plainText);
            byte[] decryptText = sm2.deceypt(deCode);
            return Encoding.UTF8.GetString(decryptText);
        }
    }
2.新建SM2类
class SM2
    {

        private ECPrivateKeyParameters privateKeyParameters;


        private ECPublicKeyParameters publicKeyParameters;

        private SM2Param sm2Param;

        public SM2(string priKey, string pubKey)
        {
            this.init(HexUtils.decode(priKey), HexUtils.decode(pubKey));
        }

        private void init(byte[] priKey, byte[] pubKey)
        {
            this.sm2Param = new SM2Param();
            if (null != priKey && this.privateKeyParameters == null)
            {
                this.privateKeyParameters = new ECPrivateKeyParameters(new BigInteger(1, priKey), this.sm2Param.ecc_bc_spec);
            }
            if (null != pubKey && this.publicKeyParameters == null)
            {
                this.publicKeyParameters = new ECPublicKeyParameters(this.sm2Param.ecc_curve.DecodePoint(pubKey), this.sm2Param.ecc_bc_spec);

            }
        }


        /**
         * 加签
         */
        public string Sign(string data)
        {
            byte[] msg = Encoding.UTF8.GetBytes(data);
            SM2Signer sm2Signer = new SM2Signer();
            sm2Signer.Init(true, this.privateKeyParameters);
            sm2Signer.BlockUpdate(msg, 0, msg.Length);
            return Base64.ToBase64String(sm2Signer.GenerateSignature());
        }


        /*
         * 验签
         */
        public bool verifySign(string data, string sign)
        {
            byte[] signBase64 = Base64.Decode(sign);
            byte[] msgByte = Encoding.UTF8.GetBytes(data);
            SM2Signer sm2Signer = new SM2Signer();
            sm2Signer.Init(false, this.publicKeyParameters);
            sm2Signer.BlockUpdate(msgByte, 0, msgByte.Length);
            return sm2Signer.VerifySignature(signBase64);
        }

        /**
         * 加密
         * 
         */
        public byte[] encrypt(byte[] plainText)
        {
            SM2Engine engine = new SM2Engine();
            engine.Init(true, new ParametersWithRandom(this.publicKeyParameters));
            return engine.ProcessBlock(plainText, 0, plainText.Length);
        }
    

        /**
         * 
         * 解密
         * 
         */
        public byte[] deceypt(byte[] plainText)
        {
            byte[] plain = plainText;
            SM2Engine engine = new SM2Engine();
            engine.Init(false, this.privateKeyParameters);
            return engine.ProcessBlock(plain, 0, plain.Length);
        }


        public static string[] GenerateKeyPair()
        {
            AsymmetricCipherKeyPair kPair = genCipherKeyPair();
            ECPrivateKeyParameters ecPrivateKey = (ECPrivateKeyParameters)kPair.Private;
            ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kPair.Public;
            BigInteger priKey = ecPrivateKey.D;
            ECPoint pubKey = ecPublicKey.Q;
            byte[] priByte = priKey.ToByteArray();
            byte[] pubByte = pubKey.GetEncoded(false);
            if (priByte.Length == 33)
            {
                Console.WriteLine("private key size 33");
                byte[] newPriByte = new byte[32];
                Array.Copy(priByte, 1, newPriByte, 0, 32);
                priByte = newPriByte;
            }
            string[] keyPairs = new string[] { Hex.ToHexString(pubByte), Hex.ToHexString(priByte) };
            return keyPairs;
        }


        /**
         *      生成引用
         * */
        private static AsymmetricCipherKeyPair genCipherKeyPair()
        {
            SM2Param ecc_param = new SM2Param();
            ECDomainParameters ecDomainParamters = ecc_param.ecc_bc_spec;
            ECKeyGenerationParameters ecGenParam = new ECKeyGenerationParameters(ecDomainParamters, new SecureRandom());

            ECKeyPairGenerator ecKeyPairGenerator = new ECKeyPairGenerator();
            ecKeyPairGenerator.Init(ecGenParam);
            return ecKeyPairGenerator.GenerateKeyPair();
        }

        private class SM2Param
        {
            public static String[] ecc_param = { "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" };
            public BigInteger ecc_p;
            public BigInteger ecc_a;
            public BigInteger ecc_b;
            public BigInteger ecc_n;
            public BigInteger ecc_gx;
            public BigInteger ecc_gy;
            public ECCurve ecc_curve;
            public ECDomainParameters ecc_bc_spec;

            public SM2Param()
            {
                this.ecc_p = new BigInteger(ecc_param[0], 16);
                this.ecc_a = new BigInteger(ecc_param[1], 16);
                this.ecc_b = new BigInteger(ecc_param[2], 16);
                this.ecc_n = new BigInteger(ecc_param[3], 16);
                this.ecc_gx = new BigInteger(ecc_param[4], 16);
                this.ecc_gy = new BigInteger(ecc_param[5], 16);
                this.ecc_curve = new FpCurve(ecc_p, ecc_a, ecc_b, ecc_n, BigInteger.One);
                this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_curve.CreatePoint(this.ecc_gx, this.ecc_gy), this.ecc_n);
            }
        }
    }
3.新建HexUtils
class HexUtils
    {
        private const string pattern = "^[a-f0-9]+$";

        public static bool isHex(string value)
        {
            if (null == value)
            {
                return false;
            }
            return System.Text.RegularExpressions.Regex.IsMatch(value, pattern);
        }

        public static byte[] decode(String str)
        {
            if (null == str)
            {
                return null;
            }
            if (isHex(str))
            {
                return hexStrToByte(str);
            }
            return Org.BouncyCastle.Utilities.Encoders.Base64.Decode(str);
        }

        public static byte[] hexStrToByte(String hexStr)
        {
            if ((null == hexStr) || (hexStr.Length == 0))
            {
                return null;
            }
            char[] hexData = hexStr.ToCharArray();
            int len = hexData.Length;
            if ((len & 0x1) != 0)
            {
                throw new SystemException("Odd number of characters.");
            }
            byte[] out1 = new byte[len >> 1];

            int i = 0;
            for (int j = 0; j < len; i++)
            {
                int f = toDigit(hexData[j], j) << 4;
                j++;
                f |= toDigit(hexData[j], j);
                j++;
                out1[i] = ((byte)(f & 0xFF));
            }
            return out1;
        }

        private static int toDigit(char ch, int index)
        {
            int digit = Convert.ToInt32(ch.ToString(), 16);
            //int digit = Character.digit(ch, 16);
            if (digit == -1)
            {
                throw new SystemException("Illegal hexadecimal character " + ch + " at index " + index);
            }
            return digit;
        }
    }
4.主函数
static void Main(string[] args)
        {
            String pubKey = "045b50327b39fe34374deeeaf44c1ed0f0bd7e20850c67ade650afdec125809fd8e499d3305d239864ef57af9218b490f204c33af1c31fd4a101d4989d579ec047";
            String priKey = "4e643581e15cbfecbfbb57b401a7eae91b9aa1073561b20606f28a03df16eec2";
            Console.WriteLine("公钥:" + pubKey);
            Console.WriteLine("私钥:" + priKey);

            Console.WriteLine("============================");

            String input = "POST|/api/v1.0/payment/pay-result-query|1627787104425|{\"payCode\":\"CK000000000011222324470415459\"}";
            Console.WriteLine("input:" + input);

            String sign = SM2Util.Sign(input, priKey);
            Console.WriteLine("sign:" + sign);

            Boolean success = SM2Util.verifySign(input, pubKey, sign);
            Console.WriteLine("success:" + success);


            Console.WriteLine("============================");

            String input2 = "湘A88888";
            String encrypt = SM2Util.encryptBase64(input2, pubKey);
            Console.WriteLine("encrypt:" + encrypt);

            String decrypt = SM2Util.decryptBase64(encrypt, priKey);
            Console.WriteLine("decrypt:" + decrypt);

        }
5.引入BouncyCastle.Crypto.dll动态库   注意动态库不同版本加密代码不一样*****
BouncyCastle.Crypto.dll动态库下载 https://files.cnblogs.com/files/ywtssydm/BouncyCastle.Crypto.rar?t=1692167684&download=true
完整代码下载: https://files.cnblogs.com/files/ywtssydm/CSharpDemo.zip?t=1692168492&download=true
更多资料:https://blog.csdn.net/a497785609/article/details/129102042
完整代码下载2:https://files.cnblogs.com/files/ywtssydm/sm2.rar?t=1692168765&download=true