C# 国密SM2 密钥生成加密解密签名验签

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
    }
}

依赖NuGet包 Portable.BouncyCastle

原文地址 https://blog.csdn.net/slwsss/article/details/115066221

提供给第三方软件,调用COM组件DLL方式进行实现,如delphi、PB等。调用方法与黑龙江省医保社保卡调用方式一致。各软件调用方法也可自行网上查询,如“delphi调用C#的COM组件DLL”。 基于C#编写的COM组件DLL,可实现SM2签名验签,SM4加解密,100%适用于黑龙江省国家医保接口中进行应用。 1、调用DLL名称:JQSM2SM4.dll 加解密类名:JQSM2SM4.SM2SM4Util CLSID=5B38DCB3-038C-4992-9FA3-1D697474FC70 2、GetSM2SM4函数说明 函数原型public string GetSM2SM4(string smType, string sM2Prikey, string sM4Key, string sInput) 1)参数一smType:填写固定字符串,识别功能,分别实现SM2签名、SM4解密、SM4加密。SM2签名入参填写“SM2Sign”、SM4解密入参填写“SM4DecryptECB”、SM4加密入参填写“SM4EncryptECB”. 2)参数二sM2Prikey:SM2私钥 3)参数三sM4Key:SM4密钥 4)参数四sInput:当smType=SM2Sign,则sInput入参填写SM4加密串;当smType=SM4DecryptECB,则sInput入参填写待解密SM4密文串;当smType=SM4EncryptECB,则sInput入参填写待加密的明文串; 5)函数返回值:当smType=SM2Sign,则返回SM2签名信息;当smType=SM4DecryptECB,则返回SM4解密信息;当smType=SM4EncryptECB,则返回SM4加密信息;异常时,则返回“加解密异常:详细错误说明” 3、购买下载后,可加QQ65635204、微信feisng,免费提供技术支持。 4、注意事项: 1)基于.NET框架4.0编写,常规win7、win10一般系统都自带无需安装,XP系统则需安装;安装包详见压缩包dotNetFx40_Full_x86_x64.exe 2)C#编写的DLL,需要注册,解压后放入所需位置,使用管理员权限运行“JQSM2SM4注册COM.bat”即可注册成功,然后即可提供给第三方软件进行使用,如delphi、PB等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值