SM2 是中国自主研发的椭圆曲线公钥密码算法,广泛应用于电子认证、数据加密等领域。

以下代码已上传到仓库:https://gitcode.com/DSOE1024/UnitySM2Sample

导入BouncyCastle库

1. 环境配置

  • 从nuget包解压引入 BouncyCastle.Crypto.dll 至 Unity 项目的 Plugin 目录

img

img

  • 添加必要的命名空间引用:
    using Org.BouncyCastle.Asn1.GM;
    using Org.BouncyCastle.Asn1.X9;
    using Org.BouncyCastle.Crypto;
    using Org.BouncyCastle.Crypto.Engines;
    using Org.BouncyCastle.Crypto.Generators;
    using Org.BouncyCastle.Crypto.Parameters;
    using Org.BouncyCastle.Math;
    using Org.BouncyCastle.Security;
    using Org.BouncyCastle.Utilities.Encoders;
    using System.Text;
    

2. 密钥对生成

通过椭圆曲线参数生成 SM2 密钥对:

X9ECParameters sm2Params = ECNamedCurveTable.GetByName("sm2p256v1");
// 初始化密钥生成器
ECKeyPairGenerator generator = new ECKeyPairGenerator();
generator.Init(new ECKeyGenerationParameters(
    new ECDomainParameters(sm2Params.Curve, sm2Params.G, sm2Params.N),
    new SecureRandom()
));

// 生成并提取密钥
AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();
ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters)keyPair.Private;
ECPublicKeyParameters publicKey = (ECPublicKeyParameters)keyPair.Public;

3. 加密

使用公钥加密数据:

public byte[] Encrypt(byte[] data, byte[] publicKey) 
{
    // 加载公钥并初始化加密引擎
    ECPublicKeyParameters pubKeyParams = new ECPublicKeyParameters(
        sm2Params.Curve.DecodePoint(publicKey), 
        new ECDomainParameters(sm2Params.Curve)
    );
    
    SM2Engine engine = new SM2Engine();
    engine.Init(true, new ParametersWithRandom(pubKeyParams, new SecureRandom()));
    return engine.ProcessBlock(data, 0, data.Length);
}

4. 解密

使用私钥解密数据:

public byte[] Decrypt(byte[] cipherData, byte[] privateKey) 
{
    // 加载私钥参数
    ECPrivateKeyParameters privKeyParams = new ECPrivateKeyParameters(
        new BigInteger(1, privateKey), 
        new ECDomainParameters(sm2Params.Curve)
    );
    
    SM2Engine engine = new SM2Engine();
    engine.Init(false, privKeyParams);
    return engine.ProcessBlock(cipherData, 0, cipherData.Length);
}

完整示例代码

using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text;
using UnityEngine;

/// <summary>
/// SM2 加密解密示例
/// </summary>
public class SM2Sample : MonoBehaviour
{
    private byte[] pubKey;
    private byte[] privKey;

    private string content = "加密的内容";

    private void Start()
    {
        GenerateKeyPair(out string priKeyStr, out string pubKeyStr);
        privKey = Hex.Decode(priKeyStr);
        pubKey = Hex.Decode(pubKeyStr);

        var str = EncryptString(content);
        Debug.Log($"加密后 { str } ");
        Debug.Log($"解密后 { DecryptString(str) }");
    }

