您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

C# 实现SM2国密加密帮助类

时间:2022-03-29 09:50:30  来源:  作者:中年农码工

本人在了解对接国家医疗保障信息平台中定点医药机构接口文档中,传输加密方式使用国密算法之SM2.然后本人在隔离期间研究了一下,将内容进行总结,本文主要讲解“国密加密算法”SM系列之SM2的C#实现方法,加密规则请详阅国密局发布的文档。

首先需第三方Nuget包:Portable.BouncyCastle

1.SM2密码计算

using Org.BouncyCastle.Crypto;

using Org.BouncyCastle.Crypto.Digests;

using Org.BouncyCastle.Crypto.Parameters;

using Org.BouncyCastle.Math;

using Org.BouncyCastle.Math.EC;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace Core.Common

{

/// <summary>

/// 密码计算

/// </summary>

public class Cipher

{

private int ct = 1;

/// <summary>

/// 椭圆曲线E上点P2

/// </summary>

private ECPoint p2;

private SM3Digest sm3keybase;

private SM3Digest sm3c3;

private readonly byte[] key = new byte[32];

private byte keyOff = 0;

public Cipher()

{

}

private void Reset()

{

sm3keybase = new SM3Digest();

sm3c3 = new SM3Digest();

byte[] p;

p = p2.Normalize().XCoord.ToBigInteger().ToByteArray();

sm3keybase.BlockUpdate(p, 0, p.Length);

sm3c3.BlockUpdate(p, 0, p.Length);

p = p2.Normalize().YCoord.ToBigInteger().ToByteArray();

sm3keybase.BlockUpdate(p, 0, p.Length);

ct = 1;

NextKey();

}

private void NextKey()

{

SM3Digest sm3keycur = new SM3Digest(sm3keybase);

sm3keycur.Update((byte)(ct >> 24 & 0x00ff));

sm3keycur.Update((byte)(ct >> 16 & 0x00ff));

sm3keycur.Update((byte)(ct >> 8 & 0x00ff));

sm3keycur.Update((byte)(ct & 0x00ff));

sm3keycur.DoFinal(key, 0);

keyOff = 0;

ct++;

}

public virtual ECPoint InitEnc(SM2 sm2, ECPoint userKey)

{

AsymmetricCipherKeyPair key = sm2.EccKeyPairGenerator.GenerateKeyPair();

ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)key.Private;

ECPublicKeyParameters ecpub = (ECPublicKeyParameters)key.Public;

BigInteger k = ecpriv.D;

ECPoint c1 = ecpub.Q;

p2 = userKey.Multiply(k);

Reset();

return c1;

}

public virtual void Encrypt(byte[] data)

{

//p2.Normalize();

sm3c3.BlockUpdate(data, 0, data.Length);

for (int i = 0; i < data.Length; i++)

{

if (keyOff == key.Length)

NextKey();

data[i] ^= key[keyOff++];

}

}

public virtual void InitDec(BigInteger userD, ECPoint c1)

{

p2 = c1.Multiply(userD);

Reset();

}

public virtual void Decrypt(byte[] data)

{

for (int i = 0; i < data.Length; i++)

{

if (keyOff == key.Length)

NextKey();

data[i] ^= key[keyOff++];

}

sm3c3.BlockUpdate(data, 0, data.Length);

}

public virtual void Dofinal(byte[] c3)

{

byte[] p = p2.Normalize().YCoord.ToBigInteger().ToByteArray();

sm3c3.BlockUpdate(p, 0, p.Length);

sm3c3.DoFinal(c3, 0);

Reset();

}

}

}

 

2. 加密处理中心

using System;

using Org.BouncyCastle.Crypto.Generators;

using Org.BouncyCastle.Math.EC;

using Org.BouncyCastle.Math;

using Org.BouncyCastle.Crypto;

using Org.BouncyCastle.Crypto.Parameters;

using Org.BouncyCastle.Security;

using System.Text;

using Org.BouncyCastle.Crypto.Digests;

namespace Core.Common

