首页 > 编程语言 >C# .NET Framework 实现SM2加签、验签

C# .NET Framework 实现SM2加签、验签

时间:2024-07-02 17:30:48浏览次数:15  
标签:return C# userId SM2 param Framework static msg byte

本文只实现SM2的加签以及验签。
首先需要安装包 Portable.BouncyCastle。然后创建类 EasyGmutil

Code

namespace ConsoleApp1
{
    public class EasyGmUtil
    {
        private static X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");
        private static ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
    /**
      *
      * @param msg
      * @param userId
      * @param privateKey
      * @return r||s,直接拼接byte数组的rs
      */
    public static byte[] signSm3WithSm2(byte[] msg, byte[] userId, byte[] privateKeyBytes)
    {
        ECPrivateKeyParameters privateKeyParameters = getPrivatekeyFromD(new BigInteger(1, privateKeyBytes));
        return rsAsn1ToPlainByteArray(signSm3WithSm2Asn1Rs(msg, userId, privateKeyParameters));
    }


    /**
      * @param msg
      * @param userId
      * @param privateKey
      * @return rs in <b>asn1 format</b>
      */
    public static byte[] signSm3WithSm2Asn1Rs(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey)
    {
        try
        {
            ISigner signer = SignerUtilities.InitSigner("SM3withSM2", true, privateKey, new SecureRandom());
            signer.BlockUpdate(msg, 0, msg.Length);
            byte[] sig = signer.GenerateSignature();
            return sig;
        }
        catch (Exception e)
        {
            return null;
        }
    }


    /**
  *
  * @param msg
  * @param userId
  * @param rs r||s,直接拼接byte数组的rs
  * @param publicKey
  * @return
  */
    public static bool verifySm3WithSm2(byte[] msg, byte[] userId, byte[] rs, byte[] publicKeyBytes)
    {
        if (rs == null || msg == null || userId == null) return false;
        if (rs.Length != RS_LEN * 2) return false;

        if (publicKeyBytes.Length != 64 && publicKeyBytes.Length != 65) throw new ArgumentException("err key length");
        BigInteger x, y;
        if (publicKeyBytes.Length > 64)
        {
            x = fromUnsignedByteArray(publicKeyBytes, 1, 32);
            y = fromUnsignedByteArray(publicKeyBytes, 33, 32);
        }
        else
        {
            x = fromUnsignedByteArray(publicKeyBytes, 0, 32);
            y = fromUnsignedByteArray(publicKeyBytes, 32, 32);
        }
        ECPublicKeyParameters publicKey = getPublickeyFromXY(x, y);
        return verifySm3WithSm2Asn1Rs(msg, userId, rsPlainByteArrayToAsn1(rs), publicKey);
    }

    public static BigInteger fromUnsignedByteArray(byte[] var0, int var1, int var2)
    {
        byte[] var3 = var0;
        if (var1 != 0 || var2 != var0.Length)
        {
            var3 = new byte[var2];
            Array.Copy(var0, var1, var3, 0, var2);
        }

        return new BigInteger(1, var3);
    }

    /**
     *
     * @param msg
     * @param userId
     * @param rs in <b>asn1 format</b>
     * @param publicKey
     * @return
     */

    public static bool verifySm3WithSm2Asn1Rs(byte[] msg, byte[] userId, byte[] sign, AsymmetricKeyParameter publicKey)
    {
        try
        {
            ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
            signer.Init(false, publicKey);
            signer.BlockUpdate(msg, 0, msg.Length);
            return signer.VerifySignature(sign);
        }
        catch (Exception e)
        {
            return false;
        }
    }

    public static ECPrivateKeyParameters getPrivatekeyFromD(BigInteger d)
    {
        return new ECPrivateKeyParameters(d, ecDomainParameters);
    }

    public static ECPublicKeyParameters getPublickeyFromXY(BigInteger x, BigInteger y)
    {
        return new ECPublicKeyParameters(x9ECParameters.Curve.CreatePoint(x, y), ecDomainParameters);
    }

    private const int RS_LEN = 32;

    private static byte[] bigIntToFixexLengthBytes(BigInteger rOrS)
    {
        // for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123,
        // r and s are the result of mod n, so they should be less than n and have length<=32
        byte[] rs = rOrS.ToByteArray();
        if (rs.Length == RS_LEN) return rs;
        else if (rs.Length == RS_LEN + 1 && rs[0] == 0) return Arrays.CopyOfRange(rs, 1, RS_LEN + 1);
        else if (rs.Length < RS_LEN)
        {
            byte[] result = new byte[RS_LEN];
            Arrays.Fill(result, (byte)0);
            Buffer.BlockCopy(rs, 0, result, RS_LEN - rs.Length, rs.Length);
            return result;
        }
        else
        {
            throw new ArgumentException("err rs: " + Hex.ToHexString(rs));
        }
    }

    /**
     * BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
     * @param rsDer rs in asn1 format
     * @return sign result in plain byte array
     */
    private static byte[] rsAsn1ToPlainByteArray(byte[] rsDer)
    {
        Asn1Sequence seq = Asn1Sequence.GetInstance(rsDer);
        byte[] r = bigIntToFixexLengthBytes(DerInteger.GetInstance(seq[0]).Value);
        byte[] s = bigIntToFixexLengthBytes(DerInteger.GetInstance(seq[1]).Value);
        byte[] result = new byte[RS_LEN * 2];
        Buffer.BlockCopy(r, 0, result, 0, r.Length);
        Buffer.BlockCopy(s, 0, result, RS_LEN, s.Length);
        return result;
    }

