NET/C#中SM2/SM3国密加密算法

发布时间 2023-07-31 18:02:47作者: JuCheap
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Encoders;
using System;


namespace JuCheap.Core
{
    /// <summary>
    /// SM2/SM3加密帮助类
    /// </summary>
    internal class GmUtil
    {
        private static readonly X9ECParameters _x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");
        private static readonly ECDomainParameters _ecDomainParameters = new ECDomainParameters(_x9ECParameters.Curve, _x9ECParameters.G, _x9ECParameters.N, _x9ECParameters.H, _x9ECParameters.GetSeed());
        private const int _rsLength = 32;

        public byte[] SignSm3WithSm2(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey)
        {
            return RsAsn1ToPlainByteArray(SignSm3WithSm2Asn1Rs(msg, userId, privateKey));
        }

        public byte[] SignSm3WithSm2Asn1Rs(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey)
        {
            ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
            signer.Init(true, new ParametersWithID(privateKey, userId));
            signer.BlockUpdate(msg, 0, msg.Length);
            byte[] sig = signer.GenerateSignature();
            return sig;
        }

        public string Sm3WithSm2Signature(string privateKeyStr, string data)
        {
            byte[] msg = System.Text.Encoding.UTF8.GetBytes(data);
            byte[] userId = System.Text.Encoding.UTF8.GetBytes("1234567812345678");
            ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(new BigInteger(1, Hex.Decode(privateKeyStr)), _ecDomainParameters);
            byte[] sig = SignSm3WithSm2(msg, userId, privateKey);
            return Hex.ToHexString(sig);
        }

        private static byte[] BigIntToFixexLengthBytes(BigInteger rOrS)
        {
            byte[] rs = rOrS.ToByteArray();
            if (rs.Length == _rsLength)
            {
                return rs;
            }
            else if (rs.Length == _rsLength + 1 && rs[0] == 0)
            {
                return Arrays.CopyOfRange(rs, 1, _rsLength + 1);
            }
            else if (rs.Length < _rsLength)
            {
                byte[] result = new byte[_rsLength];
                Arrays.Fill(result, 0);
                Buffer.BlockCopy(rs, 0, result, _rsLength - rs.Length, rs.Length);
                return result;
            }
            throw new ArgumentException("err rs: " + Hex.ToHexString(rs));
        }

        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[_rsLength * 2];
            Buffer.BlockCopy(r, 0, result, 0, r.Length);
            Buffer.BlockCopy(s, 0, result, _rsLength, s.Length);
            return result;
        }
    }
}

使用方法:

using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text;

namespace JuCheap.Core
{
    /// <summary>
    /// sm2/sm3加密算法
    /// </summary>
    internal class EncryptionTools
    {
        private EncryptionTools() { }
        /// <summary>
        /// SM3加密
        /// </summary>
        /// <param name="data">加密的数据</param>
        /// <returns></returns>
        public static string Sm3Signature2(string data)
        {
            byte[] dataBytes = Encoding.GetEncoding("UTF-8").GetBytes(data);
            SM3Digest sm3Digest = new SM3Digest();
            sm3Digest.BlockUpdate(dataBytes, 0, dataBytes.Length);
            byte[] ret = new byte[sm3Digest.GetDigestSize()];
            sm3Digest.DoFinal(ret, 0);
            return Hex.ToHexString(ret);
        }

        /// <summary>
        /// SM2加密
        /// </summary>
        /// <param name="authoritySecret">密钥</param>
        /// <param name="signString">加签的字符串</param>
        /// <returns></returns>
        public static string Sm3WithSm2Signature(string authoritySecret, string signString)
        {
            return new GmUtil().Sm3WithSm2Signature(authoritySecret, signString);
        }
    }
}