{

/// <summary>

/// SM2主类

/// </summary>

/// <summary>

/// 加密处理中心

/// </summary>

public class SM2

{

public static SM2 Instance

{

get

{

return new SM2();

}

}

public static SM2 InstanceTest

{

get

{

return new SM2();

}

}

#region 曲线参数

/// <summary>

/// 曲线参数

/// </summary>

public static readonly string[] CurveParameter = {

"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",// p,0

"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",// a,1

"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",// b,2

"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",// n,3

"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",// gx,4

"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" // gy,5

};

/// <summary>

/// 椭圆曲线参数

/// </summary>

public string[] EccParam = CurveParameter;

/// <summary>

/// 椭圆曲线参数P

/// </summary>

public readonly BigInteger EccP;

/// <summary>

/// 椭圆曲线参数A

/// </summary>

public readonly BigInteger EccA;

/// <summary>

/// 椭圆曲线参数B

/// </summary>

public readonly BigInteger EccB;

/// <summary>

/// 椭圆曲线参数N

/// </summary>

public readonly BigInteger EccN;

/// <summary>

/// 椭圆曲线参数Gx

/// </summary>

public readonly BigInteger EccGx;

/// <summary>

/// 椭圆曲线参数Gy

/// </summary>

public readonly BigInteger EccGy;

#endregion

/// <summary>

/// 椭圆曲线

/// </summary>

public readonly ECCurve EccCurve;

/// <summary>

/// 椭圆曲线的点G

/// </summary>

public readonly ECPoint EccPointG;

/// <summary>

/// 椭圆曲线 bc规范

/// </summary>

public readonly ECDomainParameters EccBcSpec;

/// <summary>

/// 椭圆曲线密钥对生成器

/// </summary>

public readonly ECKeyPairGenerator EccKeyPairGenerator;

private SM2()

{

EccParam = CurveParameter;

EccP = new BigInteger(EccParam[0], 16);

EccA = new BigInteger(EccParam[1], 16);

EccB = new BigInteger(EccParam[2], 16);

EccN = new BigInteger(EccParam[3], 16);

EccGx = new BigInteger(EccParam[4], 16);

EccGy = new BigInteger(EccParam[5], 16);

ECFieldElement ecc_gx_fieldelement = new FpFieldElement(EccP, EccGx);

ECFieldElement ecc_gy_fieldelement = new FpFieldElement(EccP, EccGy);

EccCurve = new FpCurve(EccP, EccA, EccB);

EccPointG = new FpPoint(EccCurve, ecc_gx_fieldelement, ecc_gy_fieldelement);

EccBcSpec = new ECDomainParameters(EccCurve, EccPointG, EccN);

ECKeyGenerationParameters ecc_ecgenparam;

ecc_ecgenparam = new ECKeyGenerationParameters(EccBcSpec, new SecureRandom());

EccKeyPairGenerator = new ECKeyPairGenerator();

EccKeyPairGenerator.Init(ecc_ecgenparam);

}

/// <summary>

/// 获取杂凑值H

/// </summary>

/// <param name="z">Z值</param>

/// <param name="data">待签名消息</param>

/// <returns></returns>

public virtual byte[] Sm2GetH(byte[] z, byte[] data)

{

SM3Digest sm3 = new SM3Digest();

//Z

sm3.BlockUpdate(z, 0, z.Length);

//待签名消息

sm3.BlockUpdate(data, 0, data.Length);

// H

byte[] md = new byte[sm3.GetDigestSize()];

sm3.DoFinal(md, 0);

return md;

}

/// <summary>

/// 获取Z值

/// Z=SM3(ENTL∣∣userId∣∣a∣∣b∣∣gx∣∣gy ∣∣x∣∣y)

/// </summary>

/// <param name="userId">签名方的用户身份标识</param>

/// <param name="userKey">签名方公钥</param>

/// <returns></returns>

public virtual byte[] Sm2GetZ(byte[] userId, ECPoint userKey)

{

SM3Digest sm3 = new SM3Digest();

byte[] p;

// ENTL由2个字节标识的ID的比特长度

int len = userId.Length * 8;

sm3.Update((byte)(len >> 8 & 0x00ff));

sm3.Update((byte)(len & 0x00ff));

// userId用户身份标识ID

sm3.BlockUpdate(userId, 0, userId.Length);

// a,b为系统曲线参数;

p = EccA.ToByteArray();

sm3.BlockUpdate(p, 0, p.Length);

p = EccB.ToByteArray();

sm3.BlockUpdate(p, 0, p.Length);

// gx、gy为基点

p = EccGx.ToByteArray();

sm3.BlockUpdate(p, 0, p.Length);

p = EccGy.ToByteArray();

sm3.BlockUpdate(p, 0, p.Length);

// x,y用户的公钥的X和Y

p = userKey.Normalize().XCoord.ToBigInteger().ToByteArray();

sm3.BlockUpdate(p, 0, p.Length);

p = userKey.Normalize().YCoord.ToBigInteger().ToByteArray();

sm3.BlockUpdate(p, 0, p.Length);

// Z

byte[] md = new byte[sm3.GetDigestSize()];

sm3.DoFinal(md, 0);

return md;

}

}

}

 

