国密(国产密码)SM2、SM3、SM4C#实现这两天与联通对接流量卡实名相关接⼝。他们⽤到了国密SM3,⼀个⽐较冷门的加密(或者说是签名)⽅式。顺带我也了解了下
SM2、SM3、SM4:本⽂只做了SM2、SM3、SM4 代码补充
国产密码算法(国密算法)是指国家密码局认定的国产商⽤密码算法,在⾦融领域⽬前主要使⽤公开的SM2、SM3、SM4三类算法,分别是⾮对称算法、哈希算法和对称算法。
SM1对称密码
SM1 算法是分组密码算法,分组长度为128位,密钥长度都为 128 ⽐特,算法安全保密强度及相关软硬件实现性能与 AES 相当,算法不公开,仅以IP核的形式存在于芯⽚中。
采⽤该算法已经研制了系列芯⽚、智能IC卡、智能密码钥匙、加密卡、加密机等安全产品,⼴泛应⽤于电⼦政务、电⼦商务及国民经济的各个应⽤领域(包括国家政务通、警务通等重要领域)。
SM2椭圆曲线公钥密码算法
SM2算法就是ECC椭圆曲线密码机制,但在签名、密钥交换⽅⾯不同于ECDSA、ECDH等国际标准,⽽是采取了更为安全的机制。另
外,SM2推荐了⼀条256位的曲线作为标准曲线。
SM2标准包括总则,数字签名算法,密钥交换协议,公钥加密算法四个部分,并在每个部分的附录详细说明了实现的相关细节及⽰例。
SM2算法主要考虑素域Fp和F2m上的椭圆曲线,分别介绍了这两类域的表⽰,运算,以及域上的椭圆曲线的点的表⽰,运算和多倍点计算算法。然后介绍了编程语⾔中的数据转换,包括整数和字节串,字节串和⽐特串,域元素和⽐特串,域元素和整数,点和字节串之间的数据转换规则。详细说明了有限域上椭圆曲线的参数⽣成以及验证,椭圆曲线的参数包括有限域的选取、椭圆曲线⽅程参数、椭圆曲线基点的选取等,并给出了选取的标准以便于验证。最后给椭圆曲线上密钥对的⽣成以及公钥的验证,⽤户的密钥对为(s,sP),其中s为⽤户的私钥,sP为⽤户的公钥,由于离散对数问题从sP难以得到s,并针对素域和⼆元扩域给出了密钥对⽣成细节和验证⽅式。总则中的知识也适⽤于SM9算法。
在总则的基础上给出了数字签名算法(包括数字签名⽣成算法和验证算法),密钥交换协议以及公钥加密算法(包括加密算法和解密算法),并在每个部分给出了算法描述,算法流程和相关⽰例。
数字签名算法、密钥交换协议以及公钥加密算法都使⽤了国家密管理局批准的SM3密码杂凑算法和随机数发⽣器。数字签名算法、密钥交换协议以及公钥加密算法根据总则来选取有限域和椭圆曲线,并
⽣成密钥对。
SM2算法在很多⽅⾯都优于RSA算法。
SM3杂凑算法
SM3密码杂凑(哈希、散列)算法给出了杂凑函数算法的计算⽅法和计算步骤,并给出了运算⽰例。此算法适⽤于商⽤密码应⽤中的数字签名和验证,消息认证码的⽣成与验证以及随机数的⽣成,可满⾜多种密码应⽤的安全需求。在SM2,SM9标准中使⽤。
此算法对输⼊长度⼩于2的64次⽅的⽐特消息,经过填充和迭代压缩,⽣成长度为256⽐特的杂凑值,其中使⽤了异或,模,模加,移位,与,或,⾮运算,由填充,迭代过程,消息扩展和压缩函数所构成。具体算法及运算⽰例见SM3标准。
SM4对称算法
此算法是⼀个分组算法,⽤于⽆线局域⽹产品。该算法的分组长度为128⽐特,密钥长度为128⽐特。加密算法与密钥扩展算法都采⽤32轮⾮线性迭代结构。解密算法与加密算法的结构相同,只是轮密钥的使⽤顺序相反,解密轮密钥是加密轮密钥的逆序。
此算法采⽤⾮线性迭代结构,每次迭代由⼀个轮函数给出,其中轮函数由⼀个⾮线性变换和线性变换复合⽽成,⾮线性变换由S盒所给出。其中rki为轮密钥,合成置换T组成轮函数。轮密钥的产⽣与上图流程类似,由加密密钥作为输⼊⽣成,轮函数中的线性变换不同,还有些参数的区别。SM4算法的具体描述和⽰例见SM4标准。
SM7对称密码
SM7算法,是⼀种分组密码算法,分组长度为128⽐特,密钥长度为128⽐特。SM7适⽤于⾮接触式IC卡,应⽤包括⾝份识别类应⽤(门禁卡、⼯作证、参赛证),票务类应⽤(⼤型赛事门票、展会门票),⽀付与通卡类应⽤(积分消费卡、校园⼀卡通、企业⼀卡通等)。
SM9标识密码算法
为了降低公开密钥系统中密钥和证书管理的复杂性,以⾊列科学家、RSA算法发明⼈之⼀Adi Shamir在1984年提出了标识密码(Identity-Based Cryptography)的理念。标识密码将⽤户的标识(如邮件地址、⼿机号码、QQ号码等)作为公钥,省略了交换数字证书和公钥过程,使得安全系统变得易于部署和管理,⾮常适合端对端离线安全通讯、云端数据加密、基于属性加密、基于策略加密的各种场合。2008年标识密码算法正式获得国家密码管理局颁发的商密算法型号:SM9(商密九号算法),为我国标识密码技术的应⽤奠定了坚实的基础。
SM9算法不需要申请数字证书,适⽤于互联⽹应⽤的各种新兴应⽤的安全保障。如基于云技术的密码服务、电⼦邮件安全、智能终端保护、物联⽹安全、云存储安全等等。这些安全应⽤可采⽤⼿机号码或邮件地址作为公钥,实现数据加密、⾝份认证、通话加密、通道加密等安全应⽤,并具有使⽤⽅便,易于部署的特点,从⽽开启了普及密码算法的⼤门。
ZUC祖冲之算法
祖冲之序列密码算法是中国⾃主研究的流密码算法,是运⽤于移动通信4G⽹络中的国际标准密码算法,该算法包括祖冲之算法(ZUC)、加密算法(128-EEA3)和完整性算法(128-EIA3)三个部分。⽬前已有对ZUC算法的优化实现,有专门针对128-EEA3和128-EIA3的硬件实现与优化。
⼊正题
⾸先需要引⽤ BouncyCastle.Crypto.dll(core 或者 stander 需要引⼊BouncyCastle.Crypto 的 NuGet包)
⼀、SM2
SM2主类
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;
namespace Com.Mlq.SM
{
public class SM2
{
public static SM2 Instance
{
get
{
return new SM2();
}
}
public static SM2 InstanceTest
{
get
{
return new SM2();
}
}
public static readonly string[] sm2_param = {
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",// p,0
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",// a,12020最新表白密码
"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",// b,2
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",// n,3
"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",// gx,4
"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" // gy,5
};
public string[] ecc_param = sm2_param;
public string[] ecc_param = sm2_param;
public readonly BigInteger ecc_p;
张筱雨 魁惑public readonly BigInteger ecc_a;
public readonly BigInteger ecc_b;
public readonly BigInteger ecc_n;
public readonly BigInteger ecc_gx;
public readonly BigInteger ecc_gy;
public readonly ECCurve ecc_curve;
public readonly ECPoint ecc_point_g;
public readonly ECDomainParameters ecc_bc_spec;
public readonly ECKeyPairGenerator ecc_key_pair_generator;
private SM2()
{
ecc_param = sm2_param;
ECFieldElement ecc_gx_fieldelement;龙井组合
ECFieldElement ecc_gy_fieldelement;
ecc_p = new BigInteger(ecc_param[0], 16);
ecc_a = new BigInteger(ecc_param[1], 16);
ecc_b = new BigInteger(ecc_param[2], 16);
ecc_n = new BigInteger(ecc_param[3], 16);
ecc_gx = new BigInteger(ecc_param[4], 16);
ecc_gy = new BigInteger(ecc_param[5], 16);
ecc_gx_fieldelement = new FpFieldElement(ecc_p, ecc_gx);
ecc_gy_fieldelement = new FpFieldElement(ecc_p, ecc_gy);
ecc_curve = new FpCurve(ecc_p, ecc_a, ecc_b);
ecc_point_g = new FpPoint(ecc_curve, ecc_gx_fieldelement, ecc_gy_fieldelement);
ecc_bc_spec = new ECDomainParameters(ecc_curve, ecc_point_g, ecc_n);
ECKeyGenerationParameters ecc_ecgenparam;
ecc_ecgenparam = new ECKeyGenerationParameters(ecc_bc_spec, new SecureRandom());
ecc_key_pair_generator = new ECKeyPairGenerator();
ecc_key_pair_generator.Init(ecc_ecgenparam);
}
public virtual byte[] Sm2GetZ(byte[] userId, ECPoint userKey)
{
夫妻双方公积金贷款最高额度SM3Digest sm3 = new SM3Digest();
byte[] p;
2022年国庆放假7天需调休// userId length
int len = userId.Length * 8;
sm3.Update((byte) (len >> 8 & 0x00ff));
sm3.Update((byte) (len & 0x00ff));
// userId
sm3.BlockUpdate(userId, 0, userId.Length);
// a,b
p = ecc_a.ToByteArray();
sm3.BlockUpdate(p, 0, p.Length);
p = ecc_b.ToByteArray();
sm3.BlockUpdate(p, 0, p.Length);
// gx,gy
p = ecc_gx.ToByteArray();
sm3.BlockUpdate(p, 0, p.Length);
sm3.BlockUpdate(p, 0, p.Length);
p = ecc_gy.ToByteArray();
sm3.BlockUpdate(p, 0, p.Length);
// x,y
p = userKey.X.ToBigInteger().ToByteArray();
sm3.BlockUpdate(p, 0, p.Length);
p = userKey.Y.ToBigInteger().ToByteArray();
sm3.BlockUpdate(p, 0, p.Length);
// Z
byte[] md = new byte[sm3.GetDigestSize()];
sm3.DoFinal(md, 0);
return md;
}
}
}
SM2⼯具类:
using Com.Mlq.SM;
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;
康熙来了大s汪小菲using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Com.Mlq.SM
{
class SM2Utils
{
public static void GenerateKeyPair()
{
SM2 sm2 = SM2.Instance;
AsymmetricCipherKeyPair key = _key_pair_generator.GenerateKeyPair();
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.Private;
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.Public;
BigInteger privateKey = ecpriv.D;
ECPoint publicKey = ecpub.Q;
System.Console.Out.WriteLine("公钥: " + Encoding.Default.GetString(Hex.Encode(publicKey.GetEncoded())).ToUpper()); System.Console.Out.WriteLine("私钥: " + Encoding.Default.GetString(Hex.Encode(privateKey.ToByteArray())).ToUpper()); }
public 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);
Array.Copy(data, 0, source, 0, data.Length);
Cipher cipher = new Cipher();
SM2 sm2 = SM2.Instance;
ECPoint userKey = _curve.DecodePoint(publicKey);
ECPoint c1 = cipher.Init_enc(sm2, 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();
}
public 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 = _curve.DecodePoint(c1Bytes);
Cipher cipher = new Cipher();
cipher.Init_dec(userD, c1);
cipher.Decrypt(c2);
cipher.Dofinal(c3);
return c2;
}
//[STAThread]
/
/public static void Main()
//{
// GenerateKeyPair();
// String plainText = "ererfeiisgod";
// byte[] sourceData = Encoding.Default.GetBytes(plainText);
// //下⾯的秘钥可以使⽤generateKeyPair()⽣成的秘钥内容
// // 国密规范正式私钥
// String prik = "3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94";
// // 国密规范正式公钥
// String pubk = "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813B
// System.Console.Out.WriteLine("加密: ");
// String cipherText = SM2Utils.Encrypt(Hex.Decode(pubk), sourceData);
发布评论