    /// <summary>
    /// 生成密钥对
    /// </summary>
    /// <param name="privateKeyHex"></param>
    /// <param name="publicKeyHex"></param>
    public static void GenerateKeyPair(out string privateKeyHex, out string publicKeyHex)
    {
        // 获取 SM2 椭圆曲线参数
        X9ECParameters sm2Params = ECNamedCurveTable.GetByName("sm2p256v1");
        ECDomainParameters domainParams = new ECDomainParameters(
            sm2Params.Curve,
            sm2Params.G,
            sm2Params.N,
            sm2Params.H
        );

        // 初始化密钥对生成器
        ECKeyPairGenerator generator = new ECKeyPairGenerator();
        ECKeyGenerationParameters keyGenParams = new ECKeyGenerationParameters(
            domainParams,
            new SecureRandom() // 使用安全的随机数生成器
        );
        generator.Init(keyGenParams);

        // 生成密钥对
        AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();

        // 提取私钥 (BigInteger D)
        ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters)keyPair.Private;
        byte[] privateKeyBytes = privateKey.D.ToByteArrayUnsigned(); // 转换为无符号字节数组
        privateKeyHex = Hex.ToHexString(privateKeyBytes);

        // 提取公钥 (ECPoint Q)
        ECPublicKeyParameters publicKey = (ECPublicKeyParameters)keyPair.Public;
        byte[] publicKeyBytes = publicKey.Q.GetEncoded(false); // 非压缩格式(含04前缀)
        publicKeyHex = Hex.ToHexString(publicKeyBytes);
    }


    /// <summary>
    /// 解密
    /// </summary>
    /// <param name="data"></param>
    /// <param name="privateKey"></param>
    /// <returns></returns>
    public byte[] Decrypt(byte[] data, byte[] privateKey)
    {
        BigInteger d = new BigInteger(1, privateKey);
        X9ECParameters spar = ECNamedCurveTable.GetByName("sm2p256v1");
        ECDomainParameters ecdp = new ECDomainParameters(spar.Curve, spar.G, spar.N, spar.H);

        // 创建私钥参数
        ECPrivateKeyParameters keyParameter = new ECPrivateKeyParameters(d, ecdp);

        SM2Engine engine = new SM2Engine();
        engine.Init(false, keyParameter);

        byte[] decryptedData = engine.ProcessBlock(data, 0, data.Length);
        return decryptedData;
    }

    /// <summary>
    /// 解密
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public string DecryptString(string data)
    {
        byte[] encryptedData = Hex.Decode(data);
        byte[] decryptedData = Decrypt(encryptedData, privKey);
        return Encoding.UTF8.GetString(decryptedData);
    }


    /// <summary>
    /// 加密
    /// </summary>
    /// <param name="data"></param>
    /// <param name="publicKey"></param>
    /// <returns></returns>
    public byte[] Encrypt(byte[] data, byte[] publicKey)
    {
        X9ECParameters sm2Params = GMNamedCurves.GetByName("sm2p256v1");
        Org.BouncyCastle.Math.EC.ECPoint q = sm2Params.Curve.DecodePoint(publicKey);
        ECDomainParameters domainParameters = new ECDomainParameters(sm2Params.Curve, sm2Params.G, sm2Params.N, sm2Params.H);
        AsymmetricKeyParameter keyParameter = new ECPublicKeyParameters(q, domainParameters);
        SM2Engine engine = new SM2Engine();
        engine.Init(true, new ParametersWithRandom(keyParameter, new SecureRandom()));
        byte[] encryptedData = engine.ProcessBlock(data, 0, data.Length);
        return encryptedData;
    }


    /// <summary>
    /// 加密
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public string EncryptString(string data)
    {
        byte[] dataBytes = Encoding.UTF8.GetBytes(data);
        byte[] encryptedData = Encrypt(dataBytes, pubKey);
        return Hex.ToHexString(encryptedData);
    }
}

注意事项

  1. 密钥格式
    公钥需包含 04 前缀表示非压缩格式,私钥为无符号大整数字节数组。

  2. 性能优化
    SM2Engine 加解密过程较耗时,建议避免在主线程处理大数据。

  3. 数据兼容性
    与其他系统交互时需确认椭圆曲线参数是否一致(sm2p256v1)。

  4. 错误处理
    添加异常捕获处理密钥格式错误、解密失败等情况。

Logo

盛京开源社区 SJOSC 官方论坛平台

更多推荐