    /**
     * BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
     * @param sign in plain byte array
     * @return rs result in asn1 format
     */
    private static byte[] rsPlainByteArrayToAsn1(byte[] sign)
    {
        if (sign.Length != RS_LEN * 2) throw new ArgumentException("err rs. ");
        BigInteger r = new BigInteger(1, Arrays.CopyOfRange(sign, 0, RS_LEN));
        BigInteger s = new BigInteger(1, Arrays.CopyOfRange(sign, RS_LEN, RS_LEN * 2));
        Asn1EncodableVector v = new Asn1EncodableVector();
        v.Add(new DerInteger(r));
        v.Add(new DerInteger(s));
        try
        {
            return new DerSequence(v).GetEncoded("DER");
        }
        catch (IOException e)
        {
            //log.Error("RsPlainByteArrayToAsn1 error: " + e.Message, e);
            return null;
        }
    }
}

}

此处为签名及验签 Demo

Code
string PrivateKey = "AJciGDkPWcwX"; // 私钥,用于加签,此处是乱写的
string PublicKey = "BFaPS+Hj3eXg4ENOXDjrpLhwNIY";  // 公钥,与私钥配对,此处是乱写的

string userId = "";
string str = "TestContent";
//对字符串签名
byte[] signByte = EasyGmUtil.signSm3WithSm2(Encoding.UTF8.GetBytes(str),
Encoding.UTF8.GetBytes(userId), Org.BouncyCastle.Utilities.Encoders.Base64.Decode(PrivateKey));
string signStr = Org.BouncyCastle.Utilities.Encoders.Base64.ToBase64String(signByte);

//验签
bool flag = EasyGmUtil.verifySm3WithSm2(Encoding.UTF8.GetBytes(str), Encoding.UTF8.GetBytes(userId),
Org.BouncyCastle.Utilities.Encoders.Base64.Decode(signStr),
Org.BouncyCastle.Utilities.Encoders.Base64.Decode(PublicKey));

标签:return,C#,userId,SM2,param,Framework,static,msg,byte
From: https://www.cnblogs.com/waou/p/18280259

相关文章

  • 深入理解Qt多线程编程(QtConcurrent)
    多线程编程在现代软件开发中变得越来越重要,它能够提高应用程序的响应速度和处理性能。在Qt框架中,除了QThreadPool,QtConcurrent也是一个强大的工具,用于简化和管理多线程编程。目录概述接口详解QtConcurrent::runQtConcurrent::mapQtConcurrent::mappedQtConcurrent::filt......
  • CAD图纸怎么加密?(五种简单的CAD图纸加密方法分享)
    在企业中,CAD图纸通常含有许多敏感且机密信息,对设计图纸的安全保护至关重要。为确保CAD图纸不被未经授权的人访问、复制或篡改,企业需要采用有效的加密措施。以下是一些常用的方法和工具,帮助企业对CAD图纸进行加密保护:加密软件https://www.gooxion.com/一、加密软件......
  • 大学生HTML期末大作业——HTML+CSS+JavaScript运动网站(田径)
    HTML+CSS+JS【运动网站】网页设计期末课程大作业web前端开发技术web课程设计网页规划与设计......
  • 大学生HTML期末大作业——HTML+CSS+JavaScript购物商城(Oppo)
    HTML+CSS+JS【购物商城】网页设计期末课程大作业web前端开发技术web课程设计网页规划与设计......
  • ast数据类型补充和基础代码注释-cnblog
    ast解析代码树//声明一个变量obj,并赋值一个对象letobj={//对象的属性name,值为字符串"大猩猩"name:"大猩猩",//对象的方法add,接受两个参数a和badd:function(a,b){//返回参数a和b的和加上1000returna+b+1000;......
  • 红队工具Finger 安装具体以步骤-示例centos
    1.gitclonehttps://github.com/EASY233/Finger.git如果没有yuminstallgit2.pip3install-rrequirements.txt找到finger所在的文件夹可以用find-name"Finger"进入文件中配置命令前提要安装pythonyuminstallpython-pip33.python3Finger.py-h......
  • this.$refs[tab.$attrs.id].scrollIntoView is not a function
    打印this.$refs[tab.$attrs.id].scrollIntoView 在控制台看到的是一个undefined是因为this.$refs[tab.$attrs.id]不是一个dom是一个vuecomponent如图所示:所以我用的这个document.querySelector(`.${tab.$attrs.id}`)获取domdocument.querySelector(`.${tab.$attrs......
  • Navicat for MySQL 11软件下载及安装教程
    ​根据行业数据显示数据库备份和恢复:Navicat提供了备份和恢复数据库的功能,使用者能够创建定期的数据库备份,并在需要时恢复数据,这有助于保护数据免受意外删除、损坏或灾难性事件的影响。也就是说数据导入和导出:Navicat提供了灵活的数据导入和导出功能,能够从不同的数据源导入数据......
  • 【electron-vite+live2d+vue3+element-plus】实现桌面模型宠物+桌面管理系统应用(踩坑)
    脚手架项目使用electron-vite脚手架搭建ps:还有一个框架是electron-vite,这个框架我发现与pixi库有冲突,无法使用,如果不用pixi也可以用这个脚手架。node版本建议18+----------------------------------------------------------------------------------------运行live2D......
  • SI24R03国产RISC-V内核2.4G无线收发SoC芯片
    RISC-V架构的优势相对于目前主流的英特尔X86架构及ARM等架构来说,RISC-V架构具有指令精简、模块化、可扩展、开源、免费等优点。RISC-V的基础指令集只有40多条,加上其他基本的模块化扩展指令总共几十条指令,非常简单,而且任何企业、开发者都可以免费、自由且不受限制地使用RISC-V指......