星先 2021-10-04 23:49 采纳率: 75%
浏览 157
已结题

求个好用的2021吉林省医保C#SM2签名实现的demo。

如题需求,没弄过SM2,求助下,自己想办法时间上来不及了。求个好用的2021吉林省医保C#SM2签名实现的demo。

  • 写回答

3条回答 默认 最新

  • 神仙别闹 2021-10-04 23:57
    关注

    依赖NuGet包 Portable.BouncyCastle

    using Org.BouncyCastle.Asn1.GM;
    using Org.BouncyCastle.Crypto;
    using Org.BouncyCastle.Crypto.Digests;
    using Org.BouncyCastle.Crypto.Engines;
    using Org.BouncyCastle.Crypto.Generators;
    using Org.BouncyCastle.Crypto.Parameters;
    using Org.BouncyCastle.Crypto.Signers;
    using Org.BouncyCastle.Math;
    using Org.BouncyCastle.Security;
    using Org.BouncyCastle.Utilities.Encoders;
    using System;
    using System.Text.RegularExpressions;
     
    public class SM2
    {
        public SM2(string pubkey, string privkey, Mode mode)
        {
            if (pubkey != null) this.pubkey = Decode(pubkey);
            if (privkey != null) this.privkey = Decode(privkey);
            this.mode = mode;
        }
        public SM2(byte[] pubkey, byte[] privkey, Mode mode)
        {
            this.pubkey = pubkey;
            this.privkey = privkey;
            this.mode = mode;
        }
        byte[] pubkey;
        byte[] privkey;
        Mode mode;
        ICipherParameters _privateKeyParameters;
        ICipherParameters PrivateKeyParameters
        {
            get
            {
                var r = _privateKeyParameters;
                if (r == null) r = _privateKeyParameters = new ECPrivateKeyParameters(new BigInteger(1, privkey), new ECDomainParameters(GMNamedCurves.GetByName("SM2P256V1")));
                return r;
            }
        }
        ICipherParameters _publicKeyParameters;
        ICipherParameters PublicKeyParameters
        {
            get
            {
                var r = _publicKeyParameters;
                if (r == null)
                {
                    var x9ec = GMNamedCurves.GetByName("SM2P256V1");
                    r = _publicKeyParameters = new ECPublicKeyParameters(x9ec.Curve.DecodePoint(pubkey), new ECDomainParameters(x9ec));
                }
                return r;
            }
        }
     
        public static void GenerateKeyHex(out string pubkey, out string privkey)
        {
            GenerateKey(out var a, out var b);
            pubkey = Hex.ToHexString(a);
            privkey = Hex.ToHexString(b);
        }
        public static void GenerateKey(out byte[] pubkey, out byte[] privkey)
        {
            var g = new ECKeyPairGenerator();
            g.Init(new ECKeyGenerationParameters(new ECDomainParameters(GMNamedCurves.GetByName("SM2P256V1")), new SecureRandom()));
            var k = g.GenerateKeyPair();
            pubkey = ((ECPublicKeyParameters)k.Public).Q.GetEncoded(false);
            privkey = ((ECPrivateKeyParameters)k.Private).D.ToByteArray();
        }
        public byte[] Decrypt(byte[] data)
        {
            if (mode == Mode.C1C3C2) data = C132ToC123(data);
            var sm2 = new SM2Engine(new SM3Digest());
            sm2.Init(false, this.PrivateKeyParameters);
            return sm2.ProcessBlock(data, 0, data.Length);
        }
        public byte[] Encrypt(byte[] data)
        {
            var sm2 = new SM2Engine(new SM3Digest());
            sm2.Init(true, new ParametersWithRandom(PublicKeyParameters));
            data = sm2.ProcessBlock(data, 0, data.Length);
            if (mode == Mode.C1C3C2) data = C123ToC132(data);
            return data;
        }
        public byte[] Sign(byte[] msg, byte[] id = null)
        {
            var sm2 = new SM2Signer(new SM3Digest());
            ICipherParameters cp;
            if (id != null) cp = new ParametersWithID(new ParametersWithRandom(PrivateKeyParameters), id);
            else cp = new ParametersWithRandom(PrivateKeyParameters);
            sm2.Init(true, cp);
            sm2.BlockUpdate(msg, 0, msg.Length);
            return sm2.GenerateSignature();
        }
        public bool VerifySign(byte[] msg, byte[] signature, byte[] id = null)
        {
            var sm2 = new SM2Signer(new SM3Digest());
            ICipherParameters cp;
            if (id != null) cp = new ParametersWithID(PublicKeyParameters, id);
            else cp = PublicKeyParameters;
            sm2.Init(false, cp);
            sm2.BlockUpdate(msg, 0, msg.Length);
            return sm2.VerifySignature(signature);
        }
        static byte[] C123ToC132(byte[] c1c2c3)
        {
            var gn = GMNamedCurves.GetByName("SM2P256V1");
            int c1Len = (gn.Curve.FieldSize + 7) / 8 * 2 + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
            int c3Len = 32; //new SM3Digest().getDigestSize();
            byte[] result = new byte[c1c2c3.Length];
            Array.Copy(c1c2c3, 0, result, 0, c1Len); //c1
            Array.Copy(c1c2c3, c1c2c3.Length - c3Len, result, c1Len, c3Len); //c3
            Array.Copy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.Length - c1Len - c3Len); //c2
            return result;
        }
        static byte[] C132ToC123(byte[] c1c3c2)
        {
            var gn = GMNamedCurves.GetByName("SM2P256V1");
            int c1Len = (gn.Curve.FieldSize + 7) / 8 * 2 + 1;
            int c3Len = 32; //new SM3Digest().getDigestSize();
            byte[] result = new byte[c1c3c2.Length];
            Array.Copy(c1c3c2, 0, result, 0, c1Len); //c1: 0->65
            Array.Copy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.Length - c1Len - c3Len); //c2
            Array.Copy(c1c3c2, c1Len, result, c1c3c2.Length - c3Len, c3Len); //c3
            return result;
        }
        static byte[] Decode(string key)
        {
            return Regex.IsMatch(key, "^[0-9a-f]+$", RegexOptions.IgnoreCase) ? Hex.Decode(key) : Convert.FromBase64String(key);
        }
        public enum Mode
        {
            C1C2C3, C1C3C2
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 10月12日
  • 已采纳回答 10月8日
  • 创建了问题 10月4日

悬赏问题

  • ¥15 MATLAB怎么通过柱坐标变换画开口是圆形的旋转抛物面?
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥30 用arduino开发esp32控制ps2手柄一直报错
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题
  • ¥15 Visual Studio问题