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

news/2024/7/7 16:04:34/文章来源:https://www.cnblogs.com/waou/p/18280259

本文只实现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<=32byte[] 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));

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/736414.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

odoo学习-2

1. 新加自定义模块odoo同级目录下新建my_addons文件夹加入自己的模块(注意:views中也要创建一个xml文件) 2. model代码-写在models下面的py文件中from odoo import api, fields, modelsclass EpidemicRecord(models.Model):_name = epidemic.record # 数据库表明name = fie…

C++定义函数指针,回调C#

C++定义函数指针,回调C#C++定义函数指针。 typedef int (__stdcall * delegate_func)(int a, int b); 暴露接口:int __stdcall CPPcallCSharp(delegate_func func); 方法实现:int __stdcall CPPcallCSharp(delegate_func func) { return func(1,2); } 头文件calculator.h#if…

《DNK210使用指南 -CanMV版 V1.0》第七章 基于CanMV的MicroPython语法开发环境搭建

第七章 基于CanMV的MicroPython语法开发环境搭建章节摘自【正点原子】DNK210使用指南 - CanMV版 V1.03)购买链接:https://detail.tmall.com/item.htm?&id=782801398750 4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/k210/ATK-DNK210.html 5)…

金蝶云星空字段之间连续触发值更新

场景说明字段A配置了字段B的计算公式,字段B配置了自动C的计算公式,修改A的时候,触发了B的重算,但是C触发不到。 具体需求:配置值更新事件:料本,料本系数, PCBA加工费,整机装配费,税率%【字段A】公式:供应链含税报价 = ( 料本 * 料本系数 + PCBA加工费 + 整…

PaddleNLP UIE 实体关系抽取

目录环境依赖配置SSH克隆代码训练定制代码结构数据标注准备语料库数据标注导出数据数据转换doccanoLabel Studio模型微调问题处理找不到 paddlenlp.trainer找不到GPUprotobuf==3.20.2CUDA/cuDNN/paddle PaddleNLP UIE 实体关系抽取 PaddlePaddle用户可领取免费Tesla V100在线算…

Python对历年高考分数线数据用聚类、决策树可视化分析一批、二批高校专业、位次、计划人数数据|附代码数据

全文链接:https://tecdat.cn/?p=36626 原文出处:拓端数据部落公众号 随着高等教育的普及与竞争的日益激烈,高考作为通往高等教育的重要门槛,其分数线的波动、高校及专业的选择成为了社会广泛关注的焦点。考生和家长在面临众多高校和专业的选择时,往往需要综合考虑多种因素…

阿里228x82y还原之递归数组解密

声明 本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 目标网站 某里228 分析逆向流程 228递归函数str解密 原理就是用数组push最后填充下,然…

ffmpeg在Windows上的安装

首先进入官网Download FFmpeg 选择windows版本下载想要的版本 Gyan.dev的版本可能会更符合Windows标准,而BtbN的版本可能会更加开放和跨平台往下拉选择想要的版本进行下载 我下载的是第一个下载好之后解压文件复制bin目录的路径 接着按照下面的顺序进行环境配置,结束后一路确…

leaflet如何把低层级瓦片在高层级显示

https://leafletjs.cn/reference.html#gridlayer使用了maxNativeZoom属性 示例 let map = L.map("map", {attributionControl: false,maxZoom: 18, }).setView([62, -82], 6);let layer_keepLevel_16 = L.tileLayer("url", {minZoom: 1,maxZoom: 18,maxNat…

Java JVM——11. 执行引擎

1.概述执行引擎属于JVM的下层,里面包括:解释器、即时编译器、垃圾回收器。执行引擎是Java虚拟机核心的组成部分之一。“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而…

vue3+vite打包优化

1、清除console和debugger 安装 terser插件npm install terser -Dbuild里添加terserOptions配置// 打包环境移除console.log,debugger terserOptions: { compress: { drop_console: true, drop_debugger: true } }, 二、gzip静态资源压缩 第一步:客户端打包开启首先下载 vit…

Java JVM 执行引擎深入解析

1.执行引擎概述执行引擎属于JVM的下层,里面包括:解释器、即时编译器、垃圾回收器。执行引擎是Java虚拟机核心的组成部分之一。“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面…

Vuex

Vuex 什么是Vuex? 概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对应用中多个组件的共享状态进行集中式管理(读/写),也是组件间通信的方式,且适用于任意组件间通信 之前想要传递数据,可以使用全局事件总线/消息订阅去实现,但是如果有很多组件都想要去读和写…

27-String类

String字符串是常量,创建之后不可改变 字符串字面值存储在字符串池中,可以共享 String s = "hello"; 产生一个对象,字符串池中存储 String s = new String("hello");//产生两个对象,堆、池各存储一个String name = "hello";//"hello…

01字典树和可持久化01字典树

01字典树 01字典树是一种只有0和1两种边的字典树。可以解决查询第 \(k\) 小,查询 \(x\) 是第几小等问题。 查询第 \(k\) 小 可以把输入的数转成等长二进制,然后插入01字典树。比如将 \([0,0,1,3,3]\) 插入字典树:这里红色数字表示以该段为前缀的数的个数,黑色表示对应的数。…

c# , net 创建树形结构,创建树形节点

/// <summary> /// 生成树形结构 /// </summary> public void GetTreeNode() {//SqlHelper.GetSqlDataReader是封装的查询数据库语句,可根据自己需求封装//假设获取所有一级节点List<Products> products = SqlHelper.GetSqlDataReader(sql);for (int i = 0; …

abc360 E 题解

E 对于位置2~n,它们的概率是相等的。 n*n个(x,y)对。其中x可以等于y。对于x/y,y的逆元rev(y)为mul(y,mod-2)。 加、减、乘、除都可以做。比如48/9和16/3的结果是一样的,48*rev(9)%mod = 16*rev(3)%mod。比如3*rev(2)%mod = (rev(2)+rev(2)+rev(2))%mod.对于每次操作,有多少…

数业智能荣登「全球应用算法模型大赛50强」

近日,由上海市经济和信息化委员会、上海市普陀区人民政府,上海市人工智能行业协会主办,上海人工智能研究院等单位联合承办的《BPAA第四届全球应用算法模型典范大赛》经过一个多月的角逐,最终公布《BPAA第四届全球应用算法模型典范大赛TOP50榜单》。数业智能心大陆凭借独立自…

快速调用 GLM-4-9B-Chat 语言模型

一、确认本机显卡配置二、下载大模型 国内可以从魔搭社区下载, 下载地址:https://modelscope.cn/models/ZhipuAI/glm-4-9b-chat/files 三、运行官方代码import torch from transformers import AutoModelForCausalLM, AutoTokenizerdevice = "cuda"tokenizer = A…