3 加密调用

using Org.BouncyCastle.Crypto;

using Org.BouncyCastle.Crypto.Parameters;

using Org.BouncyCastle.Math;

using Org.BouncyCastle.Math.EC;

using Org.BouncyCastle.Utilities.Encoders;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace Core.Common

{

/// <summary>

/// Sm2算法

/// 对标国际RSA算法

/// </summary>

public class Sm2Crypto

{

/// <summary>

/// 数据

/// </summary>

public string Str { get; set; }

/// <summary>

/// 数据

/// </summary>

public byte[] Data { get; set; }

/// <summary>

/// 公钥

/// </summary>

public string PublicKey { get; set; }

/// <summary>

/// 私钥

/// </summary>

public string PrivateKey { get; set; }

/// <summary>

/// 获取密钥

/// </summary>

/// <param name="privateKey">私钥</param>

/// <param name="publicKey">公钥</param>

public static void GetKey(out string privateKey, out string publicKey)

{

SM2 sm2 = SM2.Instance;

AsymmetricCipherKeyPair key = sm2.EccKeyPairGenerator.GenerateKeyPair();

ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)key.Private;

ECPublicKeyParameters ecpub = (ECPublicKeyParameters)key.Public;

publicKey = Encoding.Default.GetString(Hex.Encode(ecpub.Q.GetEncoded())).ToUpper();

privateKey = Encoding.Default.GetString(Hex.Encode(ecpriv.D.ToByteArray())).ToUpper();

}

#region 解密

public object Decrypt(Sm2Crypto entity)

{

var data = !string.IsNullOrEmpty(entity.Str) ?

Hex.Decode(entity.Str) :

entity.Data;

return Encoding.Default.GetString(Decrypt(Hex.Decode(entity.PrivateKey), data));

}

/// <summary>

/// 解密

/// </summary>

/// <param name="privateKey"></param>

/// <param name="encryptedData"></param>

/// <returns></returns>

private static byte[] Decrypt(byte[] privateKey, byte[] encryptedData)

{

if (null == privateKey || privateKey.Length == 0)

{

return null;

}

if (encryptedData == null || encryptedData.Length == 0)

{

return null;

}

String data = Encoding.Default.GetString(Hex.Encode(encryptedData));

byte[] c1Bytes = Hex.Decode(Encoding.Default.GetBytes(data.Substring(0, 130)));

int c2Len = encryptedData.Length - 97;

byte[] c2 = Hex.Decode(Encoding.Default.GetBytes(data.Substring(130, 2 * c2Len)));

byte[] c3 = Hex.Decode(Encoding.Default.GetBytes(data.Substring(130 + 2 * c2Len, 64)));

SM2 sm2 = SM2.Instance;

BigInteger userD = new BigInteger(1, privateKey);

ECPoint c1 = sm2.EccCurve.DecodePoint(c1Bytes);

//c1.Normalize();

Cipher cipher = new Cipher();

cipher.InitDec(userD, c1);

cipher.Decrypt(c2);

cipher.Dofinal(c3);

return c2;

}

#endregion

#region 加密

public string Encrypt(Sm2Crypto entity)

{

var data = !string.IsNullOrEmpty(entity.Str) ?

Encoding.Default.GetBytes(entity.Str) :

entity.Data;

return Encrypt(Hex.Decode(entity.PublicKey), data);

}

/// <summary>

/// 加密

/// </summary>

/// <param name="publicKey"></param>

/// <param name="data"></param>

/// <returns></returns>

private static string Encrypt(byte[] publicKey, byte[] data)

{

if (null == publicKey || publicKey.Length == 0)

{

return null;

}

if (data == null || data.Length == 0)

{

return null;

}

byte[] source = new byte[data.Length];

Array.Copy(data, 0, source, 0, data.Length);

Cipher cipher = new Cipher();

SM2 sm = SM2.Instance;

ECPoint userKey = sm.EccCurve.DecodePoint(publicKey);

//userKey.Normalize();

ECPoint c1 = cipher.InitEnc(sm, userKey);

cipher.Encrypt(source);

byte[] c3 = new byte[32];

cipher.Dofinal(c3);

String sc1 = Encoding.Default.GetString(Hex.Encode(c1.GetEncoded()));

String sc2 = Encoding.Default.GetString(Hex.Encode(source));

String sc3 = Encoding.Default.GetString(Hex.Encode(c3));

return (sc1 + sc2 + sc3).ToUpper();

}

#endregion

}

}

 

