国密算法(SM2)在C#里面的简单封装

C#中封装SM2工具类

前言

国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。

一、SM2是什么?

SM2为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
旧标准的加密排序C1C2C3 新标准 C1C3C2,C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。

二、C#具体代码

1.引入库

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Utilities.Encoders;

2.具体工具

代码如下(示例):


/// <summary>
/// SM2工具类
/// </summary>
public class SM2Util
{
    /// <summary>
    /// 加密
    /// </summary>
    /// <param name="publicKey_string"></param>
    /// <param name="data_string"></param>
    /// <returns></returns>
    public static string Encrypt(string publicKey_string, string data_string)
    {
        var publicKey = Hex.Decode(publicKey_string);
        var data = Encoding.UTF8.GetBytes(data_string);
        return Encrypt(publicKey, data);
    }

    /// <summary>
    /// 解密
    /// </summary>
    /// <param name="privateKey_string"></param>
    /// <param name="encryptedData_string"></param>
    /// <returns></returns>
    public static string Decrypt(string privateKey_string, string encryptedData_string)
    {
        var privateKey = Hex.Decode(privateKey_string);
        var encryptedData = Hex.Decode(encryptedData_string);
        var de_str = SM2Util.Decrypt(privateKey, encryptedData);
        string plainText = Encoding.UTF8.GetString(de_str);
        return plainText;
    }

    public static void GenerateKeyPair()
    {
        SM2 sm2 = SM2.Instance;
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.GenerateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)key.Private;
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters)key.Public;
        BigInteger privateKey = ecpriv.D;
        ECPoint publicKey = ecpub.Q;

        Console.Out.WriteLine("公钥: " + Encoding.ASCII.GetString(Hex.Encode(publicKey.GetEncoded())).ToUpper());
        Console.Out.WriteLine("私钥: " + Encoding.ASCII.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);

        var cipher = new Cipher();
        SM2 sm2 = SM2.Instance;

        ECPoint userKey = sm2.ecc_curve.DecodePoint(publicKey);

        ECPoint c1 = cipher.Init_enc(sm2, userKey);
        cipher.Encrypt(source);

        byte[] c3 = new byte[32];
        cipher.Dofinal(c3);

        string sc1 = Encoding.ASCII.GetString(Hex.Encode(c1.GetEncoded()));
        string sc2 = Encoding.ASCII.GetString(Hex.Encode(source));
        string sc3 = Encoding.ASCII.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.ASCII.GetString(Hex.Encode(encryptedData));

        byte[] c1Bytes = Hex.Decode(Encoding.ASCII.GetBytes(data.Substring(0, 130)));
        int c2Len = encryptedData.Length - 97;
        byte[] c2 = Hex.Decode(Encoding.ASCII.GetBytes(data.Substring(130, 2 * c2Len)));
        byte[] c3 = Hex.Decode(Encoding.ASCII.GetBytes(data.Substring(130 + 2 * c2Len, 64)));

        SM2 sm2 = SM2.Instance;
        var userD = new BigInteger(1, privateKey);

        ECPoint c1 = sm2.ecc_curve.DecodePoint(c1Bytes);
        var 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 = "";
    //    // 国密规范正式公钥
    //    String pubk = "";

    //    System.Console.Out.WriteLine("加密: ");
    //    String cipherText = SM2Utils.Encrypt(Hex.Decode(pubk), sourceData);
    //    System.Console.Out.WriteLine(cipherText);
    //    System.Console.Out.WriteLine("解密: ");
    //    plainText = Encoding.Default.GetString(SM2Utils.Decrypt(Hex.Decode(prik), Hex.Decode(cipherText)));
    //    System.Console.Out.WriteLine(plainText);

    //    Console.ReadLine();
    //}

    /// <summary>
    /// SM2加密
    /// </summary>
    /// <param name="plainText">明文</param>
    /// <returns>密文</returns>
    public static String 加密(String plainText)
    {
        // 国密规范正式公钥
        String pubk = "";
        byte[] sourceData = Encoding.Default.GetBytes(plainText);
        String cipherText = SM2Util.Encrypt(Hex.Decode(pubk), sourceData);
        return cipherText;
    }

    /// <summary>
    /// SM2解密
    /// </summary>
    /// <param name="cipherText">密文</param>
    /// <returns>明文</returns>
    public static string 解密(String cipherText)
    {
        // 国密规范正式私钥
        String prik = "";
        String plainText = Encoding.Default.GetString(SM2Util.Decrypt(Hex.Decode(prik), Hex.Decode(cipherText)));
        return plainText;
    }
}



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,1
        "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",// b,2
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",// n,3
        "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",// gx,4
        "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" // gy,5
    };

    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;

        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_curve = new FpCurve(ecc_p, ecc_a, ecc_b, null, null);
        ecc_point_g = ecc_curve.CreatePoint(ecc_gx, ecc_gy);

        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)
    {
        var sm3 = new SM3Digest();
        byte[] p;
        // 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);
        p = ecc_gy.ToByteArray();
        sm3.BlockUpdate(p, 0, p.Length);

        // x,y
        p = userKey.AffineXCoord.ToBigInteger().ToByteArray();
        sm3.BlockUpdate(p, 0, p.Length);
        p = userKey.AffineYCoord.ToBigInteger().ToByteArray();
        sm3.BlockUpdate(p, 0, p.Length);

        // Z
        byte[] md = new byte[sm3.GetDigestSize()];
        sm3.DoFinal(md, 0);

        return md;
    }
}

