您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > 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#   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
C# 中15个值得收藏的开源项目推荐
在开源的世界里,C# 编程语言也占有一席之地。这些开源项目涵盖了多个领域,从框架、库到工具,它们为C#开发者提供了丰富的资源和工具,帮助他们更高效地开发、测试和部署应用程序...【详细内容】
2024-03-20  Search: C#  点击:(33)  评论:(0)  加入收藏
C#异步编程:Task.Run vs. async-await,掌握基础与高级用法
概述:C#中的异步编程有两主要方式:Task.Run用于在后台线程执行同步操作,而async-await更适用于清晰表达异步流程。基础用法展示了它们的简单应用,高级用法则演示了它们的结合使...【详细内容】
2024-03-09  Search: C#  点击:(33)  评论:(0)  加入收藏
C# 线程本地存储为什么线程间值不一样
为什么用 ThreadStatic 标记的字段,只有第一个线程拿到了初始值,其他线程都是默认值,让我能不能帮他解答一下,尼玛,我也不是神仙什么都懂,既然问了,那我试着帮他解答一下,也给后面类...【详细内容】
2024-01-26  Search: C#  点击:(76)  评论:(0)  加入收藏
C# 登顶!超越Java或非空想
整理丨诺亚出品 | 51CTO技术栈(微信号:blog51cto)近日,TIOBE编程社区公布年度编程语言,此次摘得这一桂冠的是C#。这也是C#在TIOBE二十多年评选历史中首次赢得这一年度大奖。C#虽...【详细内容】
2024-01-15  Search: C#  点击:(121)  评论:(0)  加入收藏
C#进程间消息传递
C#是一种流行的编程语言,它可以用于开发Windows应用程序。在开发Windows应用程序时,有时需要进行进程间通信,以实现不同进程之间的数据传递和交互。C#提供了多种方式来进行进程...【详细内容】
2024-01-01  Search: C#  点击:(114)  评论:(0)  加入收藏
搞懂C#文件压缩:SharpZipLib vs. DotNetZip,实用代码一网打尽!
在C#中,有两个热门的文件压缩解析类库分别是SharpZipLib和DotNetZip。以下是它们的简要介绍以及使用实例代码。1. SharpZipLib功能: 支持ZIP和GZip格式的压缩和解压缩。 提供...【详细内容】
2023-12-31  Search: C#  点击:(20)  评论:(0)  加入收藏
探秘C#中的秘密通道:五种引人注目的方法调用内部或私有方法
在 C# 中,可以使用不同的方法调用内部或私有方法。下面分别介绍通过反射、MethodInfo.CreateDelegate、表达式(树)、动态方法(call)、动态方法(calli)这五种方法。1. 通过反射方法...【详细内容】
2023-11-24  Search: C#  点击:(26)  评论:(0)  加入收藏
C#参数传递
前几天一个学员在学习C#与参数传递交互时,也不知道参数传递可以用来做什么 。下面我们就详细讲讲C# 和参数传递交互的相关知识。C#是一种面向对象的编程语言,支持多种参数传...【详细内容】
2023-11-11  Search: C#  点击:(215)  评论:(0)  加入收藏
C#与高级控件
前几天一个学员在学习C#与高级控件交互时,也不知道高级控件可以用来做什么 。下面我们就详细讲讲C# 和高级控件交互的相关知识。C#是一种功能丰富的面向对象编程语言,它包含...【详细内容】
2023-11-10  Search: C#  点击:(259)  评论:(0)  加入收藏
如何在C#客户端程序中无缝集成Python算法
背景介绍在软件开发领域,C#是一种广泛应用的面向对象编程语言,具有强大的类型系统和丰富的库支持。它常被用于开发Windows桌面应用程序、Web应用程序和服务端应用程序等。然而...【详细内容】
2023-11-03  Search: C#  点击:(301)  评论:(0)  加入收藏
▌简易百科推荐
C++中的外部模板及其在当前编译文件中的实例化
在C++中,模板是一种泛型编程的工具,它允许程序员以一种类型无关的方式编写代码。然而,模板的一个常见问题是它们会导致编译时间增加,特别是在大型项目中,当多个源文件包含相同的...【详细内容】
2024-04-11  鲨鱼编程  微信公众号  Tags:C++   点击:(9)  评论:(0)  加入收藏
C++常见避坑指南
C++ 从入门到放弃?本文主要总结了在C++开发或review过程中常见易出错点做了归纳总结,希望借此能增进大家对C++的了解,减少编程出错,提升工作效率,也可以作为C++开发的避坑攻略。...【详细内容】
2024-04-03  腾讯技术工程    Tags:C++   点击:(8)  评论:(0)  加入收藏
C++ 之父反驳白宫警告:自诞生第一天起,C++ 的目标就一直是提高安全性
整理 | 郑丽媛上个月,美国白宫国家网络主任办公室(ONCD)在一份主题为《回到基础构件:通往安全软件之路》的 19 页 PDF 报告中,呼吁开发人员停止使用容易出现内存安全漏洞的编程语...【详细内容】
2024-03-25    CSDN  Tags:C++   点击:(9)  评论:(0)  加入收藏
八个 C++ 开源项目,帮助初学者进阶成长
通过参与或阅读开源项目的源代码,你可以获得丰富的实践机会。实际的项目代码比简单的教程更具挑战性,可以帮助你深入理解 C++ 的各种概念和技术。1.ThreadPool一个简单的 C++1...【详细内容】
2024-03-22  AI让生活更美好  微信公众号  Tags:C++   点击:(27)  评论:(0)  加入收藏
C# 中15个值得收藏的开源项目推荐
在开源的世界里,C# 编程语言也占有一席之地。这些开源项目涵盖了多个领域,从框架、库到工具,它们为C#开发者提供了丰富的资源和工具,帮助他们更高效地开发、测试和部署应用程序...【详细内容】
2024-03-20  程序员编程日记  微信公众号  Tags:C#   点击:(33)  评论:(0)  加入收藏
C#异步编程:Task.Run vs. async-await,掌握基础与高级用法
概述:C#中的异步编程有两主要方式:Task.Run用于在后台线程执行同步操作,而async-await更适用于清晰表达异步流程。基础用法展示了它们的简单应用,高级用法则演示了它们的结合使...【详细内容】
2024-03-09  架构师老卢  今日头条  Tags:C#   点击:(33)  评论:(0)  加入收藏
C++多线程编程:解锁性能与并发的奥秘
今天我们将深入探讨C++中的多线程编程,揭示多线程如何解锁性能潜力,提高程序的并发性能。什么是多线程?在计算机科学中,多线程是指一个进程(程序的执行实例)中的多个线程同时执行...【详细内容】
2024-02-03     AI让生活更美好  Tags:C++   点击:(76)  评论:(0)  加入收藏
C++代码优化攻略
今天我们将深入探讨C++性能优化的世界。在当今软件开发的浪潮中,高性能的代码是必不可少的。无论是开发桌面应用、移动应用,还是嵌入式系统,性能都是关键。1. 选择合适的数据结...【详细内容】
2024-01-26  AI让生活更美好  微信公众号  Tags:C++   点击:(124)  评论:(0)  加入收藏
C# 线程本地存储为什么线程间值不一样
为什么用 ThreadStatic 标记的字段,只有第一个线程拿到了初始值,其他线程都是默认值,让我能不能帮他解答一下,尼玛,我也不是神仙什么都懂,既然问了,那我试着帮他解答一下,也给后面类...【详细内容】
2024-01-26  一线码农聊技术  微信公众号  Tags:C#   点击:(76)  评论:(0)  加入收藏
C++质数检测器的设计与实现​
质数,作为数学中的一个基本概念,一直以其独特的性质吸引着众多研究者和爱好者。质数是指大于1的自然数中,除了1和它本身以外不再有其他因数的数。在实际应用中,质数检测也扮演着...【详细内容】
2024-01-15  鲨鱼编程  微信公众号  Tags:C++   点击:(123)  评论:(0)  加入收藏
站内最新
站内热门
站内头条