4.最终调用结果

 

C# 实现SM2国密加密帮助类

 


C# 实现SM2国密加密帮助类

 

希望这边文章能帮助相关人员,欢迎评论+转发,谢谢所有水友们!!!



Tags:C#   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
本人在了解对接国家医疗保障信息平台中定点医药机构接口文档中,传输加密方式使用国密算法之SM2.然后本人在隔离期间研究了一下,将内容进行总结,本文主要讲解“国密加密算法”SM...【详细内容】
2022-03-29  Tags: C#  点击:(9)  评论:(0)  加入收藏
C#可以使用Microsoft Visual Studio Installer Project工具打包成桌面应用程序,工具下载网址: https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.Mic...【详细内容】
2022-03-22  Tags: C#  点击:(19)  评论:(0)  加入收藏
上次用C#写.Net代码差不多还是10多年以前,由于当时Java已经颇具王者风范,.Net几乎被打得溃不成军。因此当时笔者对于这个.Net的项目态度比较敷衍了事,没有对其中一些优秀机制有很深的了解,在去年写《C和Java没那么香了,高...【详细内容】
2022-02-09  Tags: C#  点击:(49)  评论:(0)  加入收藏
功能说明:1、实现局域网设备互相发现2、实现右键快速发送到3、传输速度,进度显示4、支持托盘显示项目语言:c#(winform)功能实现原理:局域网内各主机之间通过upd互相发现,客户端启...【详细内容】
2022-01-20  Tags: C#  点击:(60)  评论:(0)  加入收藏
微软发布.NET框架已经21年了,现在还是不少企业的首选开发框架。尤其最近几年微软.net全面拥抱linux以及今年即将发布的.net 6基本支持所有的移动平台开发,必定能解决很多开发...【详细内容】
2022-01-10  Tags: C#  点击:(93)  评论:(0)  加入收藏
最近需要做一个打印的功能,于是在网上找到了这么一个方法。   [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public class DOCINFOA { [M...【详细内容】
2022-01-04  Tags: C#  点击:(80)  评论:(0)  加入收藏
最近有个需求需要定时清理服务器上所有的缓存。本来以为很简单的调用一下 MemoryCache.Clear 方法就完事了。谁知道 MemoryCache 类以及 IMemoryCache 扩展方法都没有 Clear...【详细内容】
2021-12-30  Tags: C#  点击:(80)  评论:(0)  加入收藏
一、简介很多时候我们都需要用到一些验证的方法,有时候需要用正则表达式校验数据时,往往需要到网上找很久,结果找到的还不是很符合自己想要的。所以我把自己整理的校验帮助类分...【详细内容】
2021-12-27  Tags: C#  点击:(60)  评论:(0)  加入收藏
读取SQLite数据库,就是读取一个路径\\192.168.100.**\position\db.sqlite下的文件<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/...【详细内容】
2021-12-16  Tags: C#  点击:(77)  评论:(0)  加入收藏
一文看懂"async"和“await”关键词是如何简化了C#中多线程的开发过程当我们使用需要长时间运行的方法(即,用于读取大文件或从网络下载大量资源)时,在同步的应用程序中,应用程序本...【详细内容】
2021-12-01  Tags: C#  点击:(76)  评论:(0)  加入收藏
▌简易百科推荐
前言内存四区,分别是全局区(静态区),代码区,栈区,堆区.从内存分配来看,可以分为静态分配和动态分配.静态分配内存分配完成之后,不会释放,直到程序结束 静态区,分配之后,不会释...【详细内容】
2022-03-30  秋风技术    Tags:c语言   点击:(2)  评论:(0)  加入收藏
本人在了解对接国家医疗保障信息平台中定点医药机构接口文档中,传输加密方式使用国密算法之SM2.然后本人在隔离期间研究了一下,将内容进行总结,本文主要讲解“国密加密算法”SM...【详细内容】
2022-03-29  中年农码工    Tags:C#   点击:(9)  评论:(0)  加入收藏
近日,Rust和Swift资深专家Aria Beingessner发布的一篇文章《C 不再是一种编程语言》在Hacker News上引起了热烈讨论。原文链接: https://gankra.github.io/blah/c-isnt-a-lang...【详细内容】
2022-03-25  CSDN程序人生    Tags:编程语言   点击:(11)  评论:(0)  加入收藏
c语言必背专业英语词汇大全要想学好c语言,对于c语言方面的专业英语词汇的学习非常重要,那么现在就一起来学习一些必背的`c语言专业英语词汇吧,希望能够帮到大家!c语言专业英语...【详细内容】
2022-03-24  编程小鱼!!    Tags:c语言   点击:(13)  评论:(0)  加入收藏
C#可以使用Microsoft Visual Studio Installer Project工具打包成桌面应用程序,工具下载网址: https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.Mic...【详细内容】
2022-03-22  工控之星小屹    Tags:C#程序   点击:(19)  评论:(0)  加入收藏
该系列文章是本人在学习C++map和set 的过程中总结下来的,里面涉及到相关源码,请结合我的源码注释 源码分析资料进行阅读 一、关联式容器 容器分类: 序列式容器:初阶阶段中学习过...【详细内容】
2022-03-18  笨鸟先飞ftyjh    Tags:C++   点击:(22)  评论:(0)  加入收藏
之前介绍了网络字节序。网络编程之网络字节序详解今天就来实现一下简单的网络程序。先看几个函数// 创建socket套接字int socket(int domain, int type, int protocol);//...【详细内容】
2022-03-17  AioT智能家居    Tags:网络编程   点击:(15)  评论:(0)  加入收藏
为什么C++的输入输出使用">>"和"<<"这两个符号?操作系统的重定向操作符就是使用">",">>",如以下的windows平台的批处理(bat)文件:chcp 65001echo ^<!DOCTYPE html PUBLIC "-//W3C...【详细内容】
2022-03-15  小智雅汇    Tags:C++   点击:(23)  评论:(0)  加入收藏
先介绍一款小巧的hash工具,就是下图这个,可以计算文件的md5值,SHA1值和CRC32值。不到100kb,功能也很简单,就是对文件进行校验,检查是否被篡改过。 对于网上下载linux操作系统和win...【详细内容】
2022-03-15  AioT智能家居    Tags:VC编程   点击:(16)  评论:(0)  加入收藏
一、定义是否是容器类型#include <iostream>#include <string>#include <type_traits> // std::enable_if #include <utility> // std::pair#include <functional>#inclu...【详细内容】
2022-03-15  好学松鼠my    Tags:C++   点击:(19)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条