总结

SM2 加解密联调时踩坑
1、密文数据,有些加密硬件出来密文结构为 C1|C2|C3 ,有些为 C1|C3|C2 , 需要对应密文结构做解密操作
2、有些加密硬件,公钥前加04 ,私钥前加00,密文前加04 ,在处理时候,可以根据长度处理,尤其 04 的处理。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 国密算法SM2是中国自主研发的一种基于椭圆曲线密码学的公钥加密算法,是对RSA和ECC的一种补充和完善。SM2算法具有安全、高效、灵活等特点,性能更优,且可以在国家保密需求下有良好应用。SM2算法可用于数字签名、密钥交换和加密等密码学应用,是最适合在中国国内使用的加密算法之一。 在线SM2算法服务可以为用户提供方便的加密服务,同时保障信息安全。通过在线SM2算法服务,用户可以轻松实现加密数据、签名和验签等操作,同时可以避免因不正确使用SM2算法而造成信息泄露等安全问题。在线SM2算法服务还可以提供密钥交换功能,确保数据在传输过程中的隐私和完整性。 总之,国密算法SM2在线服务是一种安全、可靠的加密解决方案,可以帮助用户保护数据的隐私和完整性,同时可以为用户提供方便的加密服务,推动信息安全保护水平的提升和数字化进程的发展。 ### 回答2: 国密算法SM2是我国自主研发的公钥密码算法,它是适用于数字签名、密钥交换和加密等多种场景的密码算法SM2算法采用基于椭圆曲线的密码学算法,与传统的RSA、DSA、ECC等相比,具有更高的安全性和更快的速度,且能够在轻量级设备上运行,适用范围广泛。 国密算法SM2在线服务提供了SM2算法的相关功能,包括ECIES加密、ECDSA签名、公私钥生成、密钥派生等一系列操作。借助在线服务,用户可以直接在线使用SM2算法进行数据加密、签名和验证等操作,而无需安装和配置任何软件,十分方便快捷。 SM2在线服务也为企业和开发者提供了一种简单易用、高效安全的密码编程接口,可以轻松地嵌入到自己的应用中,提供更加丰富的数据保护方案。同时,SM2在线服务还提供了一系列应用案例和详细的文档资料,帮助用户更好的了解和使用SM2算法。 总之,国密算法SM2在线服务是一款基于SM2算法的在线密码工具,提供了丰富的功能和编程接口,便于用户轻松实现数据加密、签名和验证等操作,适用于各种应用场景,是一款非常有价值